diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 37289f51..b34b2344 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ QR-PTT PushToTalk ======= QR-PTT PushToTalk is an easy to use ptt over IP Android client for voice and text communication that uses the [Jumble] (https://github.com/Morlunk/Jumble) protocol implementation and has a GPLv3 license. It can be used by companies that need to be in constant communication with their employees (Lone Workers), to give instructions, make comments, report incidents in real time by voice communication or by sending a text message within the app. -
To try it for free enter "demo" as Guard ID and leave Guard PIN field empty.* +
To try it for free enter "demo" as User ID and leave User PIN field empty.* Its main features are: - Easy to use diff --git a/app/build.gradle b/app/build.gradle old mode 100644 new mode 100755 index 42c1cc2d..7f321f34 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,28 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - - - - - - - - buildscript { repositories { mavenCentral() @@ -51,8 +26,6 @@ dependencies { compile files('/home/theo/git/QRPushToTalk/libraries/gson-2.3.1.jar') } - -// Keep my credentials private :^) def signingFile = file 'signing.gradle'; if (signingFile.exists()) apply from: 'signing.gradle' @@ -64,8 +37,8 @@ android { minSdkVersion 14 targetSdkVersion 21 applicationId "com.terracom.qrpttbeta" - versionCode 80 - versionName "0.9.0" + versionCode 82 + versionName "1.0.0" testInstrumentationRunner "android.test.InstrumentationTestRunner" buildConfigField "boolean", "DONATE_NAG", "false" } @@ -82,7 +55,6 @@ android { } jenkins { - // Abuse Jenkins environment variables. Neat. def env = System.getenv() if (env.containsKey("BUILD_NUMBER") && env.containsKey("BUILD_DISPLAY_NAME")) { versionCode Integer.parseInt(env.get("BUILD_NUMBER")) diff --git a/app/src/androidTest/java/com/terracom/qrpttbeta/test/QRPushToTalkSQLTestCase.java b/app/src/androidTest/java/com/terracom/qrpttbeta/test/QRPushToTalkSQLTestCase.java old mode 100644 new mode 100755 index ea18d5bd..f9db4e7b --- a/app/src/androidTest/java/com/terracom/qrpttbeta/test/QRPushToTalkSQLTestCase.java +++ b/app/src/androidTest/java/com/terracom/qrpttbeta/test/QRPushToTalkSQLTestCase.java @@ -23,15 +23,9 @@ import java.util.UUID; -/** - * Test case designed to test operations of QRPushToTalk's database. - * A new DB is created and destroyed with each test call. - * Created by andrew on 19/08/14. - */ public class QRPushToTalkSQLTestCase extends AndroidTestCase { - /** Database name used in the active test. */ + private String mDatabaseName; - /** Database for the active test. */ private QRPushToTalkSQLiteDatabase mDatabase; @Override @@ -57,7 +51,6 @@ public void testLocalMuteIgnore() { long server = 5; int userId = 1; - // Test ignore duplicate constraint for (int i = 0; i < 2; i++) { mDatabase.addLocalMutedUser(server, userId); mDatabase.addLocalIgnoredUser(server, userId); diff --git a/app/src/free/AndroidManifest.xml b/app/src/free/AndroidManifest.xml old mode 100644 new mode 100755 index 9aaf70e6..28cbc07f --- a/app/src/free/AndroidManifest.xml +++ b/app/src/free/AndroidManifest.xml @@ -1,22 +1,4 @@ - - - diff --git a/app/src/free/ic_launcher-web.png b/app/src/free/ic_launcher-web.png old mode 100644 new mode 100755 diff --git a/app/src/free/res/drawable-hdpi/ic_launcher.png b/app/src/free/res/drawable-hdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/free/res/drawable-mdpi/ic_launcher.png b/app/src/free/res/drawable-mdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/free/res/drawable-xhdpi/ic_launcher.png b/app/src/free/res/drawable-xhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/free/res/drawable-xxhdpi/ic_launcher.png b/app/src/free/res/drawable-xxhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/free/res/drawable-xxxhdpi/ic_launcher.png b/app/src/free/res/drawable-xxxhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/free/res/values/strings.xml b/app/src/free/res/values/strings.xml old mode 100644 new mode 100755 index cc87ea61..430e8f9e --- a/app/src/free/res/values/strings.xml +++ b/app/src/free/res/values/strings.xml @@ -1,21 +1,4 @@ - - - QR PushToTalk BETA + QR-PTT PushToTalk \ No newline at end of file diff --git a/app/src/free/res/xml/searchable.xml b/app/src/free/res/xml/searchable.xml old mode 100644 new mode 100755 index ba30745e..8d137b0b --- a/app/src/free/res/xml/searchable.xml +++ b/app/src/free/res/xml/searchable.xml @@ -1,21 +1,4 @@ - - - @@ -74,12 +58,6 @@ android:name="com.terracom.qrpttbeta.service.QRPushToTalkService" android:enabled="true" /> - . - */ - package com.terracom.qrpttbeta; public class Constants { diff --git a/app/src/main/java/com/terracom/qrpttbeta/Settings.java b/app/src/main/java/com/terracom/qrpttbeta/Settings.java old mode 100644 new mode 100755 index 07c9afb2..dc538691 --- a/app/src/main/java/com/terracom/qrpttbeta/Settings.java +++ b/app/src/main/java/com/terracom/qrpttbeta/Settings.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta; import android.content.Context; @@ -31,18 +14,11 @@ import java.util.HashSet; import java.util.Set; -/** - * Singleton settings class for universal access to the app's preferences. - * @author terracom - */ public class Settings { public static final String PREF_INPUT_METHOD = "audioInputMethod"; public static final Set ARRAY_INPUT_METHODS; - /** Voice activity transmits depending on the amplitude of user input. */ public static final String ARRAY_INPUT_METHOD_VOICE = "voiceActivity"; - /** Push to talk transmits on command. */ public static final String ARRAY_INPUT_METHOD_PTT = "ptt"; - /** Continuous transmits always. */ public static final String ARRAY_INPUT_METHOD_CONTINUOUS = "continuous"; public static final String PREF_THRESHOLD = "vadThreshold"; @@ -84,10 +60,6 @@ public class Settings { public static final Boolean DEFAULT_AUTO_RECONNECT = true; public static final String PREF_THEME = "theme"; - public static final String ARRAY_THEME_LIGHT = "lightDark"; - public static final String ARRAY_THEME_DARK = "dark"; - public static final String ARRAY_THEME_SOLARIZED_LIGHT = "solarizedLight"; - public static final String ARRAY_THEME_SOLARIZED_DARK = "solarizedDark"; public static final String PREF_CERT = "certificatePath"; public static final String PREF_CERT_PASSWORD = "certificatePassword"; @@ -152,20 +124,13 @@ private Settings(Context ctx) { } public String getInputMethod() { - //String method = preferences.getString(PREF_INPUT_METHOD, ARRAY_INPUT_METHOD_VOICE); - String method = preferences.getString(PREF_INPUT_METHOD,ARRAY_INPUT_METHOD_PTT); - if(!ARRAY_INPUT_METHODS.contains(method)) { - // Set default method for users who used to use handset mode before removal. - //method = ARRAY_INPUT_METHOD_VOICE; + String method = preferences.getString(PREF_INPUT_METHOD, ARRAY_INPUT_METHOD_PTT); + if (!ARRAY_INPUT_METHODS.contains(method)) { method = ARRAY_INPUT_METHOD_PTT; } return method; } - /** - * Converts the preference input method value to the one used to connect to a server via Jumble. - * @return An input method value used to instantiate a Jumble service. - */ public int getJumbleInputMethod() { String inputMethod = getInputMethod(); if (ARRAY_INPUT_METHOD_VOICE.equals(inputMethod)) { @@ -179,7 +144,7 @@ public int getJumbleInputMethod() { } public void setInputMethod(String inputMethod) { - if(ARRAY_INPUT_METHOD_VOICE.equals(inputMethod) || + if (ARRAY_INPUT_METHOD_VOICE.equals(inputMethod) || ARRAY_INPUT_METHOD_PTT.equals(inputMethod) || ARRAY_INPUT_METHOD_CONTINUOUS.equals(inputMethod)) { preferences.edit().putString(PREF_INPUT_METHOD, "ptt").apply(); @@ -197,11 +162,11 @@ public int getInputQuality() { } public float getAmplitudeBoostMultiplier() { - return (float)preferences.getInt(Settings.PREF_AMPLITUDE_BOOST, DEFAULT_AMPLITUDE_BOOST)/100; + return (float) preferences.getInt(Settings.PREF_AMPLITUDE_BOOST, DEFAULT_AMPLITUDE_BOOST) / 100; } public float getDetectionThreshold() { - return (float)preferences.getInt(PREF_THRESHOLD, DEFAULT_THRESHOLD)/100; + return (float) preferences.getInt(PREF_THRESHOLD, DEFAULT_THRESHOLD) / 100; } public int getPushToTalkKey() { @@ -212,58 +177,30 @@ public String getHotCorner() { return preferences.getString(PREF_HOT_CORNER_KEY, DEFAULT_HOT_CORNER); } - /** - * Returns whether or not the hot corner is enabled. - * @return true if a hot corner should be shown. - */ public boolean isHotCornerEnabled() { return !ARRAY_HOT_CORNER_NONE.equals(preferences.getString(PREF_HOT_CORNER_KEY, DEFAULT_HOT_CORNER)); } - /** - * Returns the view gravity of the hot corner, or 0 if hot corner is disabled. - * @return A {@link android.view.Gravity} value, or 0 if disabled. - */ public int getHotCornerGravity() { String hc = getHotCorner(); - if(ARRAY_HOT_CORNER_BOTTOM_LEFT.equals(hc)) { + if (ARRAY_HOT_CORNER_BOTTOM_LEFT.equals(hc)) { return Gravity.LEFT | Gravity.BOTTOM; - } else if(ARRAY_HOT_CORNER_BOTTOM_RIGHT.equals(hc)) { + } else if (ARRAY_HOT_CORNER_BOTTOM_RIGHT.equals(hc)) { return Gravity.RIGHT | Gravity.BOTTOM; - } else if(ARRAY_HOT_CORNER_TOP_LEFT.equals(hc)) { + } else if (ARRAY_HOT_CORNER_TOP_LEFT.equals(hc)) { return Gravity.LEFT | Gravity.TOP; - } else if(ARRAY_HOT_CORNER_TOP_RIGHT.equals(hc)) { + } else if (ARRAY_HOT_CORNER_TOP_RIGHT.equals(hc)) { return Gravity.RIGHT | Gravity.TOP; } return 0; } - /** - * @return the resource ID of the user-defined theme. - */ - /*public int getTheme() { - String theme = preferences.getString(PREF_THEME, ARRAY_THEME_LIGHT); - if(ARRAY_THEME_LIGHT.equals(theme)) - return R.style.Theme_QRPushToTalk; - else if(ARRAY_THEME_DARK.equals(theme)) - return R.style.Theme_QRPushToTalk_Dark; - else if(ARRAY_THEME_SOLARIZED_LIGHT.equals(theme)) - return R.style.Theme_QRPushToTalk_Solarized_Light; - else if(ARRAY_THEME_SOLARIZED_DARK.equals(theme)) - return R.style.Theme_QRPushToTalk_Solarized_Dark; - return -1; - }*/ - public int getTheme() { return R.style.Theme_QRPushToTalk_Solarized_Light; } - /** - * Attempts to read the certificate from the path specified in settings. - * @return The parsed bytes of the certificate, or null otherwise. - */ public byte[] getCertificate() { try { FileInputStream inputStream = new FileInputStream(preferences.getString(PREF_CERT, "")); diff --git a/app/src/main/java/com/terracom/qrpttbeta/app/DrawerAdapter.java b/app/src/main/java/com/terracom/qrpttbeta/app/DrawerAdapter.java old mode 100644 new mode 100755 index 280ae563..18497547 --- a/app/src/main/java/com/terracom/qrpttbeta/app/DrawerAdapter.java +++ b/app/src/main/java/com/terracom/qrpttbeta/app/DrawerAdapter.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.app; import android.content.Context; @@ -28,35 +11,21 @@ import com.terracom.qrpttbeta.R; -/** - * Created by andrew on 01/08/13. - */ public class DrawerAdapter extends ArrayAdapter { - /** - * Provides context for the drawer module. - */ public interface DrawerDataProvider { - /** - * @return true if connected, false otherwise. - */ public boolean isConnected(); - /** - * @return The name of the connected server. If not connected, then null. - */ + public String getConnectedServerName(); } - // Drawer rows, integer value is id public static final int HEADER_CONNECTED_SERVER = 0; public static final int ITEM_SERVER = 1; public static final int ITEM_INFO = 2; public static final int ITEM_ACCESS_TOKENS = 3; public static final int ITEM_PINNED_CHANNELS = 4; - public static final int HEADER_SERVERS = 5; public static final int ITEM_FAVOURITES = 6; -// public static final int ITEM_LAN = 7; public static final int ITEM_PUBLIC = 8; public static final int HEADER_GENERAL = 9; public static final int ITEM_SETTINGS = 10; @@ -64,8 +33,6 @@ public interface DrawerDataProvider { private static final int HEADER_TYPE = 0; private static final int ITEM_TYPE = 1; - // TODO clean this up. - public static class DrawerRow { int id; String title; @@ -99,16 +66,8 @@ public DrawerAdapter(Context context, DrawerDataProvider provider) { mProvider = provider; add(new DrawerAdapter.DrawerHeader(HEADER_CONNECTED_SERVER, context.getString(R.string.drawer_not_connected))); add(new DrawerAdapter.DrawerItem(ITEM_SERVER, context.getString(R.string.drawer_server), R.drawable.ic_action_channels)); -// add(new DrawerAdapter.DrawerItem(ITEM_INFO, context.getString(R.string.information), R.drawable.ic_action_info_dark)); add(new DrawerAdapter.DrawerItem(ITEM_FAVOURITES, context.getString(R.string.drawer_favorites), R.drawable.ic_action_favourite_on)); -// add(new DrawerAdapter.DrawerItem(ITEM_ACCESS_TOKENS, "Disconnect", R.drawable.ic_action_save)); -// add(new DrawerAdapter.DrawerItem(ITEM_PINNED_CHANNELS, context.getString(R.string.drawer_pinned), R.drawable.ic_action_comment)); -// add(new DrawerAdapter.DrawerHeader(HEADER_SERVERS, context.getString(R.string.drawer_header_servers))); -// add(new DrawerAdapter.DrawerItem(ITEM_FAVOURITES, context.getString(R.string.drawer_favorites), R.drawable.ic_action_favourite_on)); -// add(new DrawerAdapter.DrawerItem(ITEM_LAN, context.getString(R.string.drawer_lan), R.drawable.ic_action_fullscreen)); // Coming soon, TODO -// add(new DrawerAdapter.DrawerItem(ITEM_PUBLIC, context.getString(R.string.drawer_public), R.drawable.ic_action_search)); add(new DrawerAdapter.DrawerHeader(HEADER_GENERAL, context.getString(R.string.general))); -// add(new DrawerAdapter.DrawerItem(ITEM_FAVOURITES, context.getString(R.string.drawer_favorites), R.drawable.ic_action_favourite_on)); add(new DrawerAdapter.DrawerItem(ITEM_SETTINGS, context.getString(R.string.action_settings), R.drawable.ic_action_settings)); add(new DrawerAdapter.DrawerItem(ITEM_PUBLIC, context.getString(R.string.drawer_public), R.drawable.ic_action_error)); @@ -118,21 +77,21 @@ public DrawerAdapter(Context context, DrawerDataProvider provider) { public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; int viewType = getItemViewType(position); - if(v == null) { - if(viewType == HEADER_TYPE) + if (v == null) { + if (viewType == HEADER_TYPE) v = LayoutInflater.from(getContext()).inflate(R.layout.list_drawer_header, parent, false); - else if(viewType == ITEM_TYPE) + else if (viewType == ITEM_TYPE) v = LayoutInflater.from(getContext()).inflate(R.layout.list_drawer_item, parent, false); } - if(viewType == HEADER_TYPE) { + if (viewType == HEADER_TYPE) { DrawerHeader header = (DrawerHeader) getItem(position); TextView title = (TextView) v.findViewById(R.id.drawer_header_title); - switch((int) getItemId(position)) { + switch ((int) getItemId(position)) { case HEADER_CONNECTED_SERVER: - if(mProvider.isConnected()) { + if (mProvider.isConnected()) { title.setText(mProvider.getConnectedServerName()); break; } @@ -140,7 +99,7 @@ else if(viewType == ITEM_TYPE) title.setText(header.title); break; } - } else if(viewType == ITEM_TYPE) { + } else if (viewType == ITEM_TYPE) { DrawerItem item = (DrawerItem) getItem(position); TextView title = (TextView) v.findViewById(R.id.drawer_item_title); ImageView icon = (ImageView) v.findViewById(R.id.drawer_item_icon); @@ -149,10 +108,9 @@ else if(viewType == ITEM_TYPE) boolean enabled = isEnabled(position); - // Set text and icon color+alpha based on enabled/disabled state int textColor = title.getCurrentTextColor(); - textColor &= 0x00FFFFFF; // Clear alpha bits - textColor |= enabled ? 0xFF000000 : 0x55000000; // Set alpha bits depending on whether the state is enabled or disabled + textColor &= 0x00FFFFFF; + textColor |= enabled ? 0xFF000000 : 0x55000000; title.setTextColor(textColor); icon.setColorFilter(textColor, PorterDuff.Mode.MULTIPLY); @@ -167,9 +125,9 @@ public long getItemId(int position) { } public DrawerRow getItemWithId(int id) { - for(int x=0;x. - */ - package com.terracom.qrpttbeta.app; -import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.ComponentName; @@ -38,7 +20,6 @@ import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarDrawerToggle; -import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; @@ -66,17 +47,13 @@ import com.terracom.qrpttbeta.db.PublicServer; import com.terracom.qrpttbeta.preference.QRPushToTalkCertificateGenerateTask; import com.terracom.qrpttbeta.preference.Preferences; -import com.terracom.qrpttbeta.servers.FavouriteServerAdapter; import com.terracom.qrpttbeta.servers.FavouriteServerListFragment; -import com.terracom.qrpttbeta.servers.PublicServerListFragment; import com.terracom.qrpttbeta.servers.ServerEditFragment; import com.terracom.qrpttbeta.service.QRPushToTalkService; import com.terracom.qrpttbeta.util.JumbleServiceFragment; import com.terracom.qrpttbeta.util.JumbleServiceProvider; import com.terracom.qrpttbeta.util.QRPushToTalkTrustStore; -import org.spongycastle.util.encoders.Hex; - import java.io.ByteArrayInputStream; import java.io.File; import java.net.MalformedURLException; @@ -88,18 +65,12 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; -import java.util.StringTokenizer; - -import info.guardianproject.onionkit.ui.OrbotHelper; - public class QRPushToTalkActivity extends ActionBarActivity implements ListView.OnItemClickListener, FavouriteServerListFragment.ServerConnectHandler, JumbleServiceProvider, DatabaseProvider, SharedPreferences.OnSharedPreferenceChangeListener, DrawerAdapter.DrawerDataProvider, ServerEditFragment.ServerEditListener { - /** - * If specified, the provided integer drawer fragment ID is shown when the activity is created. - */ + public static final String EXTRA_DRAWER_FRAGMENT = "drawer_fragment"; public static final String LastChannelPreference = "lastchannelloggedprefs"; @@ -108,7 +79,6 @@ public class QRPushToTalkActivity extends ActionBarActivity implements ListView. private QRPushToTalkService.QRPushToTalkBinder mService; private QRPushToTalkDatabase mDatabase; private Settings mSettings; - private ActionBarDrawerToggle mDrawerToggle; private DrawerLayout mDrawerLayout; private ListView mDrawerList; @@ -118,7 +88,6 @@ public class QRPushToTalkActivity extends ActionBarActivity implements ListView. private AlertDialog mErrorDialog; private AlertDialog.Builder mDisconnectPromptBuilder; - /** List of fragments to be notified about service state changes. */ private List mServiceFragments = new ArrayList(); private ServiceConnection mConnection = new ServiceConnection() { @@ -127,18 +96,17 @@ public void onServiceConnected(ComponentName name, IBinder service) { mService = (QRPushToTalkService.QRPushToTalkBinder) service; try { mService.registerObserver(mObserver); - mService.clearChatNotifications(); // Clear chat notifications on resume. + mService.clearChatNotifications(); } catch (RemoteException e) { e.printStackTrace(); } mDrawerAdapter.notifyDataSetChanged(); - for(JumbleServiceFragment fragment : mServiceFragments) + for (JumbleServiceFragment fragment : mServiceFragments) fragment.setServiceBound(true); - // Re-show server list if we're showing a fragment that depends on the service. try { - if(getSupportFragmentManager().findFragmentById(R.id.content_frame) instanceof JumbleServiceFragment && + if (getSupportFragmentManager().findFragmentById(R.id.content_frame) instanceof JumbleServiceFragment && mService.getConnectionState() != JumbleService.STATE_CONNECTED) { loadDrawerFragment(DrawerAdapter.ITEM_FAVOURITES); } @@ -164,15 +132,14 @@ public void onConnected() throws RemoteException { updateConnectionState(getService()); } - @Override - public void onConnecting() throws RemoteException { - updateConnectionState(getService()); - } + @Override + public void onConnecting() throws RemoteException { + updateConnectionState(getService()); + } @Override public void onDisconnected(JumbleException e) throws RemoteException { - // Re-show server list if we're showing a fragment that depends on the service. - if(getSupportFragmentManager().findFragmentById(R.id.content_frame) instanceof JumbleServiceFragment) { + if (getSupportFragmentManager().findFragmentById(R.id.content_frame) instanceof JumbleServiceFragment) { loadDrawerFragment(DrawerAdapter.ITEM_FAVOURITES); } mDrawerAdapter.notifyDataSetChanged(); @@ -190,42 +157,14 @@ public void onTLSHandshakeFailed(ParcelableByteArray cert) throws RemoteExceptio CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); final X509Certificate x509 = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(certBytes)); - //AlertDialog.Builder adb = new AlertDialog.Builder(QRPushToTalkActivity.this); - //adb.setTitle(R.string.untrusted_certificate); try { MessageDigest digest = MessageDigest.getInstance("SHA-1"); byte[] certDigest = digest.digest(x509.getEncoded()); - String hexDigest = new String(Hex.encode(certDigest)); - /*adb.setMessage(getString(R.string.certificate_info, - x509.getSubjectDN().getName(), - x509.getNotBefore().toString(), - x509.getNotAfter().toString(), - hexDigest));*/ } catch (NoSuchAlgorithmException e) { e.printStackTrace(); - //adb.setMessage(x509.toString()); } - /*adb.setPositiveButton(R.string.allow, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // Try to add to trust store - try { - String alias = lastServer.getHost(); - KeyStore trustStore = QRPushToTalkTrustStore.getTrustStore(QRPushToTalkActivity.this); - trustStore.setCertificateEntry(alias, x509); - QRPushToTalkTrustStore.saveTrustStore(QRPushToTalkActivity.this, trustStore); - Toast.makeText(QRPushToTalkActivity.this, R.string.trust_added, Toast.LENGTH_LONG).show(); - connectToServer(lastServer); - } catch (Exception e) { - e.printStackTrace(); - Toast.makeText(QRPushToTalkActivity.this, R.string.trust_add_failed, Toast.LENGTH_LONG).show(); - } - } - }); - adb.setNegativeButton(R.string.wizard_cancel, null); - adb.show();*/ try { String alias = lastServer.getHost(); KeyStore trustStore = QRPushToTalkTrustStore.getTrustStore(QRPushToTalkActivity.this); @@ -263,7 +202,7 @@ protected void onCreate(Bundle savedInstanceState) { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); preferences.registerOnSharedPreferenceChangeListener(this); - mDatabase = new QRPushToTalkSQLiteDatabase(this); // TODO add support for cloud storage + mDatabase = new QRPushToTalkSQLiteDatabase(this); mDatabase.open(); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); @@ -282,7 +221,6 @@ public void onDrawerStateChanged(int newState) { super.onDrawerStateChanged(newState); try { - // Prevent push to talk from getting stuck on when the drawer is opened. if (getService() != null && getService().getConnectionState() == JumbleService.STATE_CONNECTED && getService().isTalking() && !mSettings.isPushToTalkToggle()) { getService().setTalkingState(false); } @@ -301,8 +239,7 @@ public void onDrawerOpened(View drawerView) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); - // Tint logo to theme - int iconColor = getTheme().obtainStyledAttributes(new int[] { android.R.attr.textColorPrimaryInverse }).getColor(0, -1); + int iconColor = getTheme().obtainStyledAttributes(new int[]{android.R.attr.textColorPrimaryInverse}).getColor(0, -1); Drawable logo = getResources().getDrawable(R.drawable.ic_home); logo.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); getSupportActionBar().setLogo(logo); @@ -313,7 +250,8 @@ public void onDrawerOpened(View drawerView) { @Override public void onClick(DialogInterface dialog, int which) { try { - if(mService != null && mService.getConnectionState() == JumbleService.STATE_CONNECTED) mService.disconnect(); + if (mService != null && mService.getConnectionState() == JumbleService.STATE_CONNECTED) + mService.disconnect(); loadDrawerFragment(DrawerAdapter.ITEM_FAVOURITES); } catch (RemoteException e) { e.printStackTrace(); @@ -323,7 +261,7 @@ public void onClick(DialogInterface dialog, int which) { dadb.setNegativeButton(android.R.string.cancel, null); mDisconnectPromptBuilder = dadb; - if(savedInstanceState == null) { + if (savedInstanceState == null) { if (getIntent() != null && getIntent().hasExtra(EXTRA_DRAWER_FRAGMENT)) { loadDrawerFragment(getIntent().getIntExtra(EXTRA_DRAWER_FRAGMENT, DrawerAdapter.ITEM_FAVOURITES)); @@ -332,14 +270,11 @@ public void onClick(DialogInterface dialog, int which) { } } - // If we're given a Mumble URL to show, open up a server edit fragment. - if(getIntent() != null && + if (getIntent() != null && Intent.ACTION_VIEW.equals(getIntent().getAction())) { String url = getIntent().getDataString(); try { Server server = MumbleURLParser.parseURL(url); - - // Open a dialog prompting the user to add the Mumble server. Bundle args = new Bundle(); args.putBoolean("save", false); args.putParcelable("server", server); @@ -350,7 +285,7 @@ public void onClick(DialogInterface dialog, int which) { e.printStackTrace(); } } - if(mSettings.isFirstRun()) showSetupWizard(); + if (mSettings.isFirstRun()) showSetupWizard(); } @Override @@ -373,9 +308,9 @@ protected void onPause() { mErrorDialog.dismiss(); if (mConnectingDialog != null) mConnectingDialog.dismiss(); - if(mService != null) + if (mService != null) try { - for(JumbleServiceFragment fragment : mServiceFragments) + for (JumbleServiceFragment fragment : mServiceFragments) fragment.setServiceBound(false); mService.unregisterObserver(mObserver); } catch (RemoteException e) { @@ -391,10 +326,10 @@ protected void onDestroy() { mDatabase.close(); - if(!ServerEditFragment.CompanyNameStr.equals("")){ - SharedPreferences mysettings = getSharedPreferences(LastChannelPreference,0); + if (!ServerEditFragment.CompanyNameStr.equals("")) { + SharedPreferences mysettings = getSharedPreferences(LastChannelPreference, 0); SharedPreferences.Editor myEditor = mysettings.edit(); - myEditor.putString("LastChannel",ServerEditFragment.CompanyNameStr); + myEditor.putString("LastChannel", ServerEditFragment.CompanyNameStr); myEditor.commit(); } @@ -406,19 +341,13 @@ protected void onDestroy() { public boolean onPrepareOptionsMenu(Menu menu) { MenuItem disconnectButton = menu.findItem(R.id.action_disconnect); disconnectButton.setVisible(false); - /*try { - disconnectButton.setVisible(mService != null && mService.getConnectionState() == JumbleService.STATE_CONNECTED); - } catch (RemoteException e) { - e.printStackTrace(); - }*/ - // Color the action bar icons to the primary text color of the theme. int foregroundColor = getSupportActionBar().getThemedContext() - .obtainStyledAttributes(new int[] { android.R.attr.textColor }) + .obtainStyledAttributes(new int[]{android.R.attr.textColor}) .getColor(0, -1); - for(int x=0;x parent, View view, int position, long id) loadDrawerFragment((int) id); } - /** - * Shows a nice looking setup wizard to guide the user through the app's settings. - * Will do nothing if it isn't the first launch. - */ - /*private void showSetupWizard() { - // Prompt the user to generate a certificate, FIXME - if(mSettings.isUsingCertificate()) return; - AlertDialog.Builder adb = new AlertDialog.Builder(this); - adb.setTitle(R.string.first_run_generate_certificate_title); - adb.setMessage(R.string.first_run_generate_certificate); - adb.setPositiveButton(R.string.generate, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - QRPushToTalkCertificateGenerateTask generateTask = new QRPushToTalkCertificateGenerateTask(QRPushToTalkActivity.this) { - @Override - protected void onPostExecute(File result) { - super.onPostExecute(result); - if(result != null) mSettings.setCertificatePath(result.getAbsolutePath()); - } - }; - generateTask.execute(); - } - }); - adb.show(); - mSettings.setFirstRun(false); - - // TODO: finish wizard -// Intent intent = new Intent(this, WizardActivity.class); -// startActivity(intent); - }*/ - private void showSetupWizard() { - // Prompt the user to generate a certificate, FIXME - if(mSettings.isUsingCertificate()) return; + if (mSettings.isUsingCertificate()) return; AlertDialog.Builder adb = new AlertDialog.Builder(this); adb.setTitle(R.string.first_run_generate_certificate_title); adb.setMessage(R.string.first_run_generate_certificate); @@ -576,7 +455,7 @@ public void onClick(DialogInterface dialog, int which) { @Override protected void onPostExecute(File result) { super.onPostExecute(result); - if(result != null) mSettings.setCertificatePath(result.getAbsolutePath()); + if (result != null) mSettings.setCertificatePath(result.getAbsolutePath()); } }; generateTask.execute(); @@ -586,21 +465,13 @@ protected void onPostExecute(File result) { @Override protected void onPostExecute(File result) { super.onPostExecute(result); - if(result != null) mSettings.setCertificatePath(result.getAbsolutePath()); + if (result != null) mSettings.setCertificatePath(result.getAbsolutePath()); } }; generateTask.execute(); - //adb.show(); mSettings.setFirstRun(false); - - // TODO: finish wizard -// Intent intent = new Intent(this, WizardActivity.class); -// startActivity(intent); } - /** - * Loads a fragment from the drawer. - */ private void loadDrawerFragment(int fragmentId) { Class fragmentClass = null; Bundle args = new Bundle(); @@ -613,16 +484,10 @@ private void loadDrawerFragment(int fragmentId) { break; case DrawerAdapter.ITEM_ACCESS_TOKENS: try { - //if(getService().isConnected()){ - if(mService.getConnectionState() == JumbleService.STATE_CONNECTED){ - //getService().disconnect(); + if (mService.getConnectionState() == JumbleService.STATE_CONNECTED) { mService.disconnect(); - //mDisconnectPromptBuilder.show(); loadDrawerFragment(DrawerAdapter.ITEM_FAVOURITES); - /*if(mService.isConnected()){ - mService.disconnect(); - }*/ - }else{ + } else { loadDrawerFragment(DrawerAdapter.ITEM_FAVOURITES); Toast.makeText(QRPushToTalkActivity.this, "You are not connected!", Toast.LENGTH_LONG).show(); } @@ -630,16 +495,7 @@ private void loadDrawerFragment(int fragmentId) { loadDrawerFragment(DrawerAdapter.ITEM_FAVOURITES); e.printStackTrace(); } - /*fragmentClass = AccessTokenFragment.class; - try { - args.putLong("server", mService.getConnectedServer().getId()); - args.putStringArrayList("access_tokens", (ArrayList) mDatabase.getAccessTokens(mService.getConnectedServer().getId())); - } catch (RemoteException e) { - e.printStackTrace(); - }*/ - //fragmentClass = PublicServerListFragment.class; fragmentClass = FavouriteServerListFragment.class; - //fragmentClass = ChannelFragment.class; break; case DrawerAdapter.ITEM_PINNED_CHANNELS: fragmentClass = ChannelFragment.class; @@ -650,19 +506,13 @@ private void loadDrawerFragment(int fragmentId) { break; case DrawerAdapter.ITEM_PUBLIC: try { - //if(getService().isConnected()){ - if(mService.getConnectionState() == JumbleService.STATE_CONNECTED){ - //getService().disconnect(); + if (mService.getConnectionState() == JumbleService.STATE_CONNECTED) { mService.disconnect(); finish(); fragmentClass = ChannelFragment.class; - //System.exit(0); - } - else{ + } else { finish(); fragmentClass = FavouriteServerListFragment.class; - //fragmentClass = PublicServerListFragment.class; - //System.exit(0); } } catch (Exception e) { finish(); @@ -680,55 +530,17 @@ private void loadDrawerFragment(int fragmentId) { } Fragment fragment = Fragment.instantiate(this, fragmentClass.getName(), args); getSupportFragmentManager().beginTransaction() - .replace(R.id.content_frame, fragment, fragmentClass.getName()) - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) - .commit(); + .replace(R.id.content_frame, fragment, fragmentClass.getName()) + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) + .commit(); setTitle(mDrawerAdapter.getItemWithId(fragmentId).title); } public void connectToServer(final Server server) { - // Check if we're already connected to a server; if so, inform user. try { - if(mService != null && mService.getConnectionState() == JumbleService.STATE_CONNECTED) { - /*AlertDialog.Builder adb = new AlertDialog.Builder(this); - adb.setMessage(R.string.reconnect_dialog_message); - adb.setPositiveButton(R.string.connect, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - try { - // Register an observer to reconnect to the new server once disconnected. - mService.registerObserver(new JumbleObserver() { - @Override - public void onDisconnected(JumbleException e) throws RemoteException { - connectToServer(server); - mService.unregisterObserver(this); - } - }); - mService.disconnect(); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - }); - adb.setNegativeButton(android.R.string.cancel, null); - adb.show();*/ - /*try { - // Register an observer to reconnect to the new server once disconnected. - mService.registerObserver(new JumbleObserver() { - @Override - public void onDisconnected(JumbleException e) throws RemoteException { - connectToServer(server); - mService.unregisterObserver(this); - } - }); - mService.disconnect(); - } catch (RemoteException e) { - e.printStackTrace(); - } - return;*/ - if(FavouriteServerListFragment.myEditedflag){ + if (mService != null && mService.getConnectionState() == JumbleService.STATE_CONNECTED) { + if (FavouriteServerListFragment.myEditedflag) { try { - // Register an observer to reconnect to the new server once disconnected. mService.registerObserver(new JumbleObserver() { @Override public void onDisconnected(JumbleException e) throws RemoteException { @@ -751,18 +563,8 @@ public void onDisconnected(JumbleException e) throws RemoteException { e.printStackTrace(); } - /*// Prompt to start Orbot if enabled but not running - if (mSettings.isTorEnabled()) { - OrbotHelper orbotHelper = new OrbotHelper(this); - if (!orbotHelper.isOrbotRunning()) { - orbotHelper.requestOrbotStart(this); - return; - } - }*/ - - - SharedPreferences mysettings = getSharedPreferences(LastChannelPreference,0); - nameOfSavedLastLoggedChannel = mysettings.getString("LastChannel",""); + SharedPreferences mysettings = getSharedPreferences(LastChannelPreference, 0); + nameOfSavedLastLoggedChannel = mysettings.getString("LastChannel", ""); ServerConnectTask connectTask = new ServerConnectTask(this, mDatabase); @@ -773,11 +575,8 @@ public void connectToPublicServer(final PublicServer server) { AlertDialog.Builder alertBuilder = new AlertDialog.Builder(this); final Settings settings = Settings.getInstance(this); - - // Allow username entry final EditText usernameField = new EditText(this); usernameField.setHint(settings.getDefaultUsername()); - //usernameField.setHint("Leave empty, a demo GuardID will be used"); alertBuilder.setView(usernameField); alertBuilder.setTitle(R.string.connectToServer); @@ -786,7 +585,7 @@ public void connectToPublicServer(final PublicServer server) { @Override public void onClick(DialogInterface dialog, int which) { PublicServer newServer = server; - if(!usernameField.getText().toString().equals("")) + if (!usernameField.getText().toString().equals("")) newServer.setUsername(usernameField.getText().toString()); else newServer.setUsername(settings.getDefaultUsername()); @@ -805,13 +604,6 @@ private void setStayAwake(boolean stayAwake) { } } - /** - * Updates the activity to represent the connection state of the given service. - * Will show reconnecting dialog if reconnecting, dismiss otherwise, etc. - * Basically, this service will do catch-up if the activity wasn't bound to receive - * connection state updates. - * @param service A bound IJumbleService. - */ private void updateConnectionState(IJumbleService service) throws RemoteException { if (mConnectingDialog != null) mConnectingDialog.dismiss(); @@ -841,7 +633,6 @@ public void onCancel(DialogInterface dialog) { mConnectingDialog.show(); break; case JumbleService.STATE_CONNECTION_LOST: - // Only bother the user if the error hasn't already been shown. if (!getService().isErrorShown()) { JumbleException error = getService().getConnectionError(); AlertDialog.Builder ab = new AlertDialog.Builder(QRPushToTalkActivity.this); @@ -883,10 +674,6 @@ public void serverInfoUpdated() { loadDrawerFragment(DrawerAdapter.ITEM_FAVOURITES); } - /* - * HERE BE IMPLEMENTATIONS - */ - @Override public QRPushToTalkService.QRPushToTalkBinder getService() { return mService; @@ -909,9 +696,8 @@ public void removeServiceFragment(JumbleServiceFragment fragment) { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if(Settings.PREF_THEME.equals(key)) { - // Recreate activity when theme is changed - if(Build.VERSION.SDK_INT >= 11) + if (Settings.PREF_THEME.equals(key)) { + if (Build.VERSION.SDK_INT >= 11) recreate(); else { Intent intent = new Intent(this, QRPushToTalkActivity.class); @@ -936,7 +722,7 @@ public boolean isConnected() { @Override public String getConnectedServerName() { try { - if(mService != null && mService.getConnectionState() == JumbleService.STATE_CONNECTED) { + if (mService != null && mService.getConnectionState() == JumbleService.STATE_CONNECTED) { Server server = mService.getConnectedServer(); return server.getName().equals("") ? server.getHost() : server.getName(); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/app/ServerConnectTask.java b/app/src/main/java/com/terracom/qrpttbeta/app/ServerConnectTask.java old mode 100644 new mode 100755 index 412f5ab7..d9e54434 --- a/app/src/main/java/com/terracom/qrpttbeta/app/ServerConnectTask.java +++ b/app/src/main/java/com/terracom/qrpttbeta/app/ServerConnectTask.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.app; import android.content.Context; @@ -34,10 +17,6 @@ import java.util.ArrayList; -/** - * Constructs an intent for connection to a QRPushToTalkService and executes it. - * Created by andrew on 20/08/14. - */ public class ServerConnectTask extends AsyncTask { private Context mContext; private QRPushToTalkDatabase mDatabase; @@ -52,8 +31,6 @@ public ServerConnectTask(Context context, QRPushToTalkDatabase database) { @Override protected Intent doInBackground(Server... params) { Server server = params[0]; - - /* Convert input method defined in settings to an integer format used by Jumble. */ int inputMethod = mSettings.getJumbleInputMethod(); int audioSource = mSettings.isHandsetMode() ? @@ -70,7 +47,7 @@ protected Intent doInBackground(Server... params) { Intent connectIntent = new Intent(mContext, QRPushToTalkService.class); connectIntent.putExtra(JumbleService.EXTRAS_SERVER, server); - connectIntent.putExtra(JumbleService.EXTRAS_CLIENT_NAME, mContext.getString(R.string.app_name)+" "+applicationVersion); + connectIntent.putExtra(JumbleService.EXTRAS_CLIENT_NAME, mContext.getString(R.string.app_name) + " " + applicationVersion); connectIntent.putExtra(JumbleService.EXTRAS_TRANSMIT_MODE, inputMethod); connectIntent.putExtra(JumbleService.EXTRAS_DETECTION_THRESHOLD, mSettings.getDetectionThreshold()); connectIntent.putExtra(JumbleService.EXTRAS_AMPLITUDE_BOOST, mSettings.getAmplitudeBoostMultiplier()); diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/AccessTokenFragment.java b/app/src/main/java/com/terracom/qrpttbeta/channel/AccessTokenFragment.java deleted file mode 100644 index bf09861f..00000000 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/AccessTokenFragment.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.terracom.qrpttbeta.channel; - -import android.app.Activity; -import android.content.Context; -import android.os.Bundle; -import android.os.RemoteException; -import android.util.Log; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; - -import com.terracom.qrpttbeta.Constants; -import com.terracom.qrpttbeta.R; -import com.terracom.qrpttbeta.db.DatabaseProvider; -import com.terracom.qrpttbeta.util.JumbleServiceFragment; - -import java.util.ArrayList; -import java.util.List; - -public class AccessTokenFragment extends JumbleServiceFragment { - - public interface AccessTokenListener { - public void onAccessTokenAdded(long serverId, String token); - public void onAccessTokenRemoved(long serverId, String token); - } - - private List mTokens; - - private ListView mTokenList; - private TokenAdapter mTokenAdapter; - private EditText mTokenField; - - private DatabaseProvider mProvider; - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - - mTokens = new ArrayList(getAccessTokens()); - mTokenAdapter = new TokenAdapter(activity, mTokens); - - try { - mProvider = (DatabaseProvider) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement DatabaseProvider"); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_tokens, container, false); - - mTokenList = (ListView) view.findViewById(R.id.tokenList); - mTokenList.setAdapter(mTokenAdapter); - - mTokenField = (EditText) view.findViewById(R.id.tokenField); - mTokenField.setOnEditorActionListener(new OnEditorActionListener() { - - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if(actionId == EditorInfo.IME_ACTION_SEND) { - addToken(); - return true; - } - return false; - } - }); - - ImageButton addButton = (ImageButton) view.findViewById(R.id.tokenAddButton); - addButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - addToken(); - } - }); - - return view; - } - - private void addToken() { - String tokenText = mTokenField.getText().toString().trim(); - - if(tokenText.equals("")) - return; - - mTokenField.setText(""); - - Log.i(Constants.TAG, "Adding token: "+tokenText); - - mTokens.add(tokenText); - mTokenAdapter.notifyDataSetChanged(); - - mTokenList.smoothScrollToPosition(mTokens.size() - 1); - mProvider.getDatabase().addAccessToken(getServerId(), tokenText); - try { - getService().sendAccessTokens(mTokens); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - - private long getServerId() { - return getArguments().getLong("server"); - } - - private List getAccessTokens() { - return getArguments().getStringArrayList("access_tokens"); - } - - private class TokenAdapter extends ArrayAdapter { - - public TokenAdapter(Context context, - List objects) { - super(context, android.R.layout.simple_list_item_1, objects); - } - - @Override - public View getView(final int position, View convertView, ViewGroup parent) { - View view = convertView; - if(convertView == null) { - view = getActivity().getLayoutInflater().inflate(R.layout.token_row, null, false); - } - - final String token = getItem(position); - - TextView title = (TextView) view.findViewById(R.id.tokenItemTitle); - title.setText(token); - - ImageButton deleteButton = (ImageButton) view.findViewById(R.id.tokenItemDelete); - deleteButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - mTokens.remove(position); - notifyDataSetChanged(); - mProvider.getDatabase().removeAccessToken(getServerId(), token); - try { - getService().sendAccessTokens(mTokens); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - }); - - return view; - } - - } - -} diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelAdapter.java b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelAdapter.java old mode 100644 new mode 100755 index f29b9f07..b3d42660 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelAdapter.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelAdapter.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import android.content.Context; @@ -31,10 +14,6 @@ import com.terracom.jumble.model.User; import com.terracom.qrpttbeta.R; -/** - * Simple adapter to display the users in a single channel. - * Created by andrew on 24/11/13. - */ public class ChannelAdapter extends BaseAdapter { private Context mContext; @@ -70,7 +49,7 @@ public long getItemId(int position) { @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; - if(v == null) { + if (v == null) { LayoutInflater layoutInflater = LayoutInflater.from(mContext); v = layoutInflater.inflate(R.layout.overlay_user_row, parent, false); } @@ -89,8 +68,7 @@ else if (user.isMuted()) state.setImageResource(R.drawable.ic_server_muted); else if (user.isSuppressed()) state.setImageResource(R.drawable.ic_suppressed); - else - if (user.getTalkState() == User.TalkState.TALKING) + else if (user.getTalkState() == User.TalkState.TALKING) state.setImageResource(R.drawable.ic_talking_on); else state.setImageResource(R.drawable.ic_talking_off); diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelChatFragment.java b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelChatFragment.java old mode 100644 new mode 100755 index 656b70f7..1ff84faf --- a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelChatFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelChatFragment.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import android.app.Activity; @@ -61,7 +44,7 @@ public class ChannelChatFragment extends JumbleServiceFragment implements ChatTa private static final Pattern LINK_PATTERN = Pattern.compile("(https?://\\S+)"); private static final String CHAT_DATE_FORMAT = "%I:%M %p"; - private IJumbleObserver mServiceObserver = new JumbleObserver() { + private IJumbleObserver mServiceObserver = new JumbleObserver() { @Override public void onMessageLogged(Message message) throws RemoteException { @@ -73,7 +56,6 @@ public void onUserJoinedChannel(User user, Channel newChannel, Channel oldChanne if (user != null && getService().getSessionUser() != null && user.equals(getService().getSessionUser()) && mTargetProvider.getChatTarget() == null) { - // Update chat target when user changes channels without a target. updateChatTargetText(null); } } @@ -81,8 +63,8 @@ public void onUserJoinedChannel(User user, Channel newChannel, Channel oldChanne private ListView mChatList; private ChannelChatAdapter mChatAdapter; - private EditText mChatTextEdit; - private ImageButton mSendButton; + private EditText mChatTextEdit; + private ImageButton mSendButton; private ChatTargetProvider mTargetProvider; @Override @@ -97,7 +79,7 @@ public void onAttach(Activity activity) { try { mTargetProvider = (ChatTargetProvider) getParentFragment(); } catch (ClassCastException e) { - throw new ClassCastException(getParentFragment().toString()+" must implement ChatTargetProvider"); + throw new ClassCastException(getParentFragment().toString() + " must implement ChatTargetProvider"); } } @@ -114,14 +96,14 @@ public void onPause() { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_chat, container, false); + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_chat, container, false); mChatList = (ListView) view.findViewById(R.id.chat_list); - mChatTextEdit = (EditText) view.findViewById(R.id.chatTextEdit); - - mSendButton = (ImageButton) view.findViewById(R.id.chatTextSend); - mSendButton.setOnClickListener(new OnClickListener() { + mChatTextEdit = (EditText) view.findViewById(R.id.chatTextEdit); + + mSendButton = (ImageButton) view.findViewById(R.id.chatTextSend); + mSendButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { @@ -131,8 +113,8 @@ public void onClick(View v) { } } }); - - mChatTextEdit.setOnEditorActionListener(new OnEditorActionListener() { + + mChatTextEdit.setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { try { @@ -143,8 +125,8 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { return true; } }); - - mChatTextEdit.addTextChangedListener(new TextWatcher() { + + mChatTextEdit.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { @@ -167,7 +149,7 @@ public void afterTextChanged(Editable s) { e.printStackTrace(); } return view; - } + } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { @@ -184,17 +166,12 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } - /** - * Adds the passed text to the fragment chat body. - * @param message The message to add. - * @param scroll Whether to scroll to the bottom after adding the message. - */ public void addChatMessage(Message message, boolean scroll) { - if(mChatAdapter == null) return; + if (mChatAdapter == null) return; mChatAdapter.add(message); - if(scroll) { + if (scroll) { mChatList.post(new Runnable() { @Override @@ -203,34 +180,24 @@ public void run() { } }); } - } - - /** - * Sends the message currently in {@link com.terracom.qrpttbeta.channel.ChannelChatFragment#mChatTextEdit} - * to the remote server. Clears the message box if the message was sent successfully. - * @throws RemoteException If the service failed to send the message. - */ - private void sendMessage() throws RemoteException { - if(mChatTextEdit.length() == 0) return; + } + + private void sendMessage() throws RemoteException { + if (mChatTextEdit.length() == 0) return; String message = mChatTextEdit.getText().toString(); String formattedMessage = markupOutgoingMessage(message); ChatTargetProvider.ChatTarget target = mTargetProvider.getChatTarget(); Message responseMessage = null; - if(target == null) + if (target == null) responseMessage = getService().sendChannelTextMessage(getService().getSessionChannel().getId(), formattedMessage, false); - else if(target.getUser() != null) + else if (target.getUser() != null) responseMessage = getService().sendUserTextMessage(target.getUser().getSession(), formattedMessage); - else if(target.getChannel() != null) + else if (target.getChannel() != null) responseMessage = getService().sendChannelTextMessage(target.getChannel().getId(), formattedMessage, false); addChatMessage(responseMessage, true); mChatTextEdit.setText(""); - } + } - /** - * Adds HTML markup to the message, replacing links and newlines. - * @param message The message to markup. - * @return HTML data. - */ private String markupOutgoingMessage(String message) { String formattedBody = message; Matcher matcher = LINK_PATTERN.matcher(formattedBody); @@ -238,8 +205,8 @@ private String markupOutgoingMessage(String message) { .replaceAll("\n", "
"); return formattedBody; } - - public void clear() { + + public void clear() { mChatAdapter.clear(); try { getService().clearMessageLog(); @@ -248,23 +215,20 @@ public void clear() { } } - /** - * Updates hint displaying chat target. - */ - public void updateChatTargetText(ChatTargetProvider.ChatTarget target) throws RemoteException { - if(getService() == null) return; + public void updateChatTargetText(ChatTargetProvider.ChatTarget target) throws RemoteException { + if (getService() == null) return; String hint = null; - if(target == null && getService().getSessionChannel() != null) { + if (target == null && getService().getSessionChannel() != null) { hint = getString(R.string.messageToChannel, getService().getSessionChannel().getName()); - } else if(target != null && target.getUser() != null) { + } else if (target != null && target.getUser() != null) { hint = getString(R.string.messageToUser, target.getUser().getName()); - } else if(target != null && target.getChannel() != null) { + } else if (target != null && target.getChannel() != null) { hint = getString(R.string.messageToChannel, target.getChannel().getName()); } mChatTextEdit.setHint(hint); - mChatTextEdit.requestLayout(); // Needed to update bounds after hint change. - } + mChatTextEdit.requestLayout(); + } @Override @@ -311,7 +275,7 @@ public ChannelChatAdapter(Context context, IJumbleService service, List @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; - if(v == null) { + if (v == null) { v = LayoutInflater.from(getContext()).inflate(R.layout.list_chat_item, parent, false); } @@ -368,7 +332,7 @@ public boolean areAllItemsEnabled() { @Override public boolean isEnabled(int position) { - return false; // Makes links clickable. + return false; } } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelEditFragment.java b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelEditFragment.java old mode 100644 new mode 100755 index da212b63..bc717387 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelEditFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelEditFragment.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import android.app.Activity; @@ -34,9 +17,6 @@ import com.terracom.qrpttbeta.R; import com.terracom.qrpttbeta.util.JumbleServiceProvider; -/** - * Created by andrew on 23/11/13. - */ public class ChannelEditFragment extends DialogFragment { private JumbleServiceProvider mServiceProvider; @@ -66,7 +46,6 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { mTemporaryBox = (CheckBox) view.findViewById(R.id.channel_edit_temporary); try { - // If we can only make temporary channels, remove the option. Channel parentChannel = mServiceProvider.getService().getChannel(getParent()); int combinedPermissions = mServiceProvider.getService().getPermissions() | parentChannel.getPermissions(); boolean canMakeChannel = (combinedPermissions & Permissions.MakeChannel) > 0; @@ -85,7 +64,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { @Override public void onClick(DialogInterface dialog, int which) { try { - if(isAdding()) { + if (isAdding()) { mServiceProvider.getService().createChannel(getParent(), mNameField.getText().toString(), mDescriptionField.getText().toString(), @@ -103,22 +82,14 @@ public void onClick(DialogInterface dialog, int which) { .create(); } - /** - * @return true if the user is adding a new channel. - */ public boolean isAdding() { return getArguments().getBoolean("adding"); } - /** - * @return the parent channel that the new channel will be a child of. - */ public int getParent() { return getArguments().getInt("parent"); } - /** - * @return the channel being updated. - */ + public int getChannel() { return getArguments().getInt("channel"); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelFragment.java b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelFragment.java old mode 100644 new mode 100755 index 86ff3b1c..db145b63 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelFragment.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import android.content.SharedPreferences; @@ -47,10 +30,6 @@ import java.util.ArrayList; import java.util.List; -/** - * Class to encapsulate both a ChannelListFragment and ChannelChatFragment. - * Created by andrew on 02/08/13. - */ public class ChannelFragment extends JumbleServiceFragment implements SharedPreferences.OnSharedPreferenceChangeListener, ChatTargetProvider { private ViewPager mViewPager; @@ -59,7 +38,6 @@ public class ChannelFragment extends JumbleServiceFragment implements SharedPref private View mTalkView; private ChatTarget mChatTarget; - /** Chat target listeners, notified when the chat target is changed. */ private List mChatTargetListeners = new ArrayList(); private boolean mTogglePTT; @@ -67,8 +45,6 @@ public class ChannelFragment extends JumbleServiceFragment implements SharedPref @Override public void onUserTalkStateUpdated(User user) throws RemoteException { if (user != null && user.getSession() == getService().getSession()) { - // Manually set button selection colour when we receive a talk state update. - // This allows representation of talk state when using hot corners and PTT toggle. switch (user.getTalkState()) { case TALKING: case SHOUTING: @@ -94,8 +70,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa View view = inflater.inflate(R.layout.fragment_channel, container, false); mViewPager = (ViewPager) view.findViewById(R.id.channel_view_pager); mTabStrip = (PagerTabStrip) view.findViewById(R.id.channel_tab_strip); - if(mTabStrip != null) { - int[] attrs = new int[] { R.attr.colorPrimary, android.R.attr.textColorPrimaryInverse }; + if (mTabStrip != null) { + int[] attrs = new int[]{R.attr.colorPrimary, android.R.attr.textColorPrimaryInverse}; TypedArray a = getActivity().obtainStyledAttributes(attrs); int titleStripBackground = a.getColor(0, -1); int titleStripColor = a.getColor(1, -1); @@ -144,10 +120,10 @@ public void onActivityCreated(Bundle savedInstanceState) { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); preferences.registerOnSharedPreferenceChangeListener(this); - if(mViewPager != null) { // Phone + if (mViewPager != null) { ChannelFragmentPagerAdapter pagerAdapter = new ChannelFragmentPagerAdapter(getChildFragmentManager()); mViewPager.setAdapter(pagerAdapter); - } else { // Tablet + } else { ChannelListFragment listFragment = new ChannelListFragment(); Bundle listArgs = new Bundle(); listArgs.putBoolean("pinned", isShowingPinnedChannels()); @@ -164,7 +140,6 @@ public void onActivityCreated(Bundle savedInstanceState) { @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); -// inflater.inflate(R.menu.channel_menu, menu); } @Override @@ -196,17 +171,11 @@ public IJumbleObserver getServiceObserver() { return mObserver; } - /** - * @return true if the channel fragment is set to display only the user's pinned channels. - */ private boolean isShowingPinnedChannels() { return getArguments() != null && - getArguments().getBoolean("pinned"); + getArguments().getBoolean("pinned"); } - /** - * Configures the fragment in accordance with the user's interface preferences. - */ private void configureInput() { Settings settings = Settings.getInstance(getActivity()); boolean showPttButton = settings.isPushToTalkButtonShown() && settings.getInputMethod().equals(Settings.ARRAY_INPUT_METHOD_PTT); @@ -216,7 +185,7 @@ private void configureInput() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if(Settings.PREF_INPUT_METHOD.equals(key) || + if (Settings.PREF_INPUT_METHOD.equals(key) || Settings.PREF_PUSH_BUTTON_HIDE_KEY.equals(key) || Settings.PREF_PTT_TOGGLE.equals(key)) configureInput(); @@ -230,7 +199,7 @@ public ChatTarget getChatTarget() { @Override public void setChatTarget(ChatTarget target) { mChatTarget = target; - for(OnChatTargetSelectedListener listener : mChatTargetListeners) + for (OnChatTargetSelectedListener listener : mChatTargetListeners) listener.onChatTargetSelected(target); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelListAdapter.java b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelListAdapter.java old mode 100644 new mode 100755 index 5e3b5696..e364d4f7 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelListAdapter.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelListAdapter.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import android.content.Context; @@ -48,18 +31,11 @@ import java.util.LinkedList; import java.util.List; -/** - * Created by andrew on 31/07/13. - */ public class ChannelListAdapter extends RecyclerView.Adapter { - // Set particular bits to make the integer-based model item ids unique. public static final long CHANNEL_ID_MASK = (0x1L << 32); public static final long USER_ID_MASK = (0x1L << 33); String nameOfChannel = QRPushToTalkActivity.nameOfSavedLastLoggedChannel; - /** - * Time (in ms) to run the flip animation for. - */ private static final long FLIP_DURATION = 350; private Context mContext; @@ -67,10 +43,6 @@ public class ChannelListAdapter extends RecyclerView.Adapter { private QRPushToTalkDatabase mDatabase; private List mRootChannels; private List mNodes; - /** - * A mapping of user-set channel expansions. - * If a key is not mapped, default to hiding empty channels. - */ private HashMap mExpandedChannels; private OnUserClickListener mUserClickListener; private OnChannelClickListener mChannelClickListener; @@ -82,13 +54,12 @@ public ChannelListAdapter(Context context, IJumbleService service, QRPushToTalkD mDatabase = database; mRootChannels = new ArrayList(); - if(showPinnedOnly) { + if (showPinnedOnly) { mRootChannels = mDatabase.getPinnedChannels(mService.getConnectedServer().getId()); } else { mRootChannels.add(0); } - // Construct channel tree mNodes = new LinkedList(); mExpandedChannels = new HashMap(); updateChannels(); @@ -111,8 +82,8 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewT public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { final Node node = mNodes.get(position); - if(!nameOfChannel.equals("")){ - if(node.isChannel() && !node.getChannel().getName().equals(nameOfChannel) && !node.getChannel().getName().equals("QR-PushToTalk Server")){ + if (!nameOfChannel.equals("")) { + if (node.isChannel() && !node.getChannel().getName().equals(nameOfChannel) && !node.getChannel().getName().equals("QR-PushToTalk Server")) { try { updateChannels(); // FIXME: very inefficient. @@ -133,7 +104,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { e.printStackTrace(); } - } else if(node.isUser() && !node.getParent().getChannel().getName().equals(nameOfChannel)){ + } else if (node.isUser() && !node.getParent().getChannel().getName().equals(nameOfChannel)) { try { updateChannels(); // FIXME: very inefficient. @@ -148,18 +119,16 @@ public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { uvh.mUserHolder.setVisibility(View.GONE); uvh.itemView.setVisibility(View.GONE); - // Pad the view depending on channel's nested level. DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); float margin = (node.getDepth() + 1) * TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, metrics); - uvh.mUserHolder.setPadding((int) margin,0,uvh.mUserHolder.getPaddingRight(),0); + uvh.mUserHolder.setPadding((int) margin, 0, uvh.mUserHolder.getPaddingRight(), 0); try { updateChannels(); // FIXME: very inefficient. } catch (RemoteException e) { e.printStackTrace(); } - } - else if (node.isChannel() ) { + } else if (node.isChannel()) { final Channel channel = node.getChannel(); ChannelViewHolder cvh = (ChannelViewHolder) viewHolder; cvh.itemView.setOnClickListener(new View.OnClickListener() { @@ -188,20 +157,18 @@ public void onClick(View v) { notifyDataSetChanged(); } }); - // Dim channel expand toggle when no subchannels exist cvh.mChannelExpandToggle.setEnabled(expandUsable); cvh.mChannelExpandToggle.setVisibility(expandUsable ? View.VISIBLE : View.INVISIBLE); cvh.mChannelName.setText(channel.getName()); int userCount = channel.getSubchannelUserCount(); - if(node.getChannel().getName().equals("QR-PushToTalk Server")) + if (node.getChannel().getName().equals("QR-PushToTalk Server")) cvh.mChannelUserCount.setText(""); - else{ + else { cvh.mChannelUserCount.setText(String.format("%d", userCount)); } - // Pad the view depending on channel's nested level. DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); float margin = node.getDepth() * TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, metrics); cvh.mChannelHolder.setPadding((int) margin, @@ -239,7 +206,6 @@ public void onClick(View v) { uvh.mUserTalkHighlight.setImageDrawable(getTalkStateDrawable(user)); - // Pad the view depending on channel's nested level. DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); float margin = (node.getDepth() + 1) * TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, metrics); uvh.mUserHolder.setPadding((int) margin, @@ -252,8 +218,8 @@ public void onClick(View v) { e.printStackTrace(); } } - }else{ - if(node.isChannel() && !node.getChannel().getName().equals("Demo Channel") && !node.getChannel().getName().equals("QR-PushToTalk Server")){ + } else { + if (node.isChannel() && !node.getChannel().getName().equals("Demo Channel") && !node.getChannel().getName().equals("QR-PushToTalk Server")) { ChannelViewHolder cvh = (ChannelViewHolder) viewHolder; cvh.mChannelExpandToggle.setVisibility(View.GONE); cvh.mChannelName.setText(""); @@ -268,7 +234,7 @@ public void onClick(View v) { e.printStackTrace(); } - } else if(node.isUser() && !node.getParent().getChannel().getName().equals("Demo Channel")){ + } else if (node.isUser() && !node.getParent().getChannel().getName().equals("Demo Channel")) { UserViewHolder uvh = (UserViewHolder) viewHolder; uvh.mUserName.setText(""); uvh.mUserName.setVisibility(View.GONE); @@ -277,7 +243,6 @@ public void onClick(View v) { uvh.mUserHolder.setVisibility(View.GONE); uvh.itemView.setVisibility(View.GONE); - // Pad the view depending on channel's nested level. DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); float margin = (node.getDepth() + 1) * TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, metrics); uvh.mUserHolder.setPadding((int) margin, @@ -289,8 +254,7 @@ public void onClick(View v) { } catch (RemoteException e) { e.printStackTrace(); } - } - else if (node.isChannel()) { + } else if (node.isChannel()) { final Channel channel = node.getChannel(); ChannelViewHolder cvh = (ChannelViewHolder) viewHolder; cvh.itemView.setOnClickListener(new View.OnClickListener() { @@ -319,21 +283,19 @@ public void onClick(View v) { notifyDataSetChanged(); } }); - // Dim channel expand toggle when no subchannels exist + cvh.mChannelExpandToggle.setEnabled(expandUsable); cvh.mChannelExpandToggle.setVisibility(expandUsable ? View.VISIBLE : View.INVISIBLE); cvh.mChannelName.setText(channel.getName()); int userCount = channel.getSubchannelUserCount(); - if(node.getChannel().getName().equals("QR-PushToTalk Server")) + if (node.getChannel().getName().equals("QR-PushToTalk Server")) cvh.mChannelUserCount.setText(""); - else{ + else { cvh.mChannelUserCount.setText(String.format("%d", userCount)); } - - // Pad the view depending on channel's nested level. DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); float margin = node.getDepth() * TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, metrics); cvh.mChannelHolder.setPadding((int) margin, @@ -345,7 +307,7 @@ public void onClick(View v) { } catch (RemoteException e) { e.printStackTrace(); } - } else if (node.isUser() ) { + } else if (node.isUser()) { final User user = node.getUser(); UserViewHolder uvh = (UserViewHolder) viewHolder; uvh.itemView.setOnClickListener(new View.OnClickListener() { @@ -366,7 +328,6 @@ public void onClick(View v) { uvh.mUserTalkHighlight.setImageDrawable(getTalkStateDrawable(user)); - // Pad the view depending on channel's nested level. DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); float margin = (node.getDepth() + 1) * TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, metrics); uvh.mUserHolder.setPadding((int) margin, @@ -407,10 +368,6 @@ public long getItemId(int position) { return mNodes.get(position).getId(); } - /** - * Updates the channel tree model. - * To be used after any channel tree modifications. - */ public void updateChannels() throws RemoteException { mNodes.clear(); for (int cid : mRootChannels) { @@ -421,11 +378,6 @@ public void updateChannels() throws RemoteException { } } - /** - * Updates the user's state icon with a nice animation. - * @param user The user to update. - * @param view The view containing this adapter. - */ public void animateUserStateUpdate(User user, RecyclerView view) { long itemId = user.getSession() | USER_ID_MASK; UserViewHolder uvh = (UserViewHolder) view.findViewHolderForItemId(itemId); @@ -435,12 +387,10 @@ public void animateUserStateUpdate(User user, RecyclerView view) { if (!newState.getConstantState().equals(oldState.getConstantState())) { if (Build.VERSION.SDK_INT >= 12) { - // "Flip" in new talking state. FlipDrawable drawable = new FlipDrawable(oldState, newState); uvh.mUserTalkHighlight.setImageDrawable(drawable); drawable.start(FLIP_DURATION); } else { - // If we're on a platform without ValueAnimator, simply set the state image. uvh.mUserTalkHighlight.setImageDrawable(newState); } } @@ -465,7 +415,6 @@ private Drawable getTalkStateDrawable(User user) { // TODO: add whisper and shouting resources return resources.getDrawable(R.drawable.outline_circle_talking_on); } else { - // Passive drawables if (user.getTexture() != null) { return new CircleDrawable(mContext.getResources(), user.getTexture()); } else { @@ -504,13 +453,6 @@ public void setOnChannelClickListener(OnChannelClickListener listener) { mChannelClickListener = listener; } - /** - * Recursively creates a list of {@link Node}s representing the channel hierarchy. - * @param parent The parent node to propagate under. - * @param channel The parent channel. - * @param depth The current depth of the subtree. - * @param nodes An accumulator to store generated nodes into. - */ private void constructNodes(Node parent, Channel channel, int depth, List nodes) throws RemoteException { Node channelNode = new Node(parent, depth, channel); @@ -520,7 +462,7 @@ private void constructNodes(Node parent, Channel channel, int depth, if ((expandSetting == null && channel.getSubchannelUserCount() == 0) || (expandSetting != null && !expandSetting)) { channelNode.setExpanded(false); - return; // Skip adding children of contracted/empty channels. + return; } for (int uid : channel.getUsers()) { @@ -536,11 +478,6 @@ private void constructNodes(Node parent, Channel channel, int depth, } } - /** - * Changes the service backing the adapter. Updates the list as well. - * @param service The new service to retrieve channels from. - * @throws RemoteException - */ public void setService(IJumbleService service) throws RemoteException { mService = service; updateChannels(); @@ -551,7 +488,6 @@ private static class UserViewHolder extends RecyclerView.ViewHolder { public LinearLayout mUserHolder; public TextView mUserName; public FrameLayout mPicofMic; -// public ImageView mUserAvatar; public ImageView mUserTalkHighlight; public UserViewHolder(View itemView) { @@ -579,10 +515,6 @@ public ChannelViewHolder(View itemView) { } } - /** - * An arbitrary node in the channel-user hierarchy. - * Can be either a channel or user. - */ private static class Node { private Node mParent; private Channel mChannel; @@ -616,7 +548,7 @@ public Node getParent() { } public Channel getChannel() { - return mChannel; + return mChannel; } public User getUser() { @@ -624,7 +556,6 @@ public User getUser() { } public Long getId() { - // Apply flags to differentiate integer-length identifiers if (isChannel()) { return CHANNEL_ID_MASK | mChannel.getId(); } else if (isUser()) { diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelListFragment.java b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelListFragment.java old mode 100644 new mode 100755 index c8bee4b9..a50af0e5 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelListFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelListFragment.java @@ -1,31 +1,10 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import android.app.Activity; import android.app.SearchManager; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.database.CursorWrapper; -import android.graphics.PorterDuff; -import android.media.AudioManager; +import android.graphics.PorterDuff;; import android.os.Bundle; import android.os.RemoteException; import android.support.v4.view.MenuItemCompat; @@ -58,7 +37,7 @@ public class ChannelListFragment extends JumbleServiceFragment implements UserActionModeCallback.LocalUserUpdateListener, OnChannelClickListener, OnUserClickListener { - private IJumbleObserver mServiceObserver = new JumbleObserver() { + private IJumbleObserver mServiceObserver = new JumbleObserver() { @Override public void onDisconnected(JumbleException e) throws RemoteException { mChannelView.setAdapter(null); @@ -68,22 +47,22 @@ public void onDisconnected(JumbleException e) throws RemoteException { public void onUserJoinedChannel(User user, Channel newChannel, Channel oldChannel) throws RemoteException { mChannelListAdapter.updateChannels(); mChannelListAdapter.notifyDataSetChanged(); - if(getService().getSession() == user.getSession()) { + if (getService().getSession() == user.getSession()) { scrollToChannel(newChannel.getId()); } } @Override - public void onChannelAdded(Channel channel) throws RemoteException { + public void onChannelAdded(Channel channel) throws RemoteException { mChannelListAdapter.updateChannels(); - mChannelListAdapter.notifyDataSetChanged(); - } + mChannelListAdapter.notifyDataSetChanged(); + } - @Override - public void onChannelRemoved(Channel channel) throws RemoteException { + @Override + public void onChannelRemoved(Channel channel) throws RemoteException { mChannelListAdapter.updateChannels(); - mChannelListAdapter.notifyDataSetChanged(); - } + mChannelListAdapter.notifyDataSetChanged(); + } @Override public void onChannelStateUpdated(Channel channel) throws RemoteException { @@ -112,18 +91,10 @@ public void onUserStateUpdated(User user) throws RemoteException { public void onUserTalkStateUpdated(User user) throws RemoteException { mChannelListAdapter.animateUserStateUpdate(user, mChannelView); } - }; + }; - /*private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if(getActivity() != null) - getActivity().supportInvalidateOptionsMenu(); // Update bluetooth menu item - } - };*/ - - private RecyclerView mChannelView; - private ChannelListAdapter mChannelListAdapter; + private RecyclerView mChannelView; + private ChannelListAdapter mChannelListAdapter; private ChatTargetProvider mTargetProvider; private DatabaseProvider mDatabaseProvider; private ActionMode mActionMode; @@ -140,12 +111,12 @@ public void onAttach(Activity activity) { try { mTargetProvider = (ChatTargetProvider) getParentFragment(); } catch (ClassCastException e) { - throw new ClassCastException(getParentFragment().toString()+" must implement ChatTargetProvider"); + throw new ClassCastException(getParentFragment().toString() + " must implement ChatTargetProvider"); } try { mDatabaseProvider = (DatabaseProvider) getActivity(); } catch (ClassCastException e) { - throw new ClassCastException(getActivity().toString()+" must implement DatabaseProvider"); + throw new ClassCastException(getActivity().toString() + " must implement DatabaseProvider"); } } @@ -163,15 +134,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); registerForContextMenu(mChannelView); - //getActivity().registerReceiver(mBluetoothReceiver, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED)); } - /*@Override - public void onDetach() { - getActivity().unregisterReceiver(mBluetoothReceiver); - super.onDetach(); - }*/ - @Override public IJumbleObserver getServiceObserver() { return mServiceObserver; @@ -198,8 +162,7 @@ public void onPrepareOptionsMenu(Menu menu) { MenuItem deafenItem = menu.findItem(R.id.menu_deafen_button); try { - if(getService() != null && getService().getConnectionState() == JumbleService.STATE_CONNECTED && getService().getSessionUser() != null) { - // Color the action bar icons to the primary text color of the theme, TODO move this elsewhere + if (getService() != null && getService().getConnectionState() == JumbleService.STATE_CONNECTED && getService().getSessionUser() != null) { int foregroundColor = getActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.textColorPrimaryInverse}).getColor(0, -1); User self = getService().getSessionUser(); @@ -211,15 +174,6 @@ public void onPrepareOptionsMenu(Menu menu) { } catch (RemoteException e) { e.printStackTrace(); } - - /*try { - if(getService() != null) { - MenuItem bluetoothItem = menu.findItem(R.id.menu_bluetooth); - bluetoothItem.setChecked(getService().isBluetoothAvailable()); - } - } catch (RemoteException e) { - e.printStackTrace(); - }*/ } @Override @@ -229,7 +183,7 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { MenuItem searchItem = menu.findItem(R.id.menu_search); SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); - final SearchView searchView = (SearchView)MenuItemCompat.getActionView(searchItem); + final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem); searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName())); searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() { @Override @@ -244,9 +198,9 @@ public boolean onSuggestionClick(int i) { int dataIdColumn = cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_INTENT_DATA); String itemType = cursor.getString(typeColumn); int itemId = cursor.getInt(dataIdColumn); - if(ChannelSearchProvider.INTENT_DATA_CHANNEL.equals(itemType)) { + if (ChannelSearchProvider.INTENT_DATA_CHANNEL.equals(itemType)) { try { - if(getService().getSessionChannel().getId() != itemId) { + if (getService().getSessionChannel().getId() != itemId) { getService().joinChannel(itemId); } else { scrollToChannel(itemId); @@ -255,7 +209,7 @@ public boolean onSuggestionClick(int i) { e.printStackTrace(); } return true; - } else if(ChannelSearchProvider.INTENT_DATA_USER.equals(itemType)) { + } else if (ChannelSearchProvider.INTENT_DATA_USER.equals(itemType)) { scrollToUser(itemId); return true; } @@ -274,7 +228,7 @@ public boolean onOptionsItemSelected(MenuItem item) { boolean muted = !self.isSelfMuted(); boolean deafened = self.isSelfDeafened(); - deafened &= muted; // Undeafen if mute is off + deafened &= muted; self.setSelfMuted(muted); self.setSelfDeafened(deafened); getService().setSelfMuteDeafState(self.isSelfMuted(), self.isSelfDeafened()); @@ -300,14 +254,6 @@ public boolean onOptionsItemSelected(MenuItem item) { return true; case R.id.menu_search: return false; - /*case R.id.menu_bluetooth: - item.setChecked(!item.isChecked()); - try { - getService().setBluetoothEnabled(item.isChecked()); - } catch (RemoteException e) { - e.printStackTrace(); - } - return true;*/ } return super.onOptionsItemSelected(item); @@ -319,22 +265,17 @@ private void setupChannelList() throws RemoteException { mChannelListAdapter.setOnUserClickListener(this); mChannelView.setAdapter(mChannelListAdapter); mChannelListAdapter.notifyDataSetChanged(); - } + } - /** - * Scrolls to the passed channel. - */ - public void scrollToChannel(int channelId) { - int channelPosition = mChannelListAdapter.getChannelPosition(channelId); + public void scrollToChannel(int channelId) { + int channelPosition = mChannelListAdapter.getChannelPosition(channelId); mChannelView.smoothScrollToPosition(channelPosition); } - /** - * Scrolls to the passed user. - */ - public void scrollToUser(int userId) { - int userPosition = mChannelListAdapter.getUserPosition(userId); - mChannelView.smoothScrollToPosition(userPosition); - } + + public void scrollToUser(int userId) { + int userPosition = mChannelListAdapter.getUserPosition(userId); + mChannelView.smoothScrollToPosition(userPosition); + } private boolean isShowingPinnedChannels() { return getArguments().getBoolean("pinned"); @@ -344,8 +285,6 @@ private boolean isShowingPinnedChannels() { public void onLocalUserStateUpdated(final User user) { try { mChannelListAdapter.notifyDataSetChanged(); - - // Add or remove registered user from local mute history final QRPushToTalkDatabase database = mDatabaseProvider.getDatabase(); final Server server = getService().getConnectedServer(); @@ -376,7 +315,6 @@ public void onChannelClick(Channel channel) { if (mTargetProvider.getChatTarget() != null && channel.equals(mTargetProvider.getChatTarget().getChannel()) && mActionMode != null) { - // Dismiss action mode if double pressed. FIXME: use list view selection instead? mActionMode.finish(); } else { ActionMode.Callback cb = new ChannelActionModeCallback(getActivity(), @@ -388,7 +326,7 @@ public void onDestroyActionMode(ActionMode actionMode) { mActionMode = null; } }; - mActionMode = ((ActionBarActivity)getActivity()).startSupportActionMode(cb); + mActionMode = ((ActionBarActivity) getActivity()).startSupportActionMode(cb); } } @@ -397,7 +335,6 @@ public void onUserClick(User user) { if (mTargetProvider.getChatTarget() != null && user.equals(mTargetProvider.getChatTarget().getUser()) && mActionMode != null) { - // Dismiss action mode if double pressed. FIXME: use list view selection instead? mActionMode.finish(); } else { ActionMode.Callback cb = new UserActionModeCallback(getActivity(), getService(), user, mTargetProvider, getChildFragmentManager(), this) { @@ -407,7 +344,7 @@ public void onDestroyActionMode(ActionMode actionMode) { mActionMode = null; } }; - mActionMode = ((ActionBarActivity)getActivity()).startSupportActionMode(cb); + mActionMode = ((ActionBarActivity) getActivity()).startSupportActionMode(cb); } } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelSearchProvider.java b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelSearchProvider.java old mode 100644 new mode 100755 index 15bfd80c..ba8bb321 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelSearchProvider.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/ChannelSearchProvider.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import android.app.SearchManager; @@ -42,60 +25,56 @@ import java.util.Locale; public class ChannelSearchProvider extends ContentProvider { - - public static final String INTENT_DATA_CHANNEL = "channel"; - public static final String INTENT_DATA_USER = "user"; + + public static final String INTENT_DATA_CHANNEL = "channel"; + public static final String INTENT_DATA_USER = "user"; private IJumbleService mService; private final Object mServiceLock = new Object(); - private ServiceConnection mConn = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - mService = (IJumbleService) service; + private ServiceConnection mConn = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mService = (IJumbleService) service; synchronized (mServiceLock) { mServiceLock.notify(); } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mService = null; - } - }; - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public String getType(Uri uri) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean onCreate() { - return true; - } - - - @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - - // Try to connect to the service. Wait for conn to establish. - if(mService == null) { - Intent serviceIntent = new Intent(getContext(), QRPushToTalkService.class); - getContext().bindService(serviceIntent, mConn, 0); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mService = null; + } + }; + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public String getType(Uri uri) { + return null; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + @Override + public boolean onCreate() { + return true; + } + + + @Override + public Cursor query(Uri uri, String[] projection, String selection, + String[] selectionArgs, String sortOrder) { + + if (mService == null) { + Intent serviceIntent = new Intent(getContext(), QRPushToTalkService.class); + getContext().bindService(serviceIntent, mConn, 0); synchronized (mServiceLock) { try { @@ -104,23 +83,23 @@ public Cursor query(Uri uri, String[] projection, String selection, e.printStackTrace(); } - if(mService == null) { + if (mService == null) { Log.v(Constants.TAG, "Failed to connect to service from search provider!"); return null; } } - } - - String query = ""; - for(int x=0;x channels; List users; @@ -132,35 +111,25 @@ public Cursor query(Uri uri, String[] projection, String selection, return cursor; } - for(int x=0;x userSearch(Channel root, String str) throws RemoteException { List list = new LinkedList(); userSearch(root, str, list); return list; } - /** - * @see #userSearch(Channel,String) - */ private void userSearch(Channel root, String str, List users) throws RemoteException { if (root == null) { return; @@ -178,22 +147,12 @@ private void userSearch(Channel root, String str, List users) throws Remot } } - /** - * Recursively searches the channel tree for a channel with a name containing the given string, - * ignoring case. - * @param root The channel to recursively search for subchannels within. - * @param str The string to match against the channel's name. Case insensitive. - * @return A list of channels whose names contain str. - */ private List channelSearch(Channel root, String str) throws RemoteException { List list = new LinkedList(); channelSearch(root, str, list); return list; } - /** - * @see #channelSearch(Channel,String) - */ private void channelSearch(Channel root, String str, List channels) throws RemoteException { if (root == null) { return; @@ -209,11 +168,10 @@ private void channelSearch(Channel root, String str, List channels) thr } } - @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { - // TODO Auto-generated method stub - return 0; - } + @Override + public int update(Uri uri, ContentValues values, String selection, + String[] selectionArgs) { + return 0; + } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/ChatTargetProvider.java b/app/src/main/java/com/terracom/qrpttbeta/channel/ChatTargetProvider.java old mode 100644 new mode 100755 index a7e5892b..d33e35c1 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/ChatTargetProvider.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/ChatTargetProvider.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import com.terracom.jumble.model.Channel; @@ -22,9 +5,6 @@ public interface ChatTargetProvider { - /** - * Abstraction for user and channel chat targets. - */ public class ChatTarget { private Channel mChannel; private User mUser; @@ -46,16 +26,15 @@ public User getUser() { } } - /** - * Interface for classes which wish to receive chat target change calls. - * Created by andrew on 06/08/13. - */ public interface OnChatTargetSelectedListener { public void onChatTargetSelected(ChatTarget target); } public ChatTarget getChatTarget(); + public void setChatTarget(ChatTarget target); + public void registerChatTargetListener(OnChatTargetSelectedListener listener); + public void unregisterChatTargetListener(OnChatTargetSelectedListener listener); } \ No newline at end of file diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/OnChannelClickListener.java b/app/src/main/java/com/terracom/qrpttbeta/channel/OnChannelClickListener.java old mode 100644 new mode 100755 index 9f4eb713..e2d105ae --- a/app/src/main/java/com/terracom/qrpttbeta/channel/OnChannelClickListener.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/OnChannelClickListener.java @@ -1,27 +1,7 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import com.terracom.jumble.model.Channel; -/** - * Created by andrew on 20/10/14. - */ public interface OnChannelClickListener { public void onChannelClick(Channel channel); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/OnUserClickListener.java b/app/src/main/java/com/terracom/qrpttbeta/channel/OnUserClickListener.java old mode 100644 new mode 100755 index b1682049..b822da2b --- a/app/src/main/java/com/terracom/qrpttbeta/channel/OnUserClickListener.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/OnUserClickListener.java @@ -1,27 +1,7 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import com.terracom.jumble.model.User; -/** - * Created by andrew on 20/10/14. - */ public interface OnUserClickListener { public void onUserClick(User user); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/ServerInfoFragment.java b/app/src/main/java/com/terracom/qrpttbeta/channel/ServerInfoFragment.java old mode 100644 new mode 100755 index 157af8cb..1e1c165c --- a/app/src/main/java/com/terracom/qrpttbeta/channel/ServerInfoFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/ServerInfoFragment.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel; import android.os.Bundle; @@ -28,7 +11,6 @@ import com.terracom.jumble.IJumbleService; import com.terracom.jumble.JumbleService; -import com.terracom.jumble.net.JumbleConnection; import com.terracom.jumble.net.JumbleUDPMessageType; import com.terracom.qrpttbeta.R; import com.terracom.qrpttbeta.util.JumbleServiceFragment; @@ -37,10 +19,6 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -/** - * A fragment that displays known information from the remote server. - * Created by andrew on 28/08/13. - */ public class ServerInfoFragment extends JumbleServiceFragment { private static final int POLL_RATE = 1000; @@ -71,17 +49,14 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa return view; } - /** - * Updates the info from the service. - */ public void updateData() throws RemoteException { - if(getService() == null || getService().getConnectionState() != JumbleService.STATE_CONNECTED) + if (getService() == null || getService().getConnectionState() != JumbleService.STATE_CONNECTED) return; mProtocolView.setText(getString(R.string.server_info_protocol, getService().getServerRelease())); mOSVersionView.setText(getString(R.string.server_info_version, getService().getServerOSName(), getService().getServerOSVersion())); - mTCPLatencyView.setText(getString(R.string.server_info_latency, (float)getService().getTCPLatency()*Math.pow(10, -3))); - mUDPLatencyView.setText(getString(R.string.server_info_latency, (float)getService().getUDPLatency()*Math.pow(10, -3))); + mTCPLatencyView.setText(getString(R.string.server_info_latency, (float) getService().getTCPLatency() * Math.pow(10, -3))); + mUDPLatencyView.setText(getString(R.string.server_info_latency, (float) getService().getUDPLatency() * Math.pow(10, -3))); mHostView.setText(getString(R.string.server_info_host, getService().getConnectedServer().getHost(), getService().getConnectedServer().getPort())); String codecName; @@ -103,14 +78,13 @@ public void updateData() throws RemoteException { codecName = "???"; } - mMaxBandwidthView.setText(getString(R.string.server_info_max_bandwidth, (float)getService().getMaxBandwidth()/1000f)); - mCurrentBandwidthView.setText(getString(R.string.server_info_current_bandwidth, (float)getService().getCurrentBandwidth()/1000f)); + mMaxBandwidthView.setText(getString(R.string.server_info_max_bandwidth, (float) getService().getMaxBandwidth() / 1000f)); + mCurrentBandwidthView.setText(getString(R.string.server_info_current_bandwidth, (float) getService().getCurrentBandwidth() / 1000f)); mCodecView.setText(getString(R.string.server_info_codec, codecName)); } @Override public void onServiceBound(IJumbleService service) { - // wow this is ugly mExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { @@ -118,7 +92,7 @@ public void run() { @Override public void run() { try { - if(!isDetached()) updateData(); + if (!isDetached()) updateData(); } catch (RemoteException e) { e.printStackTrace(); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/ChannelActionModeCallback.java b/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/ChannelActionModeCallback.java old mode 100644 new mode 100755 index f7ab2c6c..902563a1 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/ChannelActionModeCallback.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/ChannelActionModeCallback.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel.actionmode; import android.app.AlertDialog; @@ -40,12 +23,6 @@ import com.terracom.qrpttbeta.db.QRPushToTalkDatabase; import com.terracom.qrpttbeta.util.TintedMenuInflater; -/** - * Contextual action mode for channels. - * When the action mode is activated, the user is set to the current chat target. - * Upon dismissal, the chat target is reset (usually to the current channel). - * Created by andrew on 24/06/14. - */ public class ChannelActionModeCallback extends ChatTargetActionModeCallback { private Context mContext; private IJumbleService mService; @@ -77,8 +54,7 @@ public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { actionMode.setSubtitle(R.string.current_chat_target); try { - // Request permissions update from server, if we don't have channel permissions - if(mChannel.getPermissions() == 0) + if (mChannel.getPermissions() == 0) mService.requestPermissions(mChannel.getId()); } catch (RemoteException e) { e.printStackTrace(); @@ -89,10 +65,6 @@ public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { @Override public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { int perms = mChannel.getPermissions(); - - // This breaks uMurmur ACL. Put in a fix based on server version perhaps? - //menu.getMenu().findItem(R.id.menu_channel_add) - // .setVisible((permissions & (Permissions.MakeChannel | Permissions.MakeTempChannel)) > 0); menu.findItem(R.id.context_channel_edit).setVisible((perms & Permissions.Write) > 0); menu.findItem(R.id.context_channel_remove).setVisible((perms & Permissions.Write) > 0); menu.findItem(R.id.context_channel_view_description) @@ -101,9 +73,7 @@ public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { try { Server server = mService.getConnectedServer(); - if(server != null) { -// menu.findItem(R.id.context_channel_pin) -// .setChecked(mDatabase.isChannelPinned(server.getId(), mChannel.getId())); + if (server != null) { } } catch (RemoteException e) { e.printStackTrace(); @@ -115,7 +85,7 @@ public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { @Override public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { boolean adding = false; - switch(menuItem.getItemId()) { + switch (menuItem.getItemId()) { case R.id.context_channel_join: try { mService.joinChannel(mChannel.getId()); @@ -128,7 +98,7 @@ public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { case R.id.context_channel_edit: ChannelEditFragment addFragment = new ChannelEditFragment(); Bundle args = new Bundle(); - if(adding) args.putInt("parent", mChannel.getId()); + if (adding) args.putInt("parent", mChannel.getId()); else args.putInt("channel", mChannel.getId()); args.putBoolean("adding", adding); addFragment.setArguments(args); @@ -160,16 +130,6 @@ public void onClick(DialogInterface dialog, int which) { ChannelDescriptionFragment.class.getName(), commentArgs); commentFragment.show(mFragmentManager, ChannelDescriptionFragment.class.getName()); break; -/* case R.id.context_channel_pin: - try { - long serverId = mService.getConnectedServer().getId(); - boolean pinned = mDatabase.isChannelPinned(serverId, mChannel.getId()); - if(!pinned) mDatabase.addPinnedChannel(serverId, mChannel.getId()); - else mDatabase.removePinnedChannel(serverId, mChannel.getId()); - } catch (RemoteException e) { - e.printStackTrace(); - } - break;*/ } actionMode.finish(); return true; diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/ChatTargetActionModeCallback.java b/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/ChatTargetActionModeCallback.java old mode 100644 new mode 100755 index e6ac339d..3fd58291 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/ChatTargetActionModeCallback.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/ChatTargetActionModeCallback.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel.actionmode; import android.support.v7.view.ActionMode; @@ -22,11 +5,6 @@ import com.terracom.qrpttbeta.channel.ChatTargetProvider; -/** - * A callback that sets the active chat target when activated, and resets when destroyed (usually - * to the user's current channel). - * Created by andrew on 26/06/14. - */ public abstract class ChatTargetActionModeCallback implements ActionMode.Callback { private ChatTargetProvider mProvider; diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/UserActionModeCallback.java b/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/UserActionModeCallback.java old mode 100644 new mode 100755 index db6d8dcb..f6e1b46b --- a/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/UserActionModeCallback.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/actionmode/UserActionModeCallback.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel.actionmode; import android.app.AlertDialog; @@ -41,12 +24,6 @@ import java.util.List; -/** - * Contextual action mode for users. - * When the action mode is activated, the user is set to the current chat target. - * Upon dismissal, the chat target is reset (usually to the channel). - * Created by andrew on 24/06/14. - */ public class UserActionModeCallback extends ChatTargetActionModeCallback { private Context mContext; private IJumbleService mService; @@ -78,9 +55,8 @@ public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { actionMode.setSubtitle(R.string.current_chat_target); try { - // Request permissions update from server, if we don't have channel permissions Channel channel = mService.getChannel(mUser.getChannelId()); - if(channel != null && channel.getPermissions() == 0) + if (channel != null && channel.getPermissions() == 0) mService.requestPermissions(mUser.getChannelId()); } catch (RemoteException e) { e.printStackTrace(); @@ -92,7 +68,6 @@ public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { @Override public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { try { - // Use permission data to determine the actions available. boolean self = mUser.getSession() == mService.getSession(); int perms = mService.getPermissions(); Channel channel = mService.getChannel(mUser.getChannelId()); @@ -126,10 +101,6 @@ public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { menu.findItem(R.id.context_local_mute).setVisible(!self); menu.findItem(R.id.context_ignore_messages).setVisible(!self); - // TODO info -// informationItem.enabled = (((perms & (Permissions.Write | Permissions.Register))) > 0 || (channelPermissions & (Permissions.Write | Permissions.Enter)) > 0 || (mUser.getSession() == mService.getSession())); - - // Highlight toggles menu.findItem(R.id.context_mute).setChecked(mUser.isMuted() || mUser.isSuppressed()); menu.findItem(R.id.context_deafen).setChecked(mUser.isDeafened()); menu.findItem(R.id.context_priority).setChecked(mUser.isPrioritySpeaker()); @@ -147,15 +118,6 @@ public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { try { boolean ban = false; switch (menuItem.getItemId()) { -// case R.id.context_send_message: -// if(mChatTargetProvider.getChatTarget() != null && -// mChatTargetProvider.getChatTarget().getUser() != null && -// mChatTargetProvider.getChatTarget().getUser().equals(mUser)) { -// mChatTargetProvider.setChatTarget(null); -// } else { -// mChatTargetProvider.setChatTarget(new ChatTargetProvider.ChatTarget(mUser)); -// } -// break; case R.id.context_ban: ban = true; case R.id.context_kick: @@ -220,8 +182,6 @@ public void onClick(DialogInterface dialog, int which) { .setNegativeButton(android.R.string.cancel, null) .show(); break; -// case R.id.context_info: -// break; case R.id.context_register: mService.registerUser(mUser.getSession()); break; @@ -230,7 +190,7 @@ public void onClick(DialogInterface dialog, int which) { e.printStackTrace(); return false; } - actionMode.finish(); // FIXME? + actionMode.finish(); return true; } @@ -275,12 +235,6 @@ public void onClick(DialogInterface dialog, int which) { adb.show(); } - /** - * Interface for observers that wish to be notified when the user state needs to be redrawn. - * Note that this is only for local changes- server-side state changes will be propagated to - * the respective Jumble callbacks. - * i.e. if the user becomes local muted. - */ public interface LocalUserUpdateListener { public void onLocalUserStateUpdated(User user); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/comment/AbstractCommentFragment.java b/app/src/main/java/com/terracom/qrpttbeta/channel/comment/AbstractCommentFragment.java old mode 100644 new mode 100755 index 8c0af9bd..db6e9cc1 --- a/app/src/main/java/com/terracom/qrpttbeta/channel/comment/AbstractCommentFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/comment/AbstractCommentFragment.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel.comment; import android.app.Activity; @@ -34,10 +17,6 @@ import com.terracom.qrpttbeta.R; import com.terracom.qrpttbeta.util.JumbleServiceProvider; -/** - * Fragment to change your comment using basic WYSIWYG tools. - * Created by andrew on 10/08/13. - */ public abstract class AbstractCommentFragment extends DialogFragment { private TabHost mTabHost; @@ -74,7 +53,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { mTabHost = (TabHost) view.findViewById(R.id.comment_tabhost); mTabHost.setup(); - if(mComment == null) { + if (mComment == null) { mCommentView.loadData("Loading...", null, null); try { requestComment(mProvider.getService()); @@ -99,11 +78,9 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() { @Override public void onTabChanged(String tabId) { - if("View".equals(tabId)) { - // When switching back to view tab, update with user's HTML changes. + if ("View".equals(tabId)) { mCommentView.loadData(mCommentEdit.getText().toString(), "text/html", "UTF-8"); - } else if("Edit".equals(tabId) && "".equals(mCommentEdit.getText().toString())) { - // Load edittext content for the first time when the tab is selected, to improve performance with long messages. + } else if ("Edit".equals(tabId) && "".equals(mCommentEdit.getText().toString())) { mCommentEdit.setText(mComment); } } @@ -130,7 +107,7 @@ public void onClick(DialogInterface dialog, int which) { } protected void loadComment(String comment) { - if(mCommentView == null) return; + if (mCommentView == null) return; mCommentView.loadData(comment, "text/html", "UTF-8"); mComment = comment; } @@ -139,17 +116,7 @@ public boolean isEditing() { return getArguments().getBoolean("editing"); } - /** - * Requests a comment from the service. Will not be called if we already have a comment provided. - * This method is expected to set a callback that will call {@link com.terracom.qrpttbeta.channel.comment.AbstractCommentFragment#loadComment(String comment)}. - * @param service The bound Jumble service to use for remote calls. - */ public abstract void requestComment(IJumbleService service) throws RemoteException; - /** - * Asks the service to replace the comment. - * @param service The bound Jumble service to use for remote calls. - * @param comment The comment the user has defined. - */ public abstract void editComment(IJumbleService service, String comment) throws RemoteException; } diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/comment/ChannelDescriptionFragment.java b/app/src/main/java/com/terracom/qrpttbeta/channel/comment/ChannelDescriptionFragment.java old mode 100644 new mode 100755 index 344aca42..94baa6ed --- a/app/src/main/java/com/terracom/qrpttbeta/channel/comment/ChannelDescriptionFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/comment/ChannelDescriptionFragment.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel.comment; import android.os.RemoteException; @@ -23,9 +6,6 @@ import com.terracom.jumble.model.Channel; import com.terracom.jumble.util.JumbleObserver; -/** - * Created by andrew on 03/03/14. - */ public class ChannelDescriptionFragment extends AbstractCommentFragment { @Override @@ -33,7 +13,7 @@ public void requestComment(final IJumbleService service) throws RemoteException service.registerObserver(new JumbleObserver() { @Override public void onChannelStateUpdated(Channel channel) throws RemoteException { - if(channel.getId() == getChannelId() && + if (channel.getId() == getChannelId() && channel.getDescription() != null) { loadComment(channel.getDescription()); service.unregisterObserver(this); @@ -45,7 +25,6 @@ public void onChannelStateUpdated(Channel channel) throws RemoteException { @Override public void editComment(IJumbleService service, String comment) throws RemoteException { - // TODO } private int getChannelId() { diff --git a/app/src/main/java/com/terracom/qrpttbeta/channel/comment/UserCommentFragment.java b/app/src/main/java/com/terracom/qrpttbeta/channel/comment/UserCommentFragment.java old mode 100644 new mode 100755 index 61e16db8..2629114b --- a/app/src/main/java/com/terracom/qrpttbeta/channel/comment/UserCommentFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/channel/comment/UserCommentFragment.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.channel.comment; import android.os.RemoteException; @@ -23,9 +6,6 @@ import com.terracom.jumble.model.User; import com.terracom.jumble.util.JumbleObserver; -/** - * Created by andrew on 03/03/14. - */ public class UserCommentFragment extends AbstractCommentFragment { @Override @@ -33,7 +13,7 @@ public void requestComment(final IJumbleService service) throws RemoteException service.registerObserver(new JumbleObserver() { @Override public void onUserStateUpdated(User user) throws RemoteException { - if(user.getSession() == getSession() && + if (user.getSession() == getSession() && user.getComment() != null) { loadComment(user.getComment()); service.unregisterObserver(this); diff --git a/app/src/main/java/com/terracom/qrpttbeta/db/DatabaseProvider.java b/app/src/main/java/com/terracom/qrpttbeta/db/DatabaseProvider.java old mode 100644 new mode 100755 index 102c50c4..f15ad310 --- a/app/src/main/java/com/terracom/qrpttbeta/db/DatabaseProvider.java +++ b/app/src/main/java/com/terracom/qrpttbeta/db/DatabaseProvider.java @@ -1,25 +1,5 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.db; -/** - * Created by andrew on 15/08/13. - */ public interface DatabaseProvider { public QRPushToTalkDatabase getDatabase(); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/db/PublicServer.java b/app/src/main/java/com/terracom/qrpttbeta/db/PublicServer.java old mode 100644 new mode 100755 index fde7bc32..963b4a35 --- a/app/src/main/java/com/terracom/qrpttbeta/db/PublicServer.java +++ b/app/src/main/java/com/terracom/qrpttbeta/db/PublicServer.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.db; @@ -22,44 +5,32 @@ public class PublicServer extends Server { - private String mCA; - private String mContinentCode; - private String mCountry; - private String mCountryCode; - private String mRegion; - private String mUrl; - - public PublicServer(String name, String ca, String continentCode, String country, String countryCode, String ip, Integer port, String region, String url) { - super(-1, name, ip, port, "", ""); - mCA = ca; - mContinentCode = continentCode; - mCountry = country; - mCountryCode = countryCode; - mRegion = region; - mUrl = url; - } - - public String getCA() { - return mCA; - } - - public String getContinentCode() { - return mContinentCode; - } - - public String getCountry() { - return mCountry; - } + private String mCA; + private String mContinentCode; + private String mCountry; + private String mCountryCode; + private String mRegion; + private String mUrl; - public String getCountryCode() { - return mCountryCode; - } - - public String getRegion() { - return mRegion; - } - - public String getUrl() { - return mUrl; - } + public PublicServer(String name, String ca, String continentCode, String country, String countryCode, String ip, Integer port, String region, String url) { + super(-1, name, ip, port, "", ""); + mCA = ca; + mContinentCode = continentCode; + mCountry = country; + mCountryCode = countryCode; + mRegion = region; + mUrl = url; + } + + public String getCountry() { + return mCountry; + } + + public String getCountryCode() { + return mCountryCode; + } + + public String getUrl() { + return mUrl; + } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/db/QRPushToTalkDatabase.java b/app/src/main/java/com/terracom/qrpttbeta/db/QRPushToTalkDatabase.java old mode 100644 new mode 100755 index be49365d..2d33141c --- a/app/src/main/java/com/terracom/qrpttbeta/db/QRPushToTalkDatabase.java +++ b/app/src/main/java/com/terracom/qrpttbeta/db/QRPushToTalkDatabase.java @@ -1,56 +1,35 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.db; import com.terracom.jumble.model.Server; import java.util.List; -/** - * An interface for persistent storage services (i.e. databases, cloud) to implement. - * Created by andrew on 13/08/13. - */ public interface QRPushToTalkDatabase { public void open(); + public void close(); public List getServers(); + public void addServer(Server server); + public void updateServer(Server server); - public void removeServer(Server server); - public boolean isCommentSeen(String hash, byte[] commentHash); - public void markCommentSeen(String hash, byte[] commentHash); + public void removeServer(Server server); public List getPinnedChannels(long serverId); - public void addPinnedChannel(long serverId, int channelId); - public void removePinnedChannel(long serverId, int channelId); - public boolean isChannelPinned(long serverId, int channelId); public List getAccessTokens(long serverId); - public void addAccessToken(long serverId, String token); - public void removeAccessToken(long serverId, String token); public List getLocalMutedUsers(long serverId); + public void addLocalMutedUser(long serverId, int userId); + public void removeLocalMutedUser(long serverId, int userId); public List getLocalIgnoredUsers(long serverId); + public void addLocalIgnoredUser(long serverId, int userId); + public void removeLocalIgnoredUser(long serverId, int userId); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/db/QRPushToTalkSQLiteDatabase.java b/app/src/main/java/com/terracom/qrpttbeta/db/QRPushToTalkSQLiteDatabase.java old mode 100644 new mode 100755 index 4318fd2f..d5a6cbf6 --- a/app/src/main/java/com/terracom/qrpttbeta/db/QRPushToTalkSQLiteDatabase.java +++ b/app/src/main/java/com/terracom/qrpttbeta/db/QRPushToTalkSQLiteDatabase.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.db; import android.content.ContentValues; @@ -83,7 +66,7 @@ public class QRPushToTalkSQLiteDatabase extends SQLiteOpenHelper implements QRPu public static final String LOCAL_MUTE_SERVER = "server"; public static final String LOCAL_MUTE_USER = "user"; public static final String TABLE_LOCAL_MUTE_CREATE_SQL = "CREATE TABLE IF NOT EXISTS " + TABLE_LOCAL_MUTE + " (" - + "`" + LOCAL_MUTE_SERVER +"` INTEGER NOT NULL," + + "`" + LOCAL_MUTE_SERVER + "` INTEGER NOT NULL," + "`" + LOCAL_MUTE_USER + "` INTEGER NOT NULL," + "CONSTRAINT server_user UNIQUE(" + LOCAL_MUTE_SERVER + "," + LOCAL_MUTE_USER + ")" + ");"; @@ -92,7 +75,7 @@ public class QRPushToTalkSQLiteDatabase extends SQLiteOpenHelper implements QRPu public static final String LOCAL_IGNORE_SERVER = "server"; public static final String LOCAL_IGNORE_USER = "user"; public static final String TABLE_LOCAL_IGNORE_CREATE_SQL = "CREATE TABLE IF NOT EXISTS " + TABLE_LOCAL_IGNORE + " (" - + "`" + LOCAL_IGNORE_SERVER +"` INTEGER NOT NULL," + + "`" + LOCAL_IGNORE_SERVER + "` INTEGER NOT NULL," + "`" + LOCAL_IGNORE_USER + "` INTEGER NOT NULL," + "CONSTRAINT server_user UNIQUE(" + LOCAL_IGNORE_SERVER + "," + LOCAL_IGNORE_USER + ")" + ");"; @@ -151,7 +134,6 @@ public void onUpgrade( @Override public void open() { - // Do nothing. Database will be opened automatically when accessing it. } @Override @@ -215,16 +197,15 @@ public void updateServer(Server server) { @Override public void removeServer(Server server) { getWritableDatabase().delete(TABLE_SERVER, SERVER_ID + "=?", - new String[] { String.valueOf(server.getId()) }); - // Clean up server-specific entries + new String[]{String.valueOf(server.getId())}); getWritableDatabase().delete(TABLE_FAVOURITES, FAVOURITES_SERVER + "=?", - new String[] { String.valueOf(server.getId()) }); + new String[]{String.valueOf(server.getId())}); getWritableDatabase().delete(TABLE_TOKENS, TOKENS_SERVER + "=?", - new String[] { String.valueOf(server.getId()) }); + new String[]{String.valueOf(server.getId())}); getWritableDatabase().delete(TABLE_LOCAL_MUTE, LOCAL_MUTE_SERVER + "=?", - new String[] { String.valueOf(server.getId()) }); + new String[]{String.valueOf(server.getId())}); getWritableDatabase().delete(TABLE_LOCAL_IGNORE, LOCAL_IGNORE_SERVER + "=?", - new String[] { String.valueOf(server.getId()) }); + new String[]{String.valueOf(server.getId())}); } public List getPinnedChannels(long serverId) { @@ -250,39 +231,12 @@ public List getPinnedChannels(long serverId) { return favourites; } - @Override - public void addPinnedChannel(long serverId, int channelId) { - ContentValues contentValues = new ContentValues(); - contentValues.put(FAVOURITES_CHANNEL, channelId); - contentValues.put(FAVOURITES_SERVER, serverId); - getWritableDatabase().insert(TABLE_FAVOURITES, null, contentValues); - } - - @Override - public boolean isChannelPinned(long serverId, int channelId) { - Cursor c = getReadableDatabase().query( - TABLE_FAVOURITES, - new String[]{FAVOURITES_CHANNEL}, - FAVOURITES_SERVER + "=? AND " + - FAVOURITES_CHANNEL + "=?", - new String[]{String.valueOf(serverId), String.valueOf(channelId)}, - null, - null, - null); - c.moveToFirst(); - return !c.isAfterLast(); - } - - public void removePinnedChannel(long serverId, int channelId) { - getWritableDatabase().delete(TABLE_FAVOURITES, "server = ? AND channel = ?", new String[] { Long.toString(serverId), Integer.toString(channelId)}); - } - @Override public List getAccessTokens(long serverId) { - Cursor cursor = getReadableDatabase().query(TABLE_TOKENS, new String[] { TOKENS_VALUE }, TOKENS_SERVER+"=?", new String[] { String.valueOf(serverId) }, null, null, null); + Cursor cursor = getReadableDatabase().query(TABLE_TOKENS, new String[]{TOKENS_VALUE}, TOKENS_SERVER + "=?", new String[]{String.valueOf(serverId)}, null, null, null); cursor.moveToFirst(); List tokens = new ArrayList(); - while(!cursor.isAfterLast()) { + while (!cursor.isAfterLast()) { tokens.add(cursor.getString(0)); cursor.moveToNext(); } @@ -290,25 +244,12 @@ public List getAccessTokens(long serverId) { return tokens; } - @Override - public void addAccessToken(long serverId, String token) { - ContentValues contentValues = new ContentValues(); - contentValues.put(TOKENS_SERVER, serverId); - contentValues.put(TOKENS_VALUE, token); - getWritableDatabase().insert(TABLE_TOKENS, null, contentValues); - } - - @Override - public void removeAccessToken(long serverId, String token) { - getWritableDatabase().delete(TABLE_TOKENS, TOKENS_SERVER+"=? AND "+TOKENS_VALUE+"=?", new String[] {String.valueOf(serverId), token }); - } - @Override public List getLocalMutedUsers(long serverId) { Cursor cursor = getReadableDatabase().query(TABLE_LOCAL_MUTE, - new String[] { LOCAL_MUTE_USER }, + new String[]{LOCAL_MUTE_USER}, LOCAL_MUTE_SERVER + "=?", - new String[] { String.valueOf(serverId) }, + new String[]{String.valueOf(serverId)}, null, null, null); cursor.moveToNext(); List users = new ArrayList(); @@ -331,15 +272,15 @@ public void addLocalMutedUser(long serverId, int userId) { public void removeLocalMutedUser(long serverId, int userId) { getWritableDatabase().delete(TABLE_LOCAL_MUTE, LOCAL_MUTE_SERVER + "=? AND " + LOCAL_MUTE_USER + "=?", - new String[] { String.valueOf(serverId), String.valueOf(userId) }); + new String[]{String.valueOf(serverId), String.valueOf(userId)}); } @Override public List getLocalIgnoredUsers(long serverId) { Cursor cursor = getReadableDatabase().query(TABLE_LOCAL_IGNORE, - new String[] { LOCAL_IGNORE_USER }, + new String[]{LOCAL_IGNORE_USER}, LOCAL_IGNORE_SERVER + "=?", - new String[] { String.valueOf(serverId) }, + new String[]{String.valueOf(serverId)}, null, null, null); cursor.moveToFirst(); List users = new ArrayList(); @@ -362,26 +303,6 @@ public void addLocalIgnoredUser(long serverId, int userId) { public void removeLocalIgnoredUser(long serverId, int userId) { getWritableDatabase().delete(TABLE_LOCAL_IGNORE, LOCAL_IGNORE_SERVER + "=? AND " + LOCAL_IGNORE_USER + "=?", - new String[] { String.valueOf(serverId), String.valueOf(userId) }); - } - - @Override - public boolean isCommentSeen(String hash, byte[] commentHash) { - Cursor cursor = getReadableDatabase().query(TABLE_COMMENTS, - new String[]{COMMENTS_WHO, COMMENTS_COMMENT, COMMENTS_SEEN}, COMMENTS_WHO + "=? AND " + COMMENTS_COMMENT + "=?", - new String[]{hash, new String(commentHash)}, - null, null, null); - boolean hasNext = cursor.moveToNext(); - cursor.close(); - return hasNext; - } - - @Override - public void markCommentSeen(String hash, byte[] commentHash) { - ContentValues values = new ContentValues(); - values.put(COMMENTS_WHO, hash); - values.put(COMMENTS_COMMENT, commentHash); - values.put(COMMENTS_SEEN, "datetime('now')"); - getWritableDatabase().replace(TABLE_COMMENTS, null, values); + new String[]{String.valueOf(serverId), String.valueOf(userId)}); } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/drawable/CircleDrawable.java b/app/src/main/java/com/terracom/qrpttbeta/drawable/CircleDrawable.java old mode 100644 new mode 100755 index e64231ff..8a5a91a4 --- a/app/src/main/java/com/terracom/qrpttbeta/drawable/CircleDrawable.java +++ b/app/src/main/java/com/terracom/qrpttbeta/drawable/CircleDrawable.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.drawable; import android.content.res.Resources; @@ -32,10 +15,6 @@ import com.terracom.qrpttbeta.R; -/** - * A drawable containing a circular bitmap in the style of @drawable/outline_circle_talking_off. - * Created by andrew on 19/10/14. - */ public class CircleDrawable extends Drawable { public static final int STROKE_WIDTH_DP = 1; private Resources mResources; @@ -89,9 +68,8 @@ protected void onBoundsChange(Rect bounds) { public void draw(Canvas canvas) { RectF imageRect = new RectF(getBounds()); RectF strokeRect = new RectF(getBounds()); - // Default stroke drawing is both inset and outset. - strokeRect.inset(mStrokePaint.getStrokeWidth()/2, - mStrokePaint.getStrokeWidth()/2); + strokeRect.inset(mStrokePaint.getStrokeWidth() / 2, + mStrokePaint.getStrokeWidth() / 2); canvas.drawOval(imageRect, mPaint); canvas.drawOval(strokeRect, mStrokePaint); diff --git a/app/src/main/java/com/terracom/qrpttbeta/drawable/FlipDrawable.java b/app/src/main/java/com/terracom/qrpttbeta/drawable/FlipDrawable.java old mode 100644 new mode 100755 index 00d2c361..a70d9e6d --- a/app/src/main/java/com/terracom/qrpttbeta/drawable/FlipDrawable.java +++ b/app/src/main/java/com/terracom/qrpttbeta/drawable/FlipDrawable.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.drawable; import android.animation.ValueAnimator; @@ -24,10 +7,6 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; -/** - * A transition drawable that shows a "flip" between two different images. - * Created by andrew on 19/10/14. - */ @TargetApi(11) public class FlipDrawable extends LayerDrawable implements ValueAnimator.AnimatorUpdateListener { private Drawable mFrom; @@ -36,7 +15,7 @@ public class FlipDrawable extends LayerDrawable implements ValueAnimator.Animato private float mRotate; public FlipDrawable(Drawable from, Drawable to) { - super(new Drawable[] { from, to }); + super(new Drawable[]{from, to}); mFrom = from; mTo = to; mCamera = new Camera(); @@ -45,8 +24,8 @@ public FlipDrawable(Drawable from, Drawable to) { @Override public void draw(Canvas canvas) { - float centerX = getIntrinsicWidth()/2; - float centerY = getIntrinsicHeight()/2; + float centerX = getIntrinsicWidth() / 2; + float centerY = getIntrinsicHeight() / 2; boolean flipped = mRotate > 90; mCamera.save(); mCamera.translate(centerX, centerY, 0); @@ -71,10 +50,6 @@ public Drawable getCurrent() { return mRotate > 90 ? mTo : mFrom; } - /** - * Starts the flip animation. - * @param duration The duration in ms for the flip to occur. - */ public void start(long duration) { ValueAnimator animator = ValueAnimator.ofFloat(0, 180); animator.setDuration(duration); diff --git a/app/src/main/java/com/terracom/qrpttbeta/preference/KeySelectDialogPreference.java b/app/src/main/java/com/terracom/qrpttbeta/preference/KeySelectDialogPreference.java old mode 100644 new mode 100755 index 80871de3..9cdb1644 --- a/app/src/main/java/com/terracom/qrpttbeta/preference/KeySelectDialogPreference.java +++ b/app/src/main/java/com/terracom/qrpttbeta/preference/KeySelectDialogPreference.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.preference; import android.annotation.TargetApi; @@ -36,110 +19,108 @@ import com.terracom.qrpttbeta.R; public class KeySelectDialogPreference extends DialogPreference implements OnKeyListener { - - //private static final String ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"; - - private TextView valueTextView; - private int keyCode; - - public KeySelectDialogPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onPrepareDialogBuilder(Builder builder) { - super.onPrepareDialogBuilder(builder); - - builder.setOnKeyListener(this); - builder.setNeutralButton(R.string.reset_key, new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - keyCode = 0; - valueTextView.setText("No Key"); - persistInt(keyCode); // Neutral is a 'negative' response to android, we save manually here. - } - }); - } - - @Override - protected View onCreateDialogView() { - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - LinearLayout layout = new LinearLayout(getContext()); - layout.setOrientation(LinearLayout.VERTICAL); - layout.setPadding(6,6,6,6); - - TextView promptTextView = new TextView(getContext()); - promptTextView.setText(R.string.pressKey); - promptTextView.setGravity(Gravity.CENTER_HORIZONTAL); - - valueTextView = new TextView(getContext()); - valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 22); - valueTextView.setGravity(Gravity.CENTER_HORIZONTAL); - valueTextView.setPadding(0, 12, 0, 12); - - TextView alertTextView = new TextView(getContext()); - alertTextView.setText(R.string.pressKeyInfo); - alertTextView.setGravity(Gravity.CENTER_HORIZONTAL); - alertTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); - - layout.addView(promptTextView, params); - layout.addView(valueTextView, params); - layout.addView(alertTextView); - - return layout; - } - - @Override - protected void onSetInitialValue(boolean restorePersistedValue, - Object defaultValue) { - super.onSetInitialValue(restorePersistedValue, defaultValue); - if(restorePersistedValue) { - keyCode = getPersistedInt(0); - } else { - keyCode = (Integer)defaultValue; - } - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - if(positiveResult) { - persistInt(keyCode); - } - - super.onDialogClosed(positiveResult); - } - - @TargetApi(12) - @Override - protected void onBindDialogView(View view) { - super.onBindDialogView(view); - if(keyCode == 0) { - valueTextView.setText("No Key"); - } else { - if(android.os.Build.VERSION.SDK_INT >= 12) { - valueTextView.setText(KeyEvent.keyCodeToString(keyCode)); - } else { - valueTextView.setText("Key code: "+keyCode); - } - } - } - - @TargetApi(12) - @Override - public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { - if(keyCode != KeyEvent.KEYCODE_BACK) { - this.keyCode = keyCode; - - if(android.os.Build.VERSION.SDK_INT >= 12) { - valueTextView.setText(KeyEvent.keyCodeToString(keyCode)); - } else { - valueTextView.setText("Key code: "+keyCode); - } - } else { - dialog.dismiss(); - } - return true; - } + + private TextView valueTextView; + private int keyCode; + + public KeySelectDialogPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onPrepareDialogBuilder(Builder builder) { + super.onPrepareDialogBuilder(builder); + + builder.setOnKeyListener(this); + builder.setNeutralButton(R.string.reset_key, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + keyCode = 0; + valueTextView.setText("No Key"); + persistInt(keyCode); + } + }); + } + + @Override + protected View onCreateDialogView() { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + LinearLayout layout = new LinearLayout(getContext()); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setPadding(6, 6, 6, 6); + + TextView promptTextView = new TextView(getContext()); + promptTextView.setText(R.string.pressKey); + promptTextView.setGravity(Gravity.CENTER_HORIZONTAL); + + valueTextView = new TextView(getContext()); + valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 22); + valueTextView.setGravity(Gravity.CENTER_HORIZONTAL); + valueTextView.setPadding(0, 12, 0, 12); + + TextView alertTextView = new TextView(getContext()); + alertTextView.setText(R.string.pressKeyInfo); + alertTextView.setGravity(Gravity.CENTER_HORIZONTAL); + alertTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); + + layout.addView(promptTextView, params); + layout.addView(valueTextView, params); + layout.addView(alertTextView); + + return layout; + } + + @Override + protected void onSetInitialValue(boolean restorePersistedValue, + Object defaultValue) { + super.onSetInitialValue(restorePersistedValue, defaultValue); + if (restorePersistedValue) { + keyCode = getPersistedInt(0); + } else { + keyCode = (Integer) defaultValue; + } + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + if (positiveResult) { + persistInt(keyCode); + } + + super.onDialogClosed(positiveResult); + } + + @TargetApi(12) + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + if (keyCode == 0) { + valueTextView.setText("No Key"); + } else { + if (android.os.Build.VERSION.SDK_INT >= 12) { + valueTextView.setText(KeyEvent.keyCodeToString(keyCode)); + } else { + valueTextView.setText("Key code: " + keyCode); + } + } + } + + @TargetApi(12) + @Override + public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { + if (keyCode != KeyEvent.KEYCODE_BACK) { + this.keyCode = keyCode; + + if (android.os.Build.VERSION.SDK_INT >= 12) { + valueTextView.setText(KeyEvent.keyCodeToString(keyCode)); + } else { + valueTextView.setText("Key code: " + keyCode); + } + } else { + dialog.dismiss(); + } + return true; + } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/preference/Preferences.java b/app/src/main/java/com/terracom/qrpttbeta/preference/Preferences.java old mode 100644 new mode 100755 index 2ab5d8e7..c6f2741f --- a/app/src/main/java/com/terracom/qrpttbeta/preference/Preferences.java +++ b/app/src/main/java/com/terracom/qrpttbeta/preference/Preferences.java @@ -1,27 +1,9 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.preference; import android.annotation.TargetApi; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; -import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -38,14 +20,11 @@ import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; import android.text.InputType; -import android.util.Log; import android.widget.EditText; import android.widget.Toast; import com.terracom.qrpttbeta.R; import com.terracom.qrpttbeta.Settings; -import com.terracom.qrpttbeta.app.DrawerAdapter; -import com.terracom.qrpttbeta.app.QRPushToTalkActivity; import com.terracom.qrpttbeta.util.QRPushToTalkTrustStore; import java.io.File; @@ -56,10 +35,6 @@ import info.guardianproject.onionkit.ui.OrbotHelper; -/** - * This entire class is a mess. - * FIXME. Please. - */ public class Preferences extends PreferenceActivity { public static final String ACTION_PREFS_GENERAL = "com.terracom.qrpttbeta.app.PREFS_GENERAL"; @@ -78,8 +53,6 @@ public class Preferences extends PreferenceActivity { protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // Legacy preference section handling - String action = getIntent().getAction(); if (action != null) { if (ACTION_PREFS_GENERAL.equals(action)) { @@ -128,20 +101,16 @@ public boolean onPreferenceClick(Preference preference) { certificatePathPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { - // Unset password SharedPreferences preferences = preference.getSharedPreferences(); preferences.edit() .putString(Settings.PREF_CERT_PASSWORD, "") .commit(); - if("".equals(newValue)) return true; // No certificate - File cert = new File((String)newValue); + if ("".equals(newValue)) return true; + File cert = new File((String) newValue); try { boolean needsPassword = QRPushToTalkCertificateManager.isPasswordRequired(cert); - if(!needsPassword) return true; - - // If we need a password, prompt the user. Do NOT change the preference until - // the password has been provided. + if (!needsPassword) return true; promptCertificatePassword(preference.getContext(), (ListPreference) preference, cert); } catch (Exception e) { @@ -160,7 +129,6 @@ public boolean onPreferenceClick(Preference preference) { } }); - // Make sure media is mounted, otherwise do not allow certificate loading. if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { try { updateCertificatePath(certificatePathPreference); @@ -174,10 +142,6 @@ public boolean onPreferenceClick(Preference preference) { } } - /** - * Prompts the user for the given certificate's password, setting the certificate as - * active if the password is correct. - */ private static void promptCertificatePassword(final Context context, final ListPreference certificatePreference, final File certificate) { AlertDialog.Builder adb = new AlertDialog.Builder(context); adb.setTitle(R.string.certificatePassword); @@ -200,7 +164,7 @@ public void onClick(DialogInterface dialog, int which) { } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } finally { - if(passwordValid) { + if (passwordValid) { certificatePreference.setValue(certificate.getAbsolutePath()); certificatePreference.getSharedPreferences().edit() .putString(Settings.PREF_CERT_PASSWORD, password) @@ -232,13 +196,12 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { } }); - // Scan each bitrate and determine if the device supports it ListPreference inputQualityPreference = (ListPreference) screen.findPreference(Settings.PREF_INPUT_RATE); String[] bitrateNames = new String[inputQualityPreference.getEntryValues().length]; - for(int x=0;x 0; - bitrateNames[x] = bitrate+"Hz" + (supported ? "" : " (unsupported)"); + bitrateNames[x] = bitrate + "Hz" + (supported ? "" : " (unsupported)"); } inputQualityPreference.setEntries(bitrateNames); @@ -248,21 +211,13 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { private static void updateAudioDependents(PreferenceScreen screen, String inputMethod) { PreferenceCategory pttCategory = (PreferenceCategory) screen.findPreference("ptt_settings"); PreferenceCategory vadCategory = (PreferenceCategory) screen.findPreference("vad_settings"); -// pttCategory.setEnabled(Settings.ARRAY_INPUT_METHOD_PTT.equals(inputMethod)); pttCategory.setEnabled(true); -// vadCategory.setEnabled(Settings.ARRAY_INPUT_METHOD_VOICE.equals(inputMethod)); vadCategory.setEnabled(false); } - /** - * Updates the passed preference with the certificate paths found on external storage. - * - * @param preference The ListPreference to update. - */ private static void updateCertificatePath(ListPreference preference) throws NullPointerException, IOException { List certificateFiles = QRPushToTalkCertificateManager.getAvailableCertificates(); - // Get arrays of certificate paths and names. String[] certificateNames = new String[certificateFiles.size() + 1]; // Extra space for 'None' option String[] certificatePaths = new String[certificateFiles.size() + 1]; for (int x = 0; x < certificateFiles.size(); x++) { @@ -277,11 +232,6 @@ private static void updateCertificatePath(ListPreference preference) throws Null preference.setEntryValues(certificatePaths); } - /** - * Generates a new certificate and sets it as active. - * - * @param certificateList If passed, will update the list of certificates available. Messy. - */ private static void generateCertificate(final ListPreference certificateList) { QRPushToTalkCertificateGenerateTask generateTask = new QRPushToTalkCertificateGenerateTask(certificateList.getContext()) { @Override @@ -290,7 +240,7 @@ protected void onPostExecute(File result) { if (result != null) { try { - updateCertificatePath(certificateList); // Update cert path after + updateCertificatePath(certificateList); certificateList.setValue(result.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); diff --git a/app/src/main/java/com/terracom/qrpttbeta/preference/QRPushToTalkCertificateGenerateTask.java b/app/src/main/java/com/terracom/qrpttbeta/preference/QRPushToTalkCertificateGenerateTask.java old mode 100644 new mode 100755 index a049f08a..0abe8914 --- a/app/src/main/java/com/terracom/qrpttbeta/preference/QRPushToTalkCertificateGenerateTask.java +++ b/app/src/main/java/com/terracom/qrpttbeta/preference/QRPushToTalkCertificateGenerateTask.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.preference; import android.app.ProgressDialog; @@ -29,50 +12,51 @@ import java.io.File; public class QRPushToTalkCertificateGenerateTask extends AsyncTask { - - private Context context; - private ProgressDialog loadingDialog; - - public QRPushToTalkCertificateGenerateTask(Context context) { - this.context = context; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - - loadingDialog = new ProgressDialog(context); - loadingDialog.setIndeterminate(true); - loadingDialog.setMessage(context.getString(R.string.generateCertProgress)); - loadingDialog.setOnCancelListener(new OnCancelListener() { - - @Override - public void onCancel(DialogInterface arg0) { - cancel(true); - - } - }); - loadingDialog.show(); - } - @Override - protected File doInBackground(Void... params) { - try { - return QRPushToTalkCertificateManager.generateCertificate(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override - protected void onPostExecute(File result) { - super.onPostExecute(result); - if(result != null) { - Toast.makeText(context, context.getString(R.string.generateCertSuccess, result.getName()), Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(context, R.string.generateCertFailure, Toast.LENGTH_SHORT).show(); - } - - loadingDialog.dismiss(); - } + + private Context context; + private ProgressDialog loadingDialog; + + public QRPushToTalkCertificateGenerateTask(Context context) { + this.context = context; + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + + loadingDialog = new ProgressDialog(context); + loadingDialog.setIndeterminate(true); + loadingDialog.setMessage(context.getString(R.string.generateCertProgress)); + loadingDialog.setOnCancelListener(new OnCancelListener() { + + @Override + public void onCancel(DialogInterface arg0) { + cancel(true); + + } + }); + loadingDialog.show(); + } + + @Override + protected File doInBackground(Void... params) { + try { + return QRPushToTalkCertificateManager.generateCertificate(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + @Override + protected void onPostExecute(File result) { + super.onPostExecute(result); + if (result != null) { + Toast.makeText(context, context.getString(R.string.generateCertSuccess, result.getName()), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(context, R.string.generateCertFailure, Toast.LENGTH_SHORT).show(); + } + + loadingDialog.dismiss(); + } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/preference/QRPushToTalkCertificateManager.java b/app/src/main/java/com/terracom/qrpttbeta/preference/QRPushToTalkCertificateManager.java old mode 100644 new mode 100755 index 38817d42..341988fc --- a/app/src/main/java/com/terracom/qrpttbeta/preference/QRPushToTalkCertificateManager.java +++ b/app/src/main/java/com/terracom/qrpttbeta/preference/QRPushToTalkCertificateManager.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.preference; import android.os.Environment; @@ -41,15 +24,10 @@ public class QRPushToTalkCertificateManager { - private static final String CERTIFICATE_FOLDER = "QRPushToTalk"; - private static final String CERTIFICATE_FORMAT = "qrptt-%s.p12"; + private static final String CERTIFICATE_FOLDER = "QRPushToTalk"; + private static final String CERTIFICATE_FORMAT = "qrptt-%s.p12"; private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); - - /** - * Generates a new X.509 passwordless certificate in PKCS12 format for connection to a Mumble server. - * This certificate is stored in the {@value #CERTIFICATE_FOLDER} folder on the external storage, in the format {@value #CERTIFICATE_FORMAT} where the timestamp is substituted in. - * @return The path of the generated certificate if the operation was a success. Otherwise, null. - */ + public static File generateCertificate() throws NoSuchAlgorithmException, OperatorCreationException, CertificateException, KeyStoreException, NoSuchProviderException, IOException { File certificateDirectory = getCertificateDirectory(); @@ -61,29 +39,20 @@ public static File generateCertificate() throws NoSuchAlgorithmException, Operat return certificateFile; } - /** - * Returns a list of certificates in the {@value #CERTIFICATE_FOLDER} folder on external storage, ending with pfx or p12. - * @return A list of {@link File} objects containing certificates. - */ - public static List getAvailableCertificates() throws IOException { - File certificateDirectory = getCertificateDirectory(); - - File[] p12Files = certificateDirectory.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.getName().endsWith("pfx") || - pathname.getName().endsWith("p12"); - } - }); - - return Arrays.asList(p12Files); - } + public static List getAvailableCertificates() throws IOException { + File certificateDirectory = getCertificateDirectory(); + + File[] p12Files = certificateDirectory.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.getName().endsWith("pfx") || + pathname.getName().endsWith("p12"); + } + }); + + return Arrays.asList(p12Files); + } - /** - * Checks to see if the certificate at the given path is password protected. - * @param certificateFile A PKCS12 certificate. - * @return true if the certificate is password protected, false otherwise. - */ public static boolean isPasswordRequired(File certificateFile) throws KeyStoreException, IOException, NoSuchAlgorithmException { KeyStore p12store = KeyStore.getInstance("PKCS12"); FileInputStream inputStream = new FileInputStream(certificateFile); @@ -99,12 +68,6 @@ public static boolean isPasswordRequired(File certificateFile) throws KeyStoreEx } } - /** - * Checks to see if the certificate at the given path is password protected. - * @param certificateFile A PKCS12 certificate. - * @param password A password for the certificate. - * @return true if the password is valid, false otherwise. - */ public static boolean isPasswordValid(File certificateFile, String password) throws KeyStoreException, IOException, NoSuchAlgorithmException { KeyStore p12store = KeyStore.getInstance("PKCS12"); FileInputStream inputStream = new FileInputStream(certificateFile); @@ -117,19 +80,14 @@ public static boolean isPasswordValid(File certificateFile, String password) thr } } - /** - * Returns the certificate directory, {@value #PLUMBLE_CERTIFICATE_FOLDER}, on external storage. - * Will create if does not exist, and throw an assert if the external storage is not mounted. - * @return The {@link File} object of the directory. - */ - public static File getCertificateDirectory() throws IOException { - if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + public static File getCertificateDirectory() throws IOException { + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { File certificateDirectory = new File(Environment.getExternalStorageDirectory(), CERTIFICATE_FOLDER); - if(!certificateDirectory.exists()) + if (!certificateDirectory.exists()) certificateDirectory.mkdir(); return certificateDirectory; } else { throw new IOException("External storage not available."); } - } + } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/preference/SeekBarDialogPreference.java b/app/src/main/java/com/terracom/qrpttbeta/preference/SeekBarDialogPreference.java old mode 100644 new mode 100755 index d075651a..5f4af8a3 --- a/app/src/main/java/com/terracom/qrpttbeta/preference/SeekBarDialogPreference.java +++ b/app/src/main/java/com/terracom/qrpttbeta/preference/SeekBarDialogPreference.java @@ -1,28 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* The following code was written by Matthew Wiggins - * and is released under the Apache 2.0 license - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * I added some extra functionality like a multiplier + better persistence. - * - Andrew Comminos - */ package com.terracom.qrpttbeta.preference; import android.content.Context; @@ -115,9 +90,6 @@ public void onStartTrackingTouch(SeekBar seek) { public void onStopTrackingTouch(SeekBar seek) { } - /* (non-Javadoc) - * @see android.preference.DialogPreference#onDialogClosed(boolean) - */ @Override protected void onDialogClosed(boolean positiveResult) { super.onDialogClosed(positiveResult); diff --git a/app/src/main/java/com/terracom/qrpttbeta/servers/FavouriteServerAdapter.java b/app/src/main/java/com/terracom/qrpttbeta/servers/FavouriteServerAdapter.java old mode 100644 new mode 100755 index b7716713..1a36b0f0 --- a/app/src/main/java/com/terracom/qrpttbeta/servers/FavouriteServerAdapter.java +++ b/app/src/main/java/com/terracom/qrpttbeta/servers/FavouriteServerAdapter.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.servers; import android.content.Context; @@ -22,7 +5,6 @@ import com.terracom.jumble.model.Server; import com.terracom.qrpttbeta.R; -import com.terracom.qrpttbeta.app.QRPushToTalkActivity; import java.util.List; @@ -50,9 +32,6 @@ public boolean onPopupItemClick(Server server, MenuItem menuItem) { case R.id.menu_server_edit: mListener.editServer(server); return true; - /*case R.id.menu_server_share: - mListener.shareServer(server); - return true;*/ case R.id.menu_server_delete: mListener.deleteServer(server); return true; @@ -63,7 +42,7 @@ public boolean onPopupItemClick(Server server, MenuItem menuItem) { public static interface FavouriteServerAdapterMenuListener { public void editServer(Server server); - public void shareServer(Server server); + public void deleteServer(Server server); } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/servers/FavouriteServerListFragment.java b/app/src/main/java/com/terracom/qrpttbeta/servers/FavouriteServerListFragment.java old mode 100644 new mode 100755 index 7c3d14c2..b3ad6368 --- a/app/src/main/java/com/terracom/qrpttbeta/servers/FavouriteServerListFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/servers/FavouriteServerListFragment.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.servers; import android.app.Activity; @@ -40,11 +23,6 @@ import java.util.List; -/** - * Displays a list of servers, and allows the user to connect and edit them. - * @author terracom - * - */ public class FavouriteServerListFragment extends Fragment implements OnItemClickListener, FavouriteServerAdapter.FavouriteServerAdapterMenuListener { private ServerConnectHandler mConnectHandler; @@ -64,10 +42,10 @@ public void onAttach(Activity activity) { super.onAttach(activity); try { - mConnectHandler = (ServerConnectHandler)activity; + mConnectHandler = (ServerConnectHandler) activity; mDatabaseProvider = (DatabaseProvider) activity; } catch (ClassCastException e) { - throw new ClassCastException(activity.toString()+" must implement ServerConnectHandler!"); + throw new ClassCastException(activity.toString() + " must implement ServerConnectHandler!"); } } @@ -78,17 +56,6 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, mServerGrid = (GridView) view.findViewById(R.id.server_list_grid); mServerGrid.setOnItemClickListener(this); mServerGrid.setEmptyView(view.findViewById(R.id.server_list_grid_empty)); - - /*TextView donateText = (TextView) view.findViewById(R.id.donate_box); - donateText.setVisibility(BuildConfig.DONATE_NAG ? View.VISIBLE : View.GONE); - donateText.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - Intent playIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.terracom.qrpttbeta")); - startActivity(playIntent); - } - });*/ - registerForContextMenu(mServerGrid); return view; } @@ -107,7 +74,7 @@ public void onResume() { @Override public boolean onOptionsItemSelected(MenuItem item) { - if(item.getItemId() == R.id.menu_add_server_item) { + if (item.getItemId() == R.id.menu_add_server_item) { addServer(); return true; } @@ -128,21 +95,10 @@ public void editServer(Server server) { setEditedUsernameFlag(true); } - public static void setEditedUsernameFlag(boolean myflag){ + public static void setEditedUsernameFlag(boolean myflag) { myEditedflag = myflag; } - public void shareServer(Server server) { - // Build Mumble server URL - String serverUrl = "mumble://"+server.getHost()+":"+server.getPort()+"/"; - - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.shareMessage, serverUrl)); - intent.setType("text/plain"); - startActivity(intent); - } - public void deleteServer(final Server server) { AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); alertBuilder.setMessage(R.string.confirm_delete_server); @@ -163,8 +119,6 @@ public void updateServers() { mServerGrid.setAdapter(mServerAdapter); } - - public List getServers() { List servers = mDatabaseProvider.getDatabase().getServers(); return servers; @@ -177,6 +131,7 @@ public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { public static interface ServerConnectHandler { public void connectToServer(Server server); + public void connectToPublicServer(PublicServer server); } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/servers/HttpRequest.java b/app/src/main/java/com/terracom/qrpttbeta/servers/HttpRequest.java old mode 100644 new mode 100755 index 012a3ef6..71979026 --- a/app/src/main/java/com/terracom/qrpttbeta/servers/HttpRequest.java +++ b/app/src/main/java/com/terracom/qrpttbeta/servers/HttpRequest.java @@ -1,54 +1,18 @@ -/* - * Copyright (c) 2014 Kevin Sawicki - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ package com.terracom.qrpttbeta.servers; import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; -import static java.net.HttpURLConnection.HTTP_CREATED; -import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR; -import static java.net.HttpURLConnection.HTTP_NO_CONTENT; -import static java.net.HttpURLConnection.HTTP_NOT_FOUND; -import static java.net.HttpURLConnection.HTTP_NOT_MODIFIED; -import static java.net.HttpURLConnection.HTTP_OK; import static java.net.Proxy.Type.HTTP; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; -import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.Flushable; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintStream; import java.io.Reader; -import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.HttpURLConnection; import java.net.InetSocketAddress; @@ -57,27 +21,20 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.net.URLEncoder; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; -import java.security.AccessController; import java.security.GeneralSecurityException; -import java.security.PrivilegedAction; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Callable; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; import java.util.zip.GZIPInputStream; import javax.net.ssl.HostnameVerifier; @@ -88,3172 +45,627 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; -/** - * A fluid interface for making HTTP requests using an underlying - * {@link java.net.HttpURLConnection} (or sub-class). - *

- * Each instance supports making a single request and cannot be reused for - * further requests. - */ public class HttpRequest { - /** - * 'UTF-8' charset name - */ - public static final String CHARSET_UTF8 = "UTF-8"; - - /** - * 'application/x-www-form-urlencoded' content type header value - */ - public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded"; - - /** - * 'application/json' content type header value - */ - public static final String CONTENT_TYPE_JSON = "application/json"; - - /** - * 'gzip' encoding header value - */ - public static final String ENCODING_GZIP = "gzip"; - - /** - * 'Accept' header name - */ - public static final String HEADER_ACCEPT = "Accept"; - - /** - * 'Accept-Charset' header name - */ - public static final String HEADER_ACCEPT_CHARSET = "Accept-Charset"; - - /** - * 'Accept-Encoding' header name - */ - public static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"; - - /** - * 'Authorization' header name - */ - public static final String HEADER_AUTHORIZATION = "Authorization"; - - /** - * 'Cache-Control' header name - */ - public static final String HEADER_CACHE_CONTROL = "Cache-Control"; - - /** - * 'Content-Encoding' header name - */ - public static final String HEADER_CONTENT_ENCODING = "Content-Encoding"; - - /** - * 'Content-Length' header name - */ - public static final String HEADER_CONTENT_LENGTH = "Content-Length"; - - /** - * 'Content-Type' header name - */ - public static final String HEADER_CONTENT_TYPE = "Content-Type"; - - /** - * 'Date' header name - */ - public static final String HEADER_DATE = "Date"; - - /** - * 'ETag' header name - */ - public static final String HEADER_ETAG = "ETag"; - - /** - * 'Expires' header name - */ - public static final String HEADER_EXPIRES = "Expires"; - - /** - * 'If-None-Match' header name - */ - public static final String HEADER_IF_NONE_MATCH = "If-None-Match"; - - /** - * 'Last-Modified' header name - */ - public static final String HEADER_LAST_MODIFIED = "Last-Modified"; - - /** - * 'Location' header name - */ - public static final String HEADER_LOCATION = "Location"; - - /** - * 'Proxy-Authorization' header name - */ - public static final String HEADER_PROXY_AUTHORIZATION = "Proxy-Authorization"; - - /** - * 'Referer' header name - */ - public static final String HEADER_REFERER = "Referer"; - - /** - * 'Server' header name - */ - public static final String HEADER_SERVER = "Server"; - - /** - * 'User-Agent' header name - */ - public static final String HEADER_USER_AGENT = "User-Agent"; - - /** - * 'DELETE' request method - */ - public static final String METHOD_DELETE = "DELETE"; - - /** - * 'GET' request method - */ - public static final String METHOD_GET = "GET"; - - /** - * 'HEAD' request method - */ - public static final String METHOD_HEAD = "HEAD"; - - /** - * 'OPTIONS' options method - */ - public static final String METHOD_OPTIONS = "OPTIONS"; - - /** - * 'POST' request method - */ - public static final String METHOD_POST = "POST"; - - /** - * 'PUT' request method - */ - public static final String METHOD_PUT = "PUT"; - - /** - * 'TRACE' request method - */ - public static final String METHOD_TRACE = "TRACE"; - - /** - * 'charset' header value parameter - */ - public static final String PARAM_CHARSET = "charset"; - - private static final String BOUNDARY = "00content0boundary00"; - - private static final String CONTENT_TYPE_MULTIPART = "multipart/form-data; boundary=" - + BOUNDARY; - - private static final String CRLF = "\r\n"; - - private static final String[] EMPTY_STRINGS = new String[0]; - - private static SSLSocketFactory TRUSTED_FACTORY; - - private static HostnameVerifier TRUSTED_VERIFIER; - - private static String getValidCharset(final String charset) { - if (charset != null && charset.length() > 0) - return charset; - else - return CHARSET_UTF8; - } - - private static SSLSocketFactory getTrustedFactory() - throws HttpRequestException { - if (TRUSTED_FACTORY == null) { - final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { - - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; + public static final String CHARSET_UTF8 = "UTF-8"; + public static final String ENCODING_GZIP = "gzip"; + public static final String HEADER_CONTENT_ENCODING = "Content-Encoding"; + public static final String HEADER_CONTENT_LENGTH = "Content-Length"; + public static final String HEADER_CONTENT_TYPE = "Content-Type"; + public static final String HEADER_SERVER = "Server"; + public static final String METHOD_DELETE = "DELETE"; + public static final String METHOD_GET = "GET"; + public static final String PARAM_CHARSET = "charset"; + private static SSLSocketFactory TRUSTED_FACTORY; + private static HostnameVerifier TRUSTED_VERIFIER; + + private static String getValidCharset(final String charset) { + if (charset != null && charset.length() > 0) + return charset; + else + return CHARSET_UTF8; + } + + private static SSLSocketFactory getTrustedFactory() + throws HttpRequestException { + if (TRUSTED_FACTORY == null) { + final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { + + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + public void checkClientTrusted(X509Certificate[] chain, String authType) { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) { + } + }}; + try { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, trustAllCerts, new SecureRandom()); + TRUSTED_FACTORY = context.getSocketFactory(); + } catch (GeneralSecurityException e) { + IOException ioException = new IOException( + "Security exception configuring SSL context"); + ioException.initCause(e); + throw new HttpRequestException(ioException); + } } + return TRUSTED_FACTORY; + } + + private static HostnameVerifier getTrustedVerifier() { + if (TRUSTED_VERIFIER == null) + TRUSTED_VERIFIER = new HostnameVerifier() { + + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + return TRUSTED_VERIFIER; + } + + private static StringBuilder addPathSeparator(final String baseUrl, + final StringBuilder result) { + if (baseUrl.indexOf(':') + 2 == baseUrl.lastIndexOf('/')) + result.append('/'); + return result; + } + + private static StringBuilder addParamPrefix(final String baseUrl, + final StringBuilder result) { + final int queryStart = baseUrl.indexOf('?'); + final int lastChar = result.length() - 1; + if (queryStart == -1) + result.append('?'); + else if (queryStart < lastChar && baseUrl.charAt(lastChar) != '&') + result.append('&'); + return result; + } + + private static StringBuilder addParam(final Object key, Object value, + final StringBuilder result) { + if (value != null && value.getClass().isArray()) + value = arrayToList(value); + if (value instanceof Iterable) { + Iterator iterator = ((Iterable) value).iterator(); + while (iterator.hasNext()) { + result.append(key); + result.append("[]="); + Object element = iterator.next(); + if (element != null) + result.append(element); + if (iterator.hasNext()) + result.append("&"); + } + } else { + result.append(key); + result.append("="); + if (value != null) + result.append(value); + } + return result; + } + + public interface ConnectionFactory { + HttpURLConnection create(URL url) throws IOException; + + ConnectionFactory DEFAULT = new ConnectionFactory() { + public HttpURLConnection create(URL url) throws IOException { + return (HttpURLConnection) url.openConnection(); + } + }; + } + + private static ConnectionFactory CONNECTION_FACTORY = ConnectionFactory.DEFAULT; + + public interface UploadProgress { + void onUpload(long uploaded, long total); + + UploadProgress DEFAULT = new UploadProgress() { + public void onUpload(long uploaded, long total) { + } + }; + } + + public static class Base64 { + private Base64() { + } + } + + public static class HttpRequestException extends RuntimeException { + + private static final long serialVersionUID = -1170466989781746231L; - public void checkClientTrusted(X509Certificate[] chain, String authType) { - // Intentionally left blank + public HttpRequestException(final IOException cause) { + super(cause); } - public void checkServerTrusted(X509Certificate[] chain, String authType) { - // Intentionally left blank + @Override + public IOException getCause() { + return (IOException) super.getCause(); } - } }; - try { - SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, trustAllCerts, new SecureRandom()); - TRUSTED_FACTORY = context.getSocketFactory(); - } catch (GeneralSecurityException e) { - IOException ioException = new IOException( - "Security exception configuring SSL context"); - ioException.initCause(e); - throw new HttpRequestException(ioException); - } } - return TRUSTED_FACTORY; - } + protected static abstract class Operation implements Callable { + protected abstract V run() throws HttpRequestException, IOException; + + protected abstract void done() throws IOException; + + public V call() throws HttpRequestException { + boolean thrown = false; + try { + return run(); + } catch (HttpRequestException e) { + thrown = true; + throw e; + } catch (IOException e) { + thrown = true; + throw new HttpRequestException(e); + } finally { + try { + done(); + } catch (IOException e) { + if (!thrown) + throw new HttpRequestException(e); + } + } + } + } - private static HostnameVerifier getTrustedVerifier() { - if (TRUSTED_VERIFIER == null) - TRUSTED_VERIFIER = new HostnameVerifier() { + protected static abstract class CloseOperation extends Operation { - public boolean verify(String hostname, SSLSession session) { - return true; + private final Closeable closeable; + private final boolean ignoreCloseExceptions; + + protected CloseOperation(final Closeable closeable, + final boolean ignoreCloseExceptions) { + this.closeable = closeable; + this.ignoreCloseExceptions = ignoreCloseExceptions; + } + + @Override + protected void done() throws IOException { + if (closeable instanceof Flushable) + ((Flushable) closeable).flush(); + if (ignoreCloseExceptions) + try { + closeable.close(); + } catch (IOException e) { + } + else + closeable.close(); } - }; - - return TRUSTED_VERIFIER; - } - - private static StringBuilder addPathSeparator(final String baseUrl, - final StringBuilder result) { - // Add trailing slash if the base URL doesn't have any path segments. - // - // The following test is checking for the last slash not being part of - // the protocol to host separator: '://'. - if (baseUrl.indexOf(':') + 2 == baseUrl.lastIndexOf('/')) - result.append('/'); - return result; - } - - private static StringBuilder addParamPrefix(final String baseUrl, - final StringBuilder result) { - // Add '?' if missing and add '&' if params already exist in base url - final int queryStart = baseUrl.indexOf('?'); - final int lastChar = result.length() - 1; - if (queryStart == -1) - result.append('?'); - else if (queryStart < lastChar && baseUrl.charAt(lastChar) != '&') - result.append('&'); - return result; - } - - private static StringBuilder addParam(final Object key, Object value, - final StringBuilder result) { - if (value != null && value.getClass().isArray()) - value = arrayToList(value); - - if (value instanceof Iterable) { - Iterator iterator = ((Iterable) value).iterator(); - while (iterator.hasNext()) { - result.append(key); - result.append("[]="); - Object element = iterator.next(); - if (element != null) - result.append(element); - if (iterator.hasNext()) - result.append("&"); - } - } else { - result.append(key); - result.append("="); - if (value != null) - result.append(value); } - return result; - } - - /** - * Creates {@link java.net.HttpURLConnection HTTP connections} for - * {@link java.net.URL urls}. - */ - public interface ConnectionFactory { - /** - * Open an {@link java.net.HttpURLConnection} for the specified {@link java.net.URL}. - * - * @throws java.io.IOException - */ - HttpURLConnection create(URL url) throws IOException; - - /** - * Open an {@link java.net.HttpURLConnection} for the specified {@link java.net.URL} - * and {@link java.net.Proxy}. - * - * @throws java.io.IOException - */ - HttpURLConnection create(URL url, Proxy proxy) throws IOException; - - /** - * A {@link com.terracom.qrpttbeta.servers.HttpRequest.ConnectionFactory} which uses the built-in - * {@link java.net.URL#openConnection()} - */ - ConnectionFactory DEFAULT = new ConnectionFactory() { - public HttpURLConnection create(URL url) throws IOException { - return (HttpURLConnection) url.openConnection(); - } - - public HttpURLConnection create(URL url, Proxy proxy) throws IOException { - return (HttpURLConnection) url.openConnection(proxy); - } - }; - } - - private static ConnectionFactory CONNECTION_FACTORY = ConnectionFactory.DEFAULT; - - /** - * Specify the {@link com.terracom.qrpttbeta.servers.HttpRequest.ConnectionFactory} used to create new requests. - */ - public static void setConnectionFactory(final ConnectionFactory connectionFactory) { - if (connectionFactory == null) - CONNECTION_FACTORY = ConnectionFactory.DEFAULT; - else - CONNECTION_FACTORY = connectionFactory; - } - - /** - * Callback interface for reporting upload progress for a request. - */ - public interface UploadProgress { - /** - * Callback invoked as data is uploaded by the request. - * - * @param uploaded The number of bytes already uploaded - * @param total The total number of bytes that will be uploaded or -1 if - * the length is unknown. - */ - void onUpload(long uploaded, long total); - - UploadProgress DEFAULT = new UploadProgress() { - public void onUpload(long uploaded, long total) { - } - }; - } - - /** - *

- * Encodes and decodes to and from Base64 notation. - *

- *

- * I am placing this code in the Public Domain. Do with it as you will. This - * software comes with no guarantees or warranties but with plenty of - * well-wishing instead! Please visit http://iharder.net/base64 periodically - * to check for updates or to contribute improvements. - *

- * - * @author Robert Harder - * @author rob@iharder.net - * @version 2.3.7 - */ - public static class Base64 { - - /** The equals sign (=) as a byte. */ - private final static byte EQUALS_SIGN = (byte) '='; - - /** Preferred encoding. */ - private final static String PREFERRED_ENCODING = "US-ASCII"; - - /** The 64 valid Base64 values. */ - private final static byte[] _STANDARD_ALPHABET = { (byte) 'A', (byte) 'B', - (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', - (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', - (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', - (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', - (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', - (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', - (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', - (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', - (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', - (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', - (byte) '+', (byte) '/' }; - - /** Defeats instantiation. */ - private Base64() { + public static class RequestOutputStream extends BufferedOutputStream { + + public RequestOutputStream(final OutputStream stream, final String charset, + final int bufferSize) { + super(stream, bufferSize); + } } - /** - *

- * Encodes up to three bytes of the array source and writes the - * resulting four Base64 bytes to destination. The source and - * destination arrays can be manipulated anywhere along their length by - * specifying srcOffset and destOffset. This method - * does not check to make sure your arrays are large enough to accomodate - * srcOffset + 3 for the source array or - * destOffset + 4 for the destination array. The - * actual number of significant bytes in your array is given by - * numSigBytes. - *

- *

- * This is the lowest level of the encoding methods with all possible - * parameters. - *

- * - * @param source - * the array to convert - * @param srcOffset - * the index where conversion begins - * @param numSigBytes - * the number of significant bytes in your array - * @param destination - * the array to hold the conversion - * @param destOffset - * the index where output will be put - * @return the destination array - * @since 1.3 - */ - private static byte[] encode3to4(byte[] source, int srcOffset, - int numSigBytes, byte[] destination, int destOffset) { - - byte[] ALPHABET = _STANDARD_ALPHABET; - - int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) - | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) - | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); - - switch (numSigBytes) { - case 3: - destination[destOffset] = ALPHABET[(inBuff >>> 18)]; - destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; - destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f]; - return destination; - - case 2: - destination[destOffset] = ALPHABET[(inBuff >>> 18)]; - destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; - destination[destOffset + 3] = EQUALS_SIGN; - return destination; - - case 1: - destination[destOffset] = ALPHABET[(inBuff >>> 18)]; - destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = EQUALS_SIGN; - destination[destOffset + 3] = EQUALS_SIGN; - return destination; - - default: - return destination; - } + private static List arrayToList(final Object array) { + if (array instanceof Object[]) + return Arrays.asList((Object[]) array); + + List result = new ArrayList(); + if (array instanceof int[]) + for (int value : (int[]) array) result.add(value); + else if (array instanceof boolean[]) + for (boolean value : (boolean[]) array) result.add(value); + else if (array instanceof long[]) + for (long value : (long[]) array) result.add(value); + else if (array instanceof float[]) + for (float value : (float[]) array) result.add(value); + else if (array instanceof double[]) + for (double value : (double[]) array) result.add(value); + else if (array instanceof short[]) + for (short value : (short[]) array) result.add(value); + else if (array instanceof byte[]) + for (byte value : (byte[]) array) result.add(value); + else if (array instanceof char[]) + for (char value : (char[]) array) result.add(value); + return result; + } + + public static String encode(final CharSequence url) + throws HttpRequestException { + URL parsed; + try { + parsed = new URL(url.toString()); + } catch (IOException e) { + throw new HttpRequestException(e); + } + + String host = parsed.getHost(); + int port = parsed.getPort(); + if (port != -1) + host = host + ':' + Integer.toString(port); + + try { + String encoded = new URI(parsed.getProtocol(), host, parsed.getPath(), + parsed.getQuery(), null).toASCIIString(); + int paramsStart = encoded.indexOf('?'); + if (paramsStart > 0 && paramsStart + 1 < encoded.length()) + encoded = encoded.substring(0, paramsStart + 1) + + encoded.substring(paramsStart + 1).replace("+", "%2B"); + return encoded; + } catch (URISyntaxException e) { + IOException io = new IOException("Parsing URI failed"); + io.initCause(e); + throw new HttpRequestException(io); + } + } + + public static String append(final CharSequence url, final Map params) { + final String baseUrl = url.toString(); + if (params == null || params.isEmpty()) + return baseUrl; + + final StringBuilder result = new StringBuilder(baseUrl); + + addPathSeparator(baseUrl, result); + addParamPrefix(baseUrl, result); + Entry entry; + Iterator iterator = params.entrySet().iterator(); + entry = (Entry) iterator.next(); + addParam(entry.getKey().toString(), entry.getValue(), result); + + while (iterator.hasNext()) { + result.append('&'); + entry = (Entry) iterator.next(); + addParam(entry.getKey().toString(), entry.getValue(), result); + } + return result.toString(); + } + + public static String append(final CharSequence url, final Object... params) { + final String baseUrl = url.toString(); + if (params == null || params.length == 0) + return baseUrl; + + if (params.length % 2 != 0) + throw new IllegalArgumentException( + "Must specify an even number of parameter names/values"); + + final StringBuilder result = new StringBuilder(baseUrl); + + addPathSeparator(baseUrl, result); + addParamPrefix(baseUrl, result); + addParam(params[0], params[1], result); + + for (int i = 2; i < params.length; i += 2) { + result.append('&'); + addParam(params[i], params[i + 1], result); + } + return result.toString(); } - /** - * Encode string as a byte array in Base64 annotation. - * - * @param string - * @return The Base64-encoded data as a string - */ - public static String encode(String string) { - byte[] bytes; - try { - bytes = string.getBytes(PREFERRED_ENCODING); - } catch (UnsupportedEncodingException e) { - bytes = string.getBytes(); - } - return encodeBytes(bytes); + public static HttpRequest get(final CharSequence url) + throws HttpRequestException { + return new HttpRequest(url, METHOD_GET); } - /** - * Encodes a byte array into Base64 notation. - * - * @param source - * The data to convert - * @return The Base64-encoded data as a String - * @throws NullPointerException - * if source array is null - * @throws IllegalArgumentException - * if source array, offset, or length are invalid - * @since 2.0 - */ - public static String encodeBytes(byte[] source) { - return encodeBytes(source, 0, source.length); + public static HttpRequest get(final URL url) throws HttpRequestException { + return new HttpRequest(url, METHOD_GET); } - /** - * Encodes a byte array into Base64 notation. - * - * @param source - * The data to convert - * @param off - * Offset in array where conversion should begin - * @param len - * Length of data to convert - * @return The Base64-encoded data as a String - * @throws NullPointerException - * if source array is null - * @throws IllegalArgumentException - * if source array, offset, or length are invalid - * @since 2.0 - */ - public static String encodeBytes(byte[] source, int off, int len) { - byte[] encoded = encodeBytesToBytes(source, off, len); - try { - return new String(encoded, PREFERRED_ENCODING); - } catch (UnsupportedEncodingException uue) { - return new String(encoded); - } + public static HttpRequest get(final CharSequence baseUrl, + final Map params, final boolean encode) { + String url = append(baseUrl, params); + return get(encode ? encode(url) : url); } - /** - * Similar to {@link #encodeBytes(byte[], int, int)} but returns a byte - * array instead of instantiating a String. This is more efficient if you're - * working with I/O streams and have large data sets to encode. - * - * - * @param source - * The data to convert - * @param off - * Offset in array where conversion should begin - * @param len - * Length of data to convert - * @return The Base64-encoded data as a String if there is an error - * @throws NullPointerException - * if source array is null - * @throws IllegalArgumentException - * if source array, offset, or length are invalid - * @since 2.3.1 - */ - public static byte[] encodeBytesToBytes(byte[] source, int off, int len) { - - if (source == null) - throw new NullPointerException("Cannot serialize a null array."); - - if (off < 0) - throw new IllegalArgumentException("Cannot have negative offset: " - + off); - - if (len < 0) - throw new IllegalArgumentException("Cannot have length offset: " + len); - - if (off + len > source.length) - throw new IllegalArgumentException( - String - .format( - "Cannot have offset of %d and length of %d with array of length %d", - off, len, source.length)); - - // Bytes needed for actual encoding - int encLen = (len / 3) * 4 + (len % 3 > 0 ? 4 : 0); - - byte[] outBuff = new byte[encLen]; - - int d = 0; - int e = 0; - int len2 = len - 2; - for (; d < len2; d += 3, e += 4) - encode3to4(source, d + off, 3, outBuff, e); - - if (d < len) { - encode3to4(source, d + off, len - d, outBuff, e); - e += 4; - } - - if (e <= outBuff.length - 1) { - byte[] finalOut = new byte[e]; - System.arraycopy(outBuff, 0, finalOut, 0, e); - return finalOut; - } else - return outBuff; + public static HttpRequest get(final CharSequence baseUrl, + final boolean encode, final Object... params) { + String url = append(baseUrl, params); + return get(encode ? encode(url) : url); } - } - - /** - * HTTP request exception whose cause is always an {@link java.io.IOException} - */ - public static class HttpRequestException extends RuntimeException { - - private static final long serialVersionUID = -1170466989781746231L; - - /** - * Create a new HttpRequestException with the given cause - * - * @param cause - */ - public HttpRequestException(final IOException cause) { - super(cause); + + public static HttpRequest delete(final CharSequence url) + throws HttpRequestException { + return new HttpRequest(url, METHOD_DELETE); } - /** - * Get {@link java.io.IOException} that triggered this request exception - * - * @return {@link java.io.IOException} cause - */ - @Override - public IOException getCause() { - return (IOException) super.getCause(); + public static HttpRequest delete(final URL url) throws HttpRequestException { + return new HttpRequest(url, METHOD_DELETE); + } + + public static HttpRequest delete(final CharSequence baseUrl, + final Map params, final boolean encode) { + String url = append(baseUrl, params); + return delete(encode ? encode(url) : url); } - } - - /** - * Operation that handles executing a callback once complete and handling - * nested exceptions - * - * @param - */ - protected static abstract class Operation implements Callable { - - /** - * Run operation - * - * @return result - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - * @throws java.io.IOException - */ - protected abstract V run() throws HttpRequestException, IOException; - - /** - * Operation complete callback - * - * @throws java.io.IOException - */ - protected abstract void done() throws IOException; - - public V call() throws HttpRequestException { - boolean thrown = false; - try { - return run(); - } catch (HttpRequestException e) { - thrown = true; - throw e; - } catch (IOException e) { - thrown = true; - throw new HttpRequestException(e); - } finally { + + public static HttpRequest delete(final CharSequence baseUrl, + final boolean encode, final Object... params) { + String url = append(baseUrl, params); + return delete(encode ? encode(url) : url); + } + + private HttpURLConnection connection = null; + private final URL url; + private final String requestMethod; + private RequestOutputStream output; + private boolean ignoreCloseExceptions = true; + private boolean uncompress = false; + private int bufferSize = 8192; + private long totalSize = -1; + private long totalWritten = 0; + private UploadProgress progress = UploadProgress.DEFAULT; + + public HttpRequest(final CharSequence url, final String method) + throws HttpRequestException { try { - done(); - } catch (IOException e) { - if (!thrown) + this.url = new URL(url.toString()); + } catch (MalformedURLException e) { throw new HttpRequestException(e); } - } + this.requestMethod = method; } - } - - /** - * Class that ensures a {@link java.io.Closeable} gets closed with proper exception - * handling. - * - * @param - */ - protected static abstract class CloseOperation extends Operation { - - private final Closeable closeable; - - private final boolean ignoreCloseExceptions; - - /** - * Create closer for operation - * - * @param closeable - * @param ignoreCloseExceptions - */ - protected CloseOperation(final Closeable closeable, - final boolean ignoreCloseExceptions) { - this.closeable = closeable; - this.ignoreCloseExceptions = ignoreCloseExceptions; + + public HttpRequest(final URL url, final String method) + throws HttpRequestException { + this.url = url; + this.requestMethod = method; } - @Override - protected void done() throws IOException { - if (closeable instanceof Flushable) - ((Flushable) closeable).flush(); - if (ignoreCloseExceptions) + private HttpURLConnection createConnection() { try { - closeable.close(); + final HttpURLConnection connection; + connection = CONNECTION_FACTORY.create(url); + connection.setRequestMethod(requestMethod); + return connection; } catch (IOException e) { - // Ignored + throw new HttpRequestException(e); } - else - closeable.close(); - } - } - - /** - * Class that and ensures a {@link java.io.Flushable} gets flushed with proper - * exception handling. - * - * @param - */ - protected static abstract class FlushOperation extends Operation { - - private final Flushable flushable; - - /** - * Create flush operation - * - * @param flushable - */ - protected FlushOperation(final Flushable flushable) { - this.flushable = flushable; } @Override - protected void done() throws IOException { - flushable.flush(); - } - } - - /** - * Request output stream - */ - public static class RequestOutputStream extends BufferedOutputStream { - - private final CharsetEncoder encoder; - - /** - * Create request output stream - * - * @param stream - * @param charset - * @param bufferSize - */ - public RequestOutputStream(final OutputStream stream, final String charset, - final int bufferSize) { - super(stream, bufferSize); - - encoder = Charset.forName(getValidCharset(charset)).newEncoder(); + public String toString() { + return method() + ' ' + url(); } - /** - * Write string to stream - * - * @param value - * @return this stream - * @throws java.io.IOException - */ - public RequestOutputStream write(final String value) throws IOException { - final ByteBuffer bytes = encoder.encode(CharBuffer.wrap(value)); - - super.write(bytes.array(), 0, bytes.limit()); - - return this; - } - } - - /** - * Represents array of any type as list of objects so we can easily iterate over it - * @param array of elements - * @return list with the same elements - */ - private static List arrayToList(final Object array) { - if (array instanceof Object[]) - return Arrays.asList((Object[]) array); - - List result = new ArrayList(); - // Arrays of the primitive types can't be cast to array of Object, so this: - if (array instanceof int[]) - for (int value : (int[]) array) result.add(value); - else if (array instanceof boolean[]) - for (boolean value : (boolean[]) array) result.add(value); - else if (array instanceof long[]) - for (long value : (long[]) array) result.add(value); - else if (array instanceof float[]) - for (float value : (float[]) array) result.add(value); - else if (array instanceof double[]) - for (double value : (double[]) array) result.add(value); - else if (array instanceof short[]) - for (short value : (short[]) array) result.add(value); - else if (array instanceof byte[]) - for (byte value : (byte[]) array) result.add(value); - else if (array instanceof char[]) - for (char value : (char[]) array) result.add(value); - return result; - } - - /** - * Encode the given URL as an ASCII {@link String} - *

- * This method ensures the path and query segments of the URL are properly - * encoded such as ' ' characters being encoded to '%20' or any UTF-8 - * characters that are non-ASCII. No encoding of URLs is done by default by - * the {@link com.terracom.qrpttbeta.servers.HttpRequest} constructors and so if URL encoding is needed this - * method should be called before calling the {@link com.terracom.qrpttbeta.servers.HttpRequest} constructor. - * - * @param url - * @return encoded URL - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static String encode(final CharSequence url) - throws HttpRequestException { - URL parsed; - try { - parsed = new URL(url.toString()); - } catch (IOException e) { - throw new HttpRequestException(e); + public HttpURLConnection getConnection() { + if (connection == null) + connection = createConnection(); + return connection; } - String host = parsed.getHost(); - int port = parsed.getPort(); - if (port != -1) - host = host + ':' + Integer.toString(port); - - try { - String encoded = new URI(parsed.getProtocol(), host, parsed.getPath(), - parsed.getQuery(), null).toASCIIString(); - int paramsStart = encoded.indexOf('?'); - if (paramsStart > 0 && paramsStart + 1 < encoded.length()) - encoded = encoded.substring(0, paramsStart + 1) - + encoded.substring(paramsStart + 1).replace("+", "%2B"); - return encoded; - } catch (URISyntaxException e) { - IOException io = new IOException("Parsing URI failed"); - io.initCause(e); - throw new HttpRequestException(io); + public int code() throws HttpRequestException { + try { + closeOutput(); + return getConnection().getResponseCode(); + } catch (IOException e) { + throw new HttpRequestException(e); + } } - } - - /** - * Append given map as query parameters to the base URL - *

- * Each map entry's key will be a parameter name and the value's - * {@link Object#toString()} will be the parameter value. - * - * @param url - * @param params - * @return URL with appended query params - */ - public static String append(final CharSequence url, final Map params) { - final String baseUrl = url.toString(); - if (params == null || params.isEmpty()) - return baseUrl; - - final StringBuilder result = new StringBuilder(baseUrl); - - addPathSeparator(baseUrl, result); - addParamPrefix(baseUrl, result); - - Entry entry; - Iterator iterator = params.entrySet().iterator(); - entry = (Entry) iterator.next(); - addParam(entry.getKey().toString(), entry.getValue(), result); - - while (iterator.hasNext()) { - result.append('&'); - entry = (Entry) iterator.next(); - addParam(entry.getKey().toString(), entry.getValue(), result); + + public HttpRequest disconnect() { + getConnection().disconnect(); + return this; } - return result.toString(); - } - - /** - * Append given name/value pairs as query parameters to the base URL - *

- * The params argument is interpreted as a sequence of name/value pairs so the - * given number of params must be divisible by 2. - * - * @param url - * @param params - * name/value pairs - * @return URL with appended query params - */ - public static String append(final CharSequence url, final Object... params) { - final String baseUrl = url.toString(); - if (params == null || params.length == 0) - return baseUrl; - - if (params.length % 2 != 0) - throw new IllegalArgumentException( - "Must specify an even number of parameter names/values"); - - final StringBuilder result = new StringBuilder(baseUrl); - - addPathSeparator(baseUrl, result); - addParamPrefix(baseUrl, result); - - addParam(params[0], params[1], result); - - for (int i = 2; i < params.length; i += 2) { - result.append('&'); - addParam(params[i], params[i + 1], result); + protected ByteArrayOutputStream byteStream() { + final int size = contentLength(); + if (size > 0) + return new ByteArrayOutputStream(size); + else + return new ByteArrayOutputStream(); } - return result.toString(); - } - - /** - * Start a 'GET' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest get(final CharSequence url) - throws HttpRequestException { - return new HttpRequest(url, METHOD_GET); - } - - /** - * Start a 'GET' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest get(final URL url) throws HttpRequestException { - return new HttpRequest(url, METHOD_GET); - } - - /** - * Start a 'GET' request to the given URL along with the query params - * - * @param baseUrl - * @param params - * The query parameters to include as part of the baseUrl - * @param encode - * true to encode the full URL - * - * @see #append(CharSequence, java.util.Map) - * @see #encode(CharSequence) - * - * @return request - */ - public static HttpRequest get(final CharSequence baseUrl, - final Map params, final boolean encode) { - String url = append(baseUrl, params); - return get(encode ? encode(url) : url); - } - - /** - * Start a 'GET' request to the given URL along with the query params - * - * @param baseUrl - * @param encode - * true to encode the full URL - * @param params - * the name/value query parameter pairs to include as part of the - * baseUrl - * - * @see #append(CharSequence, Object...) - * @see #encode(CharSequence) - * - * @return request - */ - public static HttpRequest get(final CharSequence baseUrl, - final boolean encode, final Object... params) { - String url = append(baseUrl, params); - return get(encode ? encode(url) : url); - } - - /** - * Start a 'POST' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest post(final CharSequence url) - throws HttpRequestException { - return new HttpRequest(url, METHOD_POST); - } - - /** - * Start a 'POST' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest post(final URL url) throws HttpRequestException { - return new HttpRequest(url, METHOD_POST); - } - - /** - * Start a 'POST' request to the given URL along with the query params - * - * @param baseUrl - * @param params - * the query parameters to include as part of the baseUrl - * @param encode - * true to encode the full URL - * - * @see #append(CharSequence, java.util.Map) - * @see #encode(CharSequence) - * - * @return request - */ - public static HttpRequest post(final CharSequence baseUrl, - final Map params, final boolean encode) { - String url = append(baseUrl, params); - return post(encode ? encode(url) : url); - } - - /** - * Start a 'POST' request to the given URL along with the query params - * - * @param baseUrl - * @param encode - * true to encode the full URL - * @param params - * the name/value query parameter pairs to include as part of the - * baseUrl - * - * @see #append(CharSequence, Object...) - * @see #encode(CharSequence) - * - * @return request - */ - public static HttpRequest post(final CharSequence baseUrl, - final boolean encode, final Object... params) { - String url = append(baseUrl, params); - return post(encode ? encode(url) : url); - } - - /** - * Start a 'PUT' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest put(final CharSequence url) - throws HttpRequestException { - return new HttpRequest(url, METHOD_PUT); - } - - /** - * Start a 'PUT' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest put(final URL url) throws HttpRequestException { - return new HttpRequest(url, METHOD_PUT); - } - - /** - * Start a 'PUT' request to the given URL along with the query params - * - * @param baseUrl - * @param params - * the query parameters to include as part of the baseUrl - * @param encode - * true to encode the full URL - * - * @see #append(CharSequence, java.util.Map) - * @see #encode(CharSequence) - * - * @return request - */ - public static HttpRequest put(final CharSequence baseUrl, - final Map params, final boolean encode) { - String url = append(baseUrl, params); - return put(encode ? encode(url) : url); - } - - /** - * Start a 'PUT' request to the given URL along with the query params - * - * @param baseUrl - * @param encode - * true to encode the full URL - * @param params - * the name/value query parameter pairs to include as part of the - * baseUrl - * - * @see #append(CharSequence, Object...) - * @see #encode(CharSequence) - * - * @return request - */ - public static HttpRequest put(final CharSequence baseUrl, - final boolean encode, final Object... params) { - String url = append(baseUrl, params); - return put(encode ? encode(url) : url); - } - - /** - * Start a 'DELETE' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest delete(final CharSequence url) - throws HttpRequestException { - return new HttpRequest(url, METHOD_DELETE); - } - - /** - * Start a 'DELETE' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest delete(final URL url) throws HttpRequestException { - return new HttpRequest(url, METHOD_DELETE); - } - - /** - * Start a 'DELETE' request to the given URL along with the query params - * - * @param baseUrl - * @param params - * The query parameters to include as part of the baseUrl - * @param encode - * true to encode the full URL - * - * @see #append(CharSequence, java.util.Map) - * @see #encode(CharSequence) - * - * @return request - */ - public static HttpRequest delete(final CharSequence baseUrl, - final Map params, final boolean encode) { - String url = append(baseUrl, params); - return delete(encode ? encode(url) : url); - } - - /** - * Start a 'DELETE' request to the given URL along with the query params - * - * @param baseUrl - * @param encode - * true to encode the full URL - * @param params - * the name/value query parameter pairs to include as part of the - * baseUrl - * - * @see #append(CharSequence, Object...) - * @see #encode(CharSequence) - * - * @return request - */ - public static HttpRequest delete(final CharSequence baseUrl, - final boolean encode, final Object... params) { - String url = append(baseUrl, params); - return delete(encode ? encode(url) : url); - } - - /** - * Start a 'HEAD' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest head(final CharSequence url) - throws HttpRequestException { - return new HttpRequest(url, METHOD_HEAD); - } - - /** - * Start a 'HEAD' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest head(final URL url) throws HttpRequestException { - return new HttpRequest(url, METHOD_HEAD); - } - - /** - * Start a 'HEAD' request to the given URL along with the query params - * - * @param baseUrl - * @param params - * The query parameters to include as part of the baseUrl - * @param encode - * true to encode the full URL - * - * @see #append(CharSequence, java.util.Map) - * @see #encode(CharSequence) - * - * @return request - */ - public static HttpRequest head(final CharSequence baseUrl, - final Map params, final boolean encode) { - String url = append(baseUrl, params); - return head(encode ? encode(url) : url); - } - - /** - * Start a 'GET' request to the given URL along with the query params - * - * @param baseUrl - * @param encode - * true to encode the full URL - * @param params - * the name/value query parameter pairs to include as part of the - * baseUrl - * - * @see #append(CharSequence, Object...) - * @see #encode(CharSequence) - * - * @return request - */ - public static HttpRequest head(final CharSequence baseUrl, - final boolean encode, final Object... params) { - String url = append(baseUrl, params); - return head(encode ? encode(url) : url); - } - - /** - * Start an 'OPTIONS' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest options(final CharSequence url) - throws HttpRequestException { - return new HttpRequest(url, METHOD_OPTIONS); - } - - /** - * Start an 'OPTIONS' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest options(final URL url) throws HttpRequestException { - return new HttpRequest(url, METHOD_OPTIONS); - } - - /** - * Start a 'TRACE' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest trace(final CharSequence url) - throws HttpRequestException { - return new HttpRequest(url, METHOD_TRACE); - } - - /** - * Start a 'TRACE' request to the given URL - * - * @param url - * @return request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public static HttpRequest trace(final URL url) throws HttpRequestException { - return new HttpRequest(url, METHOD_TRACE); - } - - /** - * Set the 'http.keepAlive' property to the given value. - *

- * This setting will apply to all requests. - * - * @param keepAlive - */ - public static void keepAlive(final boolean keepAlive) { - setProperty("http.keepAlive", Boolean.toString(keepAlive)); - } - - /** - * Set the 'http.maxConnections' property to the given value. - *

- * This setting will apply to all requests. - * - * @param maxConnections - */ - public static void maxConnections(final int maxConnections) { - setProperty("http.maxConnections", Integer.toString(maxConnections)); - } - - /** - * Set the 'http.proxyHost' and 'https.proxyHost' properties to the given host - * value. - *

- * This setting will apply to all requests. - * - * @param host - */ - public static void proxyHost(final String host) { - setProperty("http.proxyHost", host); - setProperty("https.proxyHost", host); - } - - /** - * Set the 'http.proxyPort' and 'https.proxyPort' properties to the given port - * number. - *

- * This setting will apply to all requests. - * - * @param port - */ - public static void proxyPort(final int port) { - final String portValue = Integer.toString(port); - setProperty("http.proxyPort", portValue); - setProperty("https.proxyPort", portValue); - } - - /** - * Set the 'http.nonProxyHosts' property to the given host values. - *

- * Hosts will be separated by a '|' character. - *

- * This setting will apply to all requests. - * - * @param hosts - */ - public static void nonProxyHosts(final String... hosts) { - if (hosts != null && hosts.length > 0) { - StringBuilder separated = new StringBuilder(); - int last = hosts.length - 1; - for (int i = 0; i < last; i++) - separated.append(hosts[i]).append('|'); - separated.append(hosts[last]); - setProperty("http.nonProxyHosts", separated.toString()); - } else - setProperty("http.nonProxyHosts", null); - } - - /** - * Set property to given value. - *

- * Specifying a null value will cause the property to be cleared - * - * @param name - * @param value - * @return previous value - */ - private static String setProperty(final String name, final String value) { - final PrivilegedAction action; - if (value != null) - action = new PrivilegedAction() { - - public String run() { - return System.setProperty(name, value); + public String body(final String charset) throws HttpRequestException { + final ByteArrayOutputStream output = byteStream(); + try { + copy(buffer(), output); + return output.toString(getValidCharset(charset)); + } catch (IOException e) { + throw new HttpRequestException(e); } - }; - else - action = new PrivilegedAction() { + } - public String run() { - return System.clearProperty(name); + public String body() throws HttpRequestException { + return body(charset()); + } + + public BufferedInputStream buffer() throws HttpRequestException { + return new BufferedInputStream(stream(), bufferSize); + } + + public InputStream stream() throws HttpRequestException { + InputStream stream; + if (code() < HTTP_BAD_REQUEST) + try { + stream = getConnection().getInputStream(); + } catch (IOException e) { + throw new HttpRequestException(e); + } + else { + stream = getConnection().getErrorStream(); + if (stream == null) + try { + stream = getConnection().getInputStream(); + } catch (IOException e) { + if (contentLength() > 0) + throw new HttpRequestException(e); + else + stream = new ByteArrayInputStream(new byte[0]); + } } - }; - return AccessController.doPrivileged(action); - } - - private HttpURLConnection connection = null; - private final URL url; + if (!uncompress || !ENCODING_GZIP.equals(contentEncoding())) + return stream; + else + try { + return new GZIPInputStream(stream); + } catch (IOException e) { + throw new HttpRequestException(e); + } + } - private final String requestMethod; + public String header(final String name) throws HttpRequestException { + closeOutputQuietly(); + return getConnection().getHeaderField(name); + } - private RequestOutputStream output; + public int intHeader(final String name) throws HttpRequestException { + return intHeader(name, -1); + } - private boolean multipart; + public int intHeader(final String name, final int defaultValue) + throws HttpRequestException { + closeOutputQuietly(); + return getConnection().getHeaderFieldInt(name, defaultValue); + } - private boolean form; - private boolean ignoreCloseExceptions = true; + public String parameter(final String headerName, final String paramName) { + return getParam(header(headerName), paramName); + } - private boolean uncompress = false; + protected String getParam(final String value, final String paramName) { + if (value == null || value.length() == 0) + return null; - private int bufferSize = 8192; + final int length = value.length(); + int start = value.indexOf(';') + 1; + if (start == 0 || start == length) + return null; - private long totalSize = -1; + int end = value.indexOf(';', start); + if (end == -1) + end = length; - private long totalWritten = 0; + while (start < end) { + int nameEnd = value.indexOf('=', start); + if (nameEnd != -1 && nameEnd < end + && paramName.equals(value.substring(start, nameEnd).trim())) { + String paramValue = value.substring(nameEnd + 1, end).trim(); + int valueLength = paramValue.length(); + if (valueLength != 0) + if (valueLength > 2 && '"' == paramValue.charAt(0) + && '"' == paramValue.charAt(valueLength - 1)) + return paramValue.substring(1, valueLength - 1); + else + return paramValue; + } - private String httpProxyHost; + start = end + 1; + end = value.indexOf(';', start); + if (end == -1) + end = length; + } + return null; + } - private int httpProxyPort; + public String charset() { + return parameter(HEADER_CONTENT_TYPE, PARAM_CHARSET); + } - private UploadProgress progress = UploadProgress.DEFAULT; + public String contentEncoding() { + return header(HEADER_CONTENT_ENCODING); + } - /** - * Create HTTP connection wrapper - * - * @param url Remote resource URL. - * @param method HTTP request method (e.g., "GET", "POST"). - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest(final CharSequence url, final String method) - throws HttpRequestException { - try { - this.url = new URL(url.toString()); - } catch (MalformedURLException e) { - throw new HttpRequestException(e); + public String server() { + return header(HEADER_SERVER); } - this.requestMethod = method; - } - - /** - * Create HTTP connection wrapper - * - * @param url Remote resource URL. - * @param method HTTP request method (e.g., "GET", "POST"). - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest(final URL url, final String method) - throws HttpRequestException { - this.url = url; - this.requestMethod = method; - } - - private Proxy createProxy() { - return new Proxy(HTTP, new InetSocketAddress(httpProxyHost, httpProxyPort)); - } - - private HttpURLConnection createConnection() { - try { - final HttpURLConnection connection; - if (httpProxyHost != null) - connection = CONNECTION_FACTORY.create(url, createProxy()); - else - connection = CONNECTION_FACTORY.create(url); - connection.setRequestMethod(requestMethod); - return connection; - } catch (IOException e) { - throw new HttpRequestException(e); + + public int contentLength() { + return intHeader(HEADER_CONTENT_LENGTH); } - } - - @Override - public String toString() { - return method() + ' ' + url(); - } - - /** - * Get underlying connection - * - * @return connection - */ - public HttpURLConnection getConnection() { - if (connection == null) - connection = createConnection(); - return connection; - } - - /** - * Set whether or not to ignore exceptions that occur from calling - * {@link java.io.Closeable#close()} - *

- * The default value of this setting is true - * - * @param ignore - * @return this request - */ - public HttpRequest ignoreCloseExceptions(final boolean ignore) { - ignoreCloseExceptions = ignore; - return this; - } - - /** - * Get whether or not exceptions thrown by {@link java.io.Closeable#close()} are - * ignored - * - * @return true if ignoring, false if throwing - */ - public boolean ignoreCloseExceptions() { - return ignoreCloseExceptions; - } - - /** - * Get the status code of the response - * - * @return the response code - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public int code() throws HttpRequestException { - try { - closeOutput(); - return getConnection().getResponseCode(); - } catch (IOException e) { - throw new HttpRequestException(e); + + protected HttpRequest copy(final InputStream input, final OutputStream output) + throws IOException { + return new CloseOperation(input, ignoreCloseExceptions) { + + @Override + public HttpRequest run() throws IOException { + final byte[] buffer = new byte[bufferSize]; + int read; + while ((read = input.read(buffer)) != -1) { + output.write(buffer, 0, read); + totalWritten += read; + progress.onUpload(totalWritten, totalSize); + } + return HttpRequest.this; + } + }.call(); } - } - - /** - * Set the value of the given {@link java.util.concurrent.atomic.AtomicInteger} to the status code of the - * response - * - * @param output - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest code(final AtomicInteger output) - throws HttpRequestException { - output.set(code()); - return this; - } - - /** - * Is the response code a 200 OK? - * - * @return true if 200, false otherwise - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public boolean ok() throws HttpRequestException { - return HTTP_OK == code(); - } - - /** - * Is the response code a 201 Created? - * - * @return true if 201, false otherwise - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public boolean created() throws HttpRequestException { - return HTTP_CREATED == code(); - } - - /** - * Is the response code a 204 No Content? - * - * @return true if 204, false otherwise - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public boolean noContent() throws HttpRequestException { - return HTTP_NO_CONTENT == code(); - } - - /** - * Is the response code a 500 Internal Server Error? - * - * @return true if 500, false otherwise - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public boolean serverError() throws HttpRequestException { - return HTTP_INTERNAL_ERROR == code(); - } - - /** - * Is the response code a 400 Bad Request? - * - * @return true if 400, false otherwise - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public boolean badRequest() throws HttpRequestException { - return HTTP_BAD_REQUEST == code(); - } - - /** - * Is the response code a 404 Not Found? - * - * @return true if 404, false otherwise - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public boolean notFound() throws HttpRequestException { - return HTTP_NOT_FOUND == code(); - } - - /** - * Is the response code a 304 Not Modified? - * - * @return true if 304, false otherwise - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public boolean notModified() throws HttpRequestException { - return HTTP_NOT_MODIFIED == code(); - } - - /** - * Get status message of the response - * - * @return message - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public String message() throws HttpRequestException { - try { - closeOutput(); - return getConnection().getResponseMessage(); - } catch (IOException e) { - throw new HttpRequestException(e); + + + protected HttpRequest copy(final Reader input, final Writer output) + throws IOException { + return new CloseOperation(input, ignoreCloseExceptions) { + + @Override + public HttpRequest run() throws IOException { + final char[] buffer = new char[bufferSize]; + int read; + while ((read = input.read(buffer)) != -1) { + output.write(buffer, 0, read); + totalWritten += read; + progress.onUpload(totalWritten, -1); + } + return HttpRequest.this; + } + }.call(); } - } - - /** - * Disconnect the connection - * - * @return this request - */ - public HttpRequest disconnect() { - getConnection().disconnect(); - return this; - } - - /** - * Set chunked streaming mode to the given size - * - * @param size - * @return this request - */ - public HttpRequest chunk(final int size) { - getConnection().setChunkedStreamingMode(size); - return this; - } - - /** - * Set the size used when buffering and copying between streams - *

- * This size is also used for send and receive buffers created for both char - * and byte arrays - *

- * The default buffer size is 8,192 bytes - * - * @param size - * @return this request - */ - public HttpRequest bufferSize(final int size) { - if (size < 1) - throw new IllegalArgumentException("Size must be greater than zero"); - bufferSize = size; - return this; - } - - /** - * Get the configured buffer size - *

- * The default buffer size is 8,192 bytes - * - * @return buffer size - */ - public int bufferSize() { - return bufferSize; - } - - /** - * Set whether or not the response body should be automatically uncompressed - * when read from. - *

- * This will only affect requests that have the 'Content-Encoding' response - * header set to 'gzip'. - *

- * This causes all receive methods to use a {@link java.util.zip.GZIPInputStream} when - * applicable so that higher level streams and readers can read the data - * uncompressed. - *

- * Setting this option does not cause any request headers to be set - * automatically so {@link #acceptGzipEncoding()} should be used in - * conjunction with this setting to tell the server to gzip the response. - * - * @param uncompress - * @return this request - */ - public HttpRequest uncompress(final boolean uncompress) { - this.uncompress = uncompress; - return this; - } - - /** - * Create byte array output stream - * - * @return stream - */ - protected ByteArrayOutputStream byteStream() { - final int size = contentLength(); - if (size > 0) - return new ByteArrayOutputStream(size); - else - return new ByteArrayOutputStream(); - } - - /** - * Get response as {@link String} in given character set - *

- * This will fall back to using the UTF-8 character set if the given charset - * is null - * - * @param charset - * @return string - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public String body(final String charset) throws HttpRequestException { - final ByteArrayOutputStream output = byteStream(); - try { - copy(buffer(), output); - return output.toString(getValidCharset(charset)); - } catch (IOException e) { - throw new HttpRequestException(e); + + public HttpRequest progress(final UploadProgress callback) { + if (callback == null) + progress = UploadProgress.DEFAULT; + else + progress = callback; + return this; } - } - - /** - * Get response as {@link String} using character set returned from - * {@link #charset()} - * - * @return string - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public String body() throws HttpRequestException { - return body(charset()); - } - - /** - * Get the response body as a {@link String} and set it as the value of the - * given reference. - * - * @param output - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest body(final AtomicReference output) throws HttpRequestException { - output.set(body()); - return this; - } - - /** - * Get the response body as a {@link String} and set it as the value of the - * given reference. - * - * @param output - * @param charset - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest body(final AtomicReference output, final String charset) throws HttpRequestException { - output.set(body(charset)); - return this; - } - - - /** - * Is the response body empty? - * - * @return true if the Content-Length response header is 0, false otherwise - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public boolean isBodyEmpty() throws HttpRequestException { - return contentLength() == 0; - } - - /** - * Get response as byte array - * - * @return byte array - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public byte[] bytes() throws HttpRequestException { - final ByteArrayOutputStream output = byteStream(); - try { - copy(buffer(), output); - } catch (IOException e) { - throw new HttpRequestException(e); + + protected HttpRequest closeOutput() throws IOException { + progress(null); + if (output == null) + return this; + if (ignoreCloseExceptions) + try { + output.close(); + } catch (IOException ignored) { + } + else + output.close(); + output = null; + return this; } - return output.toByteArray(); - } - - /** - * Get response in a buffered stream - * - * @see #bufferSize(int) - * @return stream - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public BufferedInputStream buffer() throws HttpRequestException { - return new BufferedInputStream(stream(), bufferSize); - } - - /** - * Get stream to response body - * - * @return stream - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public InputStream stream() throws HttpRequestException { - InputStream stream; - if (code() < HTTP_BAD_REQUEST) - try { - stream = getConnection().getInputStream(); - } catch (IOException e) { - throw new HttpRequestException(e); - } - else { - stream = getConnection().getErrorStream(); - if (stream == null) + + protected HttpRequest closeOutputQuietly() throws HttpRequestException { try { - stream = getConnection().getInputStream(); + return closeOutput(); } catch (IOException e) { - if (contentLength() > 0) throw new HttpRequestException(e); - else - stream = new ByteArrayInputStream(new byte[0]); } } - if (!uncompress || !ENCODING_GZIP.equals(contentEncoding())) - return stream; - else - try { - return new GZIPInputStream(stream); - } catch (IOException e) { - throw new HttpRequestException(e); - } - } - - /** - * Get reader to response body using given character set. - *

- * This will fall back to using the UTF-8 character set if the given charset - * is null - * - * @param charset - * @return reader - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public InputStreamReader reader(final String charset) - throws HttpRequestException { - try { - return new InputStreamReader(stream(), getValidCharset(charset)); - } catch (UnsupportedEncodingException e) { - throw new HttpRequestException(e); - } - } - - /** - * Get reader to response body using the character set returned from - * {@link #charset()} - * - * @return reader - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public InputStreamReader reader() throws HttpRequestException { - return reader(charset()); - } - - /** - * Get buffered reader to response body using the given character set r and - * the configured buffer size - * - * - * @see #bufferSize(int) - * @param charset - * @return reader - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public BufferedReader bufferedReader(final String charset) - throws HttpRequestException { - return new BufferedReader(reader(charset), bufferSize); - } - - /** - * Get buffered reader to response body using the character set returned from - * {@link #charset()} and the configured buffer size - * - * @see #bufferSize(int) - * @return reader - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public BufferedReader bufferedReader() throws HttpRequestException { - return bufferedReader(charset()); - } - - /** - * Stream response body to file - * - * @param file - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest receive(final File file) throws HttpRequestException { - final OutputStream output; - try { - output = new BufferedOutputStream(new FileOutputStream(file), bufferSize); - } catch (FileNotFoundException e) { - throw new HttpRequestException(e); + public HttpRequest trustAllCerts() throws HttpRequestException { + final HttpURLConnection connection = getConnection(); + if (connection instanceof HttpsURLConnection) + ((HttpsURLConnection) connection) + .setSSLSocketFactory(getTrustedFactory()); + return this; } - return new CloseOperation(output, ignoreCloseExceptions) { - - @Override - protected HttpRequest run() throws HttpRequestException, IOException { - return receive(output); - } - }.call(); - } - - /** - * Stream response to given output stream - * - * @param output - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest receive(final OutputStream output) - throws HttpRequestException { - try { - return copy(buffer(), output); - } catch (IOException e) { - throw new HttpRequestException(e); - } - } - - /** - * Stream response to given print stream - * - * @param output - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest receive(final PrintStream output) - throws HttpRequestException { - return receive((OutputStream) output); - } - - /** - * Receive response into the given appendable - * - * @param appendable - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest receive(final Appendable appendable) - throws HttpRequestException { - final BufferedReader reader = bufferedReader(); - return new CloseOperation(reader, ignoreCloseExceptions) { - - @Override - public HttpRequest run() throws IOException { - final CharBuffer buffer = CharBuffer.allocate(bufferSize); - int read; - while ((read = reader.read(buffer)) != -1) { - buffer.rewind(); - appendable.append(buffer, 0, read); - buffer.rewind(); - } - return HttpRequest.this; - } - }.call(); - } - - /** - * Receive response into the given writer - * - * @param writer - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest receive(final Writer writer) throws HttpRequestException { - final BufferedReader reader = bufferedReader(); - return new CloseOperation(reader, ignoreCloseExceptions) { - - @Override - public HttpRequest run() throws IOException { - return copy(reader, writer); - } - }.call(); - } - - /** - * Set read timeout on connection to given value - * - * @param timeout - * @return this request - */ - public HttpRequest readTimeout(final int timeout) { - getConnection().setReadTimeout(timeout); - return this; - } - - /** - * Set connect timeout on connection to given value - * - * @param timeout - * @return this request - */ - public HttpRequest connectTimeout(final int timeout) { - getConnection().setConnectTimeout(timeout); - return this; - } - - /** - * Set header name to given value - * - * @param name - * @param value - * @return this request - */ - public HttpRequest header(final String name, final String value) { - getConnection().setRequestProperty(name, value); - return this; - } - - /** - * Set header name to given value - * - * @param name - * @param value - * @return this request - */ - public HttpRequest header(final String name, final Number value) { - return header(name, value != null ? value.toString() : null); - } - - /** - * Set all headers found in given map where the keys are the header names and - * the values are the header values - * - * @param headers - * @return this request - */ - public HttpRequest headers(final Map headers) { - if (!headers.isEmpty()) - for (Entry header : headers.entrySet()) - header(header); - return this; - } - - /** - * Set header to have given entry's key as the name and value as the value - * - * @param header - * @return this request - */ - public HttpRequest header(final Entry header) { - return header(header.getKey(), header.getValue()); - } - - /** - * Get a response header - * - * @param name - * @return response header - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public String header(final String name) throws HttpRequestException { - closeOutputQuietly(); - return getConnection().getHeaderField(name); - } - - /** - * Get all the response headers - * - * @return map of response header names to their value(s) - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public Map> headers() throws HttpRequestException { - closeOutputQuietly(); - return getConnection().getHeaderFields(); - } - - /** - * Get a date header from the response falling back to returning -1 if the - * header is missing or parsing fails - * - * @param name - * @return date, -1 on failures - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public long dateHeader(final String name) throws HttpRequestException { - return dateHeader(name, -1L); - } - - /** - * Get a date header from the response falling back to returning the given - * default value if the header is missing or parsing fails - * - * @param name - * @param defaultValue - * @return date, default value on failures - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public long dateHeader(final String name, final long defaultValue) - throws HttpRequestException { - closeOutputQuietly(); - return getConnection().getHeaderFieldDate(name, defaultValue); - } - - /** - * Get an integer header from the response falling back to returning -1 if the - * header is missing or parsing fails - * - * @param name - * @return header value as an integer, -1 when missing or parsing fails - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public int intHeader(final String name) throws HttpRequestException { - return intHeader(name, -1); - } - - /** - * Get an integer header value from the response falling back to the given - * default value if the header is missing or if parsing fails - * - * @param name - * @param defaultValue - * @return header value as an integer, default value when missing or parsing - * fails - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public int intHeader(final String name, final int defaultValue) - throws HttpRequestException { - closeOutputQuietly(); - return getConnection().getHeaderFieldInt(name, defaultValue); - } - - /** - * Get all values of the given header from the response - * - * @param name - * @return non-null but possibly empty array of {@link String} header values - */ - public String[] headers(final String name) { - final Map> headers = headers(); - if (headers == null || headers.isEmpty()) - return EMPTY_STRINGS; - - final List values = headers.get(name); - if (values != null && !values.isEmpty()) - return values.toArray(new String[values.size()]); - else - return EMPTY_STRINGS; - } - - /** - * Get parameter with given name from header value in response - * - * @param headerName - * @param paramName - * @return parameter value or null if missing - */ - public String parameter(final String headerName, final String paramName) { - return getParam(header(headerName), paramName); - } - - /** - * Get all parameters from header value in response - *

- * This will be all key=value pairs after the first ';' that are separated by - * a ';' - * - * @param headerName - * @return non-null but possibly empty map of parameter headers - */ - public Map parameters(final String headerName) { - return getParams(header(headerName)); - } - - /** - * Get parameter values from header value - * - * @param header - * @return parameter value or null if none - */ - protected Map getParams(final String header) { - if (header == null || header.length() == 0) - return Collections.emptyMap(); - - final int headerLength = header.length(); - int start = header.indexOf(';') + 1; - if (start == 0 || start == headerLength) - return Collections.emptyMap(); - - int end = header.indexOf(';', start); - if (end == -1) - end = headerLength; - - Map params = new LinkedHashMap(); - while (start < end) { - int nameEnd = header.indexOf('=', start); - if (nameEnd != -1 && nameEnd < end) { - String name = header.substring(start, nameEnd).trim(); - if (name.length() > 0) { - String value = header.substring(nameEnd + 1, end).trim(); - int length = value.length(); - if (length != 0) - if (length > 2 && '"' == value.charAt(0) - && '"' == value.charAt(length - 1)) - params.put(name, value.substring(1, length - 1)); - else - params.put(name, value); - } - } - start = end + 1; - end = header.indexOf(';', start); - if (end == -1) - end = headerLength; + public HttpRequest trustAllHosts() { + final HttpURLConnection connection = getConnection(); + if (connection instanceof HttpsURLConnection) + ((HttpsURLConnection) connection) + .setHostnameVerifier(getTrustedVerifier()); + return this; } - return params; - } - - /** - * Get parameter value from header value - * - * @param value - * @param paramName - * @return parameter value or null if none - */ - protected String getParam(final String value, final String paramName) { - if (value == null || value.length() == 0) - return null; - - final int length = value.length(); - int start = value.indexOf(';') + 1; - if (start == 0 || start == length) - return null; - - int end = value.indexOf(';', start); - if (end == -1) - end = length; - - while (start < end) { - int nameEnd = value.indexOf('=', start); - if (nameEnd != -1 && nameEnd < end - && paramName.equals(value.substring(start, nameEnd).trim())) { - String paramValue = value.substring(nameEnd + 1, end).trim(); - int valueLength = paramValue.length(); - if (valueLength != 0) - if (valueLength > 2 && '"' == paramValue.charAt(0) - && '"' == paramValue.charAt(valueLength - 1)) - return paramValue.substring(1, valueLength - 1); - else - return paramValue; - } - - start = end + 1; - end = value.indexOf(';', start); - if (end == -1) - end = length; + public URL url() { + return getConnection().getURL(); } - return null; - } - - /** - * Get 'charset' parameter from 'Content-Type' response header - * - * @return charset or null if none - */ - public String charset() { - return parameter(HEADER_CONTENT_TYPE, PARAM_CHARSET); - } - - /** - * Set the 'User-Agent' header to given value - * - * @param userAgent - * @return this request - */ - public HttpRequest userAgent(final String userAgent) { - return header(HEADER_USER_AGENT, userAgent); - } - - /** - * Set the 'Referer' header to given value - * - * @param referer - * @return this request - */ - public HttpRequest referer(final String referer) { - return header(HEADER_REFERER, referer); - } - - /** - * Set value of {@link java.net.HttpURLConnection#setUseCaches(boolean)} - * - * @param useCaches - * @return this request - */ - public HttpRequest useCaches(final boolean useCaches) { - getConnection().setUseCaches(useCaches); - return this; - } - - /** - * Set the 'Accept-Encoding' header to given value - * - * @param acceptEncoding - * @return this request - */ - public HttpRequest acceptEncoding(final String acceptEncoding) { - return header(HEADER_ACCEPT_ENCODING, acceptEncoding); - } - - /** - * Set the 'Accept-Encoding' header to 'gzip' - * - * @see #uncompress(boolean) - * @return this request - */ - public HttpRequest acceptGzipEncoding() { - return acceptEncoding(ENCODING_GZIP); - } - - /** - * Set the 'Accept-Charset' header to given value - * - * @param acceptCharset - * @return this request - */ - public HttpRequest acceptCharset(final String acceptCharset) { - return header(HEADER_ACCEPT_CHARSET, acceptCharset); - } - - /** - * Get the 'Content-Encoding' header from the response - * - * @return this request - */ - public String contentEncoding() { - return header(HEADER_CONTENT_ENCODING); - } - - /** - * Get the 'Server' header from the response - * - * @return server - */ - public String server() { - return header(HEADER_SERVER); - } - - /** - * Get the 'Date' header from the response - * - * @return date value, -1 on failures - */ - public long date() { - return dateHeader(HEADER_DATE); - } - - /** - * Get the 'Cache-Control' header from the response - * - * @return cache control - */ - public String cacheControl() { - return header(HEADER_CACHE_CONTROL); - } - - /** - * Get the 'ETag' header from the response - * - * @return entity tag - */ - public String eTag() { - return header(HEADER_ETAG); - } - - /** - * Get the 'Expires' header from the response - * - * @return expires value, -1 on failures - */ - public long expires() { - return dateHeader(HEADER_EXPIRES); - } - - /** - * Get the 'Last-Modified' header from the response - * - * @return last modified value, -1 on failures - */ - public long lastModified() { - return dateHeader(HEADER_LAST_MODIFIED); - } - - /** - * Get the 'Location' header from the response - * - * @return location - */ - public String location() { - return header(HEADER_LOCATION); - } - - /** - * Set the 'Authorization' header to given value - * - * @param authorization - * @return this request - */ - public HttpRequest authorization(final String authorization) { - return header(HEADER_AUTHORIZATION, authorization); - } - - /** - * Set the 'Proxy-Authorization' header to given value - * - * @param proxyAuthorization - * @return this request - */ - public HttpRequest proxyAuthorization(final String proxyAuthorization) { - return header(HEADER_PROXY_AUTHORIZATION, proxyAuthorization); - } - - /** - * Set the 'Authorization' header to given values in Basic authentication - * format - * - * @param name - * @param password - * @return this request - */ - public HttpRequest basic(final String name, final String password) { - return authorization("Basic " + Base64.encode(name + ':' + password)); - } - - /** - * Set the 'Proxy-Authorization' header to given values in Basic authentication - * format - * - * @param name - * @param password - * @return this request - */ - public HttpRequest proxyBasic(final String name, final String password) { - return proxyAuthorization("Basic " + Base64.encode(name + ':' + password)); - } - - /** - * Set the 'If-Modified-Since' request header to the given value - * - * @param ifModifiedSince - * @return this request - */ - public HttpRequest ifModifiedSince(final long ifModifiedSince) { - getConnection().setIfModifiedSince(ifModifiedSince); - return this; - } - - /** - * Set the 'If-None-Match' request header to the given value - * - * @param ifNoneMatch - * @return this request - */ - public HttpRequest ifNoneMatch(final String ifNoneMatch) { - return header(HEADER_IF_NONE_MATCH, ifNoneMatch); - } - - /** - * Set the 'Content-Type' request header to the given value - * - * @param contentType - * @return this request - */ - public HttpRequest contentType(final String contentType) { - return contentType(contentType, null); - } - - /** - * Set the 'Content-Type' request header to the given value and charset - * - * @param contentType - * @param charset - * @return this request - */ - public HttpRequest contentType(final String contentType, final String charset) { - if (charset != null && charset.length() > 0) { - final String separator = "; " + PARAM_CHARSET + '='; - return header(HEADER_CONTENT_TYPE, contentType + separator + charset); - } else - return header(HEADER_CONTENT_TYPE, contentType); - } - - /** - * Get the 'Content-Type' header from the response - * - * @return response header value - */ - public String contentType() { - return header(HEADER_CONTENT_TYPE); - } - - /** - * Get the 'Content-Length' header from the response - * - * @return response header value - */ - public int contentLength() { - return intHeader(HEADER_CONTENT_LENGTH); - } - - /** - * Set the 'Content-Length' request header to the given value - * - * @param contentLength - * @return this request - */ - public HttpRequest contentLength(final String contentLength) { - return contentLength(Integer.parseInt(contentLength)); - } - - /** - * Set the 'Content-Length' request header to the given value - * - * @param contentLength - * @return this request - */ - public HttpRequest contentLength(final int contentLength) { - getConnection().setFixedLengthStreamingMode(contentLength); - return this; - } - - /** - * Set the 'Accept' header to given value - * - * @param accept - * @return this request - */ - public HttpRequest accept(final String accept) { - return header(HEADER_ACCEPT, accept); - } - - /** - * Set the 'Accept' header to 'application/json' - * - * @return this request - */ - public HttpRequest acceptJson() { - return accept(CONTENT_TYPE_JSON); - } - - /** - * Copy from input stream to output stream - * - * @param input - * @param output - * @return this request - * @throws java.io.IOException - */ - protected HttpRequest copy(final InputStream input, final OutputStream output) - throws IOException { - return new CloseOperation(input, ignoreCloseExceptions) { - - @Override - public HttpRequest run() throws IOException { - final byte[] buffer = new byte[bufferSize]; - int read; - while ((read = input.read(buffer)) != -1) { - output.write(buffer, 0, read); - totalWritten += read; - progress.onUpload(totalWritten, totalSize); - } - return HttpRequest.this; - } - }.call(); - } - - /** - * Copy from reader to writer - * - * @param input - * @param output - * @return this request - * @throws java.io.IOException - */ - protected HttpRequest copy(final Reader input, final Writer output) - throws IOException { - return new CloseOperation(input, ignoreCloseExceptions) { - - @Override - public HttpRequest run() throws IOException { - final char[] buffer = new char[bufferSize]; - int read; - while ((read = input.read(buffer)) != -1) { - output.write(buffer, 0, read); - totalWritten += read; - progress.onUpload(totalWritten, -1); - } - return HttpRequest.this; - } - }.call(); - } - - /** - * Set the UploadProgress callback for this request - * - * @param callback - * @return this request - */ - public HttpRequest progress(final UploadProgress callback) { - if (callback == null) - progress = UploadProgress.DEFAULT; - else - progress = callback; - return this; - } - - private HttpRequest incrementTotalSize(final long size) { - if (totalSize == -1) - totalSize = 0; - totalSize += size; - return this; - } - - /** - * Close output stream - * - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - * @throws java.io.IOException - */ - protected HttpRequest closeOutput() throws IOException { - progress(null); - if (output == null) - return this; - if (multipart) - output.write(CRLF + "--" + BOUNDARY + "--" + CRLF); - if (ignoreCloseExceptions) - try { - output.close(); - } catch (IOException ignored) { - // Ignored - } - else - output.close(); - output = null; - return this; - } - - /** - * Call {@link #closeOutput()} and re-throw a caught {@link java.io.IOException}s as - * an {@link com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException} - * - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - protected HttpRequest closeOutputQuietly() throws HttpRequestException { - try { - return closeOutput(); - } catch (IOException e) { - throw new HttpRequestException(e); - } - } - - /** - * Open output stream - * - * @return this request - * @throws java.io.IOException - */ - protected HttpRequest openOutput() throws IOException { - if (output != null) - return this; - getConnection().setDoOutput(true); - final String charset = getParam( - getConnection().getRequestProperty(HEADER_CONTENT_TYPE), PARAM_CHARSET); - output = new RequestOutputStream(getConnection().getOutputStream(), charset, - bufferSize); - return this; - } - - /** - * Start part of a multipart - * - * @return this request - * @throws java.io.IOException - */ - protected HttpRequest startPart() throws IOException { - if (!multipart) { - multipart = true; - contentType(CONTENT_TYPE_MULTIPART).openOutput(); - output.write("--" + BOUNDARY + CRLF); - } else - output.write(CRLF + "--" + BOUNDARY + CRLF); - return this; - } - - /** - * Write part header - * - * @param name - * @param filename - * @return this request - * @throws java.io.IOException - */ - protected HttpRequest writePartHeader(final String name, final String filename) - throws IOException { - return writePartHeader(name, filename, null); - } - - /** - * Write part header - * - * @param name - * @param filename - * @param contentType - * @return this request - * @throws java.io.IOException - */ - protected HttpRequest writePartHeader(final String name, - final String filename, final String contentType) throws IOException { - final StringBuilder partBuffer = new StringBuilder(); - partBuffer.append("form-data; name=\"").append(name); - if (filename != null) - partBuffer.append("\"; filename=\"").append(filename); - partBuffer.append('"'); - partHeader("Content-Disposition", partBuffer.toString()); - if (contentType != null) - partHeader(HEADER_CONTENT_TYPE, contentType); - return send(CRLF); - } - - /** - * Write part of a multipart request to the request body - * - * @param name - * @param part - * @return this request - */ - public HttpRequest part(final String name, final String part) { - return part(name, null, part); - } - - /** - * Write part of a multipart request to the request body - * - * @param name - * @param filename - * @param part - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest part(final String name, final String filename, - final String part) throws HttpRequestException { - return part(name, filename, null, part); - } - - /** - * Write part of a multipart request to the request body - * - * @param name - * @param filename - * @param contentType - * value of the Content-Type part header - * @param part - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest part(final String name, final String filename, - final String contentType, final String part) throws HttpRequestException { - try { - startPart(); - writePartHeader(name, filename, contentType); - output.write(part); - } catch (IOException e) { - throw new HttpRequestException(e); - } - return this; - } - - /** - * Write part of a multipart request to the request body - * - * @param name - * @param part - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest part(final String name, final Number part) - throws HttpRequestException { - return part(name, null, part); - } - - /** - * Write part of a multipart request to the request body - * - * @param name - * @param filename - * @param part - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest part(final String name, final String filename, - final Number part) throws HttpRequestException { - return part(name, filename, part != null ? part.toString() : null); - } - - /** - * Write part of a multipart request to the request body - * - * @param name - * @param part - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest part(final String name, final File part) - throws HttpRequestException { - return part(name, null, part); - } - - /** - * Write part of a multipart request to the request body - * - * @param name - * @param filename - * @param part - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest part(final String name, final String filename, - final File part) throws HttpRequestException { - return part(name, filename, null, part); - } - - /** - * Write part of a multipart request to the request body - * - * @param name - * @param filename - * @param contentType - * value of the Content-Type part header - * @param part - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest part(final String name, final String filename, - final String contentType, final File part) throws HttpRequestException { - final InputStream stream; - try { - stream = new BufferedInputStream(new FileInputStream(part)); - incrementTotalSize(part.length()); - } catch (IOException e) { - throw new HttpRequestException(e); - } - return part(name, filename, contentType, stream); - } - - /** - * Write part of a multipart request to the request body - * - * @param name - * @param part - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest part(final String name, final InputStream part) - throws HttpRequestException { - return part(name, null, null, part); - } - - /** - * Write part of a multipart request to the request body - * - * @param name - * @param filename - * @param contentType - * value of the Content-Type part header - * @param part - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest part(final String name, final String filename, - final String contentType, final InputStream part) - throws HttpRequestException { - try { - startPart(); - writePartHeader(name, filename, contentType); - copy(part, output); - } catch (IOException e) { - throw new HttpRequestException(e); - } - return this; - } - - /** - * Write a multipart header to the response body - * - * @param name - * @param value - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest partHeader(final String name, final String value) - throws HttpRequestException { - return send(name).send(": ").send(value).send(CRLF); - } - - /** - * Write contents of file to request body - * - * @param input - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest send(final File input) throws HttpRequestException { - final InputStream stream; - try { - stream = new BufferedInputStream(new FileInputStream(input)); - incrementTotalSize(input.length()); - } catch (FileNotFoundException e) { - throw new HttpRequestException(e); - } - return send(stream); - } - - /** - * Write byte array to request body - * - * @param input - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest send(final byte[] input) throws HttpRequestException { - if (input != null) - incrementTotalSize(input.length); - return send(new ByteArrayInputStream(input)); - } - - /** - * Write stream to request body - *

- * The given stream will be closed once sending completes - * - * @param input - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest send(final InputStream input) throws HttpRequestException { - try { - openOutput(); - copy(input, output); - } catch (IOException e) { - throw new HttpRequestException(e); - } - return this; - } - - /** - * Write reader to request body - *

- * The given reader will be closed once sending completes - * - * @param input - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest send(final Reader input) throws HttpRequestException { - try { - openOutput(); - } catch (IOException e) { - throw new HttpRequestException(e); - } - final Writer writer = new OutputStreamWriter(output, - output.encoder.charset()); - return new FlushOperation(writer) { - - @Override - protected HttpRequest run() throws IOException { - return copy(input, writer); - } - }.call(); - } - - /** - * Write char sequence to request body - *

- * The charset configured via {@link #contentType(String)} will be used and - * UTF-8 will be used if it is unset. - * - * @param value - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest send(final CharSequence value) throws HttpRequestException { - try { - openOutput(); - output.write(value.toString()); - } catch (IOException e) { - throw new HttpRequestException(e); - } - return this; - } - - /** - * Create writer to request output stream - * - * @return writer - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public OutputStreamWriter writer() throws HttpRequestException { - try { - openOutput(); - return new OutputStreamWriter(output, output.encoder.charset()); - } catch (IOException e) { - throw new HttpRequestException(e); - } - } - - /** - * Write the values in the map as form data to the request body - *

- * The pairs specified will be URL-encoded in UTF-8 and sent with the - * 'application/x-www-form-urlencoded' content-type - * - * @param values - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest form(final Map values) throws HttpRequestException { - return form(values, CHARSET_UTF8); - } - - /** - * Write the key and value in the entry as form data to the request body - *

- * The pair specified will be URL-encoded in UTF-8 and sent with the - * 'application/x-www-form-urlencoded' content-type - * - * @param entry - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest form(final Entry entry) throws HttpRequestException { - return form(entry, CHARSET_UTF8); - } - - /** - * Write the key and value in the entry as form data to the request body - *

- * The pair specified will be URL-encoded and sent with the - * 'application/x-www-form-urlencoded' content-type - * - * @param entry - * @param charset - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest form(final Entry entry, final String charset) - throws HttpRequestException { - return form(entry.getKey(), entry.getValue(), charset); - } - - /** - * Write the name/value pair as form data to the request body - *

- * The pair specified will be URL-encoded in UTF-8 and sent with the - * 'application/x-www-form-urlencoded' content-type - * - * @param name - * @param value - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest form(final Object name, final Object value) - throws HttpRequestException { - return form(name, value, CHARSET_UTF8); - } - - /** - * Write the name/value pair as form data to the request body - *

- * The values specified will be URL-encoded and sent with the - * 'application/x-www-form-urlencoded' content-type - * - * @param name - * @param value - * @param charset - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest form(final Object name, final Object value, String charset) - throws HttpRequestException { - final boolean first = !form; - if (first) { - contentType(CONTENT_TYPE_FORM, charset); - form = true; - } - charset = getValidCharset(charset); - try { - openOutput(); - if (!first) - output.write('&'); - output.write(URLEncoder.encode(name.toString(), charset)); - output.write('='); - if (value != null) - output.write(URLEncoder.encode(value.toString(), charset)); - } catch (IOException e) { - throw new HttpRequestException(e); + public String method() { + return getConnection().getRequestMethod(); } - return this; - } - - /** - * Write the values in the map as encoded form data to the request body - * - * @param values - * @param charset - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest form(final Map values, final String charset) - throws HttpRequestException { - if (!values.isEmpty()) - for (Entry entry : values.entrySet()) - form(entry, charset); - return this; - } - - /** - * Configure HTTPS connection to trust all certificates - *

- * This method does nothing if the current request is not a HTTPS request - * - * @return this request - * @throws com.terracom.qrpttbeta.servers.HttpRequest.HttpRequestException - */ - public HttpRequest trustAllCerts() throws HttpRequestException { - final HttpURLConnection connection = getConnection(); - if (connection instanceof HttpsURLConnection) - ((HttpsURLConnection) connection) - .setSSLSocketFactory(getTrustedFactory()); - return this; - } - - /** - * Configure HTTPS connection to trust all hosts using a custom - * {@link javax.net.ssl.HostnameVerifier} that always returns true for each - * host verified - *

- * This method does nothing if the current request is not a HTTPS request - * - * @return this request - */ - public HttpRequest trustAllHosts() { - final HttpURLConnection connection = getConnection(); - if (connection instanceof HttpsURLConnection) - ((HttpsURLConnection) connection) - .setHostnameVerifier(getTrustedVerifier()); - return this; - } - - /** - * Get the {@link java.net.URL} of this request's connection - * - * @return request URL - */ - public URL url() { - return getConnection().getURL(); - } - - /** - * Get the HTTP method of this request - * - * @return method - */ - public String method() { - return getConnection().getRequestMethod(); - } - - /** - * Configure an HTTP proxy on this connection. Use {{@link #proxyBasic(String, String)} if - * this proxy requires basic authentication. - * - * @param proxyHost - * @param proxyPort - * @return this request - */ - public HttpRequest useProxy(final String proxyHost, final int proxyPort) { - if (connection != null) - throw new IllegalStateException("The connection has already been created. This method must be called before reading or writing to the request."); - - this.httpProxyHost = proxyHost; - this.httpProxyPort = proxyPort; - return this; - } - - /** - * Set whether or not the underlying connection should follow redirects in - * the response. - * - * @param followRedirects - true fo follow redirects, false to not. - * @return this request - */ - public HttpRequest followRedirects(final boolean followRedirects) { - getConnection().setInstanceFollowRedirects(followRedirects); - return this; - } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/terracom/qrpttbeta/servers/PublicServerAdapter.java b/app/src/main/java/com/terracom/qrpttbeta/servers/PublicServerAdapter.java deleted file mode 100644 index cee2447c..00000000 --- a/app/src/main/java/com/terracom/qrpttbeta/servers/PublicServerAdapter.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.terracom.qrpttbeta.servers; - -import android.content.Context; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.terracom.jumble.model.Server; -import com.terracom.qrpttbeta.R; -import com.terracom.qrpttbeta.db.PublicServer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -/** -* Created by andrew on 07/05/14. -*/ -public class PublicServerAdapter extends ServerAdapter { - private List mUnfilteredServers; - private PublicServerAdapterMenuListener mListener; - - public PublicServerAdapter(Context context, List servers, PublicServerAdapterMenuListener listener) { - super(context, R.layout.public_server_list_row, servers); - mUnfilteredServers = new ArrayList(servers); - mListener = listener; - } - - public void filter(String queryName, String queryCountry) { - clear(); - - for(PublicServer server : mUnfilteredServers) { - String serverName = server.getName() != null ? server.getName().toUpperCase(Locale.US) : ""; - String serverCountry = server.getCountry() != null ? server.getCountry().toUpperCase(Locale.US) : ""; - - if(serverName.contains(queryName) && serverCountry.contains(queryCountry)) - add(server); - } - } - - @Override - public View getView(int position, View v, ViewGroup parent) { - View view = super.getView(position, v, parent); - - final PublicServer server = getItem(position); - - TextView locationText = (TextView) view.findViewById(R.id.server_row_location); - locationText.setText(server.getCountry()); - - return view; - } - - @Override - public int getPopupMenuResource() { - return R.menu.popup_public_server; - } - - @Override - public boolean onPopupItemClick(Server server, MenuItem menuItem) { - switch (menuItem.getItemId()) { - case R.id.menu_server_favourite: - mListener.favouriteServer(server); - return true; - default: - return false; - } - } - - public static interface PublicServerAdapterMenuListener { - public void favouriteServer(Server server); - } -} diff --git a/app/src/main/java/com/terracom/qrpttbeta/servers/PublicServerFetchTask.java b/app/src/main/java/com/terracom/qrpttbeta/servers/PublicServerFetchTask.java deleted file mode 100644 index 99577875..00000000 --- a/app/src/main/java/com/terracom/qrpttbeta/servers/PublicServerFetchTask.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.terracom.qrpttbeta.servers; - -import android.os.AsyncTask; -import android.util.Xml; - -import com.terracom.qrpttbeta.db.PublicServer; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.ProtocolException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -/** - * Created by andrew on 05/05/14. - */ -class PublicServerFetchTask extends AsyncTask> { - - private static final String MUMBLE_PUBLIC_URL = "http://mumble.info/list2.cgi"; - - @Override - protected List doInBackground(Void... params) { - try { - // Fetch XML from server - URL url = new URL(MUMBLE_PUBLIC_URL); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - connection.addRequestProperty("version", com.terracom.jumble.Constants.PROTOCOL_STRING); - connection.connect(); - InputStream stream = connection.getInputStream(); - - XmlPullParser parser = Xml.newPullParser(); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); - parser.setInput(stream, "UTF-8"); - parser.nextTag(); - - List serverList = new ArrayList(); - - parser.require(XmlPullParser.START_TAG, null, "servers"); - while(parser.next() != XmlPullParser.END_TAG) { - if (parser.getEventType() != XmlPullParser.START_TAG) { - continue; - } - - serverList.add(readEntry(parser)); - } - parser.require(XmlPullParser.END_TAG, null, "servers"); - - return serverList; - } catch (XmlPullParserException e) { - e.printStackTrace(); - } catch (ProtocolException e) { - e.printStackTrace(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } - - private PublicServer readEntry(XmlPullParser parser) throws XmlPullParserException, IOException { - String name = parser.getAttributeValue(null, "name"); - String ca = parser.getAttributeValue(null, "ca"); - String continentCode = parser.getAttributeValue(null, "continent_code"); - String country = parser.getAttributeValue(null, "country"); - String countryCode = parser.getAttributeValue(null, "country_code"); - String ip = parser.getAttributeValue(null, "ip"); - String port = parser.getAttributeValue(null, "port"); - String region = parser.getAttributeValue(null, "region"); - String url = parser.getAttributeValue(null, "url"); - - parser.nextTag(); - - PublicServer server = new PublicServer(name, ca, continentCode, country, countryCode, ip, Integer.parseInt(port), region, url); - - return server; - } -} diff --git a/app/src/main/java/com/terracom/qrpttbeta/servers/PublicServerListFragment.java b/app/src/main/java/com/terracom/qrpttbeta/servers/PublicServerListFragment.java deleted file mode 100644 index 36868e4d..00000000 --- a/app/src/main/java/com/terracom/qrpttbeta/servers/PublicServerListFragment.java +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.terracom.qrpttbeta.servers; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Build.VERSION; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.view.inputmethod.EditorInfo; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.GridView; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; - -import com.terracom.jumble.model.Server; -import com.terracom.qrpttbeta.R; -import com.terracom.qrpttbeta.Settings; -import com.terracom.qrpttbeta.db.DatabaseProvider; -import com.terracom.qrpttbeta.db.QRPushToTalkDatabase; -import com.terracom.qrpttbeta.db.PublicServer; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * Displays a list of public servers that can be connected to, sorted, and favourited. - * @author terracom - * - */ -public class PublicServerListFragment extends Fragment implements OnItemClickListener, PublicServerAdapter.PublicServerAdapterMenuListener { - - private FavouriteServerListFragment.ServerConnectHandler mConnectHandler; - private DatabaseProvider mDatabaseProvider; - private List mServers; - private GridView mServerGrid; - private ProgressBar mServerProgress; - private PublicServerAdapter mServerAdapter; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setHasOptionsMenu(true); - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - - try { - mConnectHandler = (FavouriteServerListFragment.ServerConnectHandler)activity; - mDatabaseProvider = (DatabaseProvider) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString()+" must implement ServerConnectHandler and DatabaseProvider!"); - } - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - fillPublicList(); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_public_server_list, container, false); - mServerGrid = (GridView) view.findViewById(R.id.server_list_grid); - mServerGrid.setOnItemClickListener(this); - if(mServerAdapter != null) - mServerGrid.setAdapter(mServerAdapter); - mServerProgress = (ProgressBar) view.findViewById(R.id.serverProgress); - mServerProgress.setVisibility(mServerAdapter == null ? View.VISIBLE : View.GONE); - return view; - } - - @Override - public void onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - menu.findItem(R.id.menu_match_server).setVisible(VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB); // Executors only supported on Honeycomb + - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.fragment_public_server_list, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (isFilled()) { - switch(item.getItemId()) { - case R.id.menu_match_server: - showMatchDialog(); - break; - case R.id.menu_sort_server_item: - showSortDialog(); - return true; - case R.id.menu_search_server_item: - showFilterDialog(); - return true; - } - } - return super.onOptionsItemSelected(item); - } - - @Override - public void favouriteServer(final Server server) { - final Settings settings = Settings.getInstance(getActivity()); - final EditText usernameField = new EditText(getActivity()); - usernameField.setHint(settings.getDefaultUsername()); - AlertDialog.Builder adb = new AlertDialog.Builder(getActivity()); - adb.setTitle(R.string.addFavorite); - adb.setView(usernameField); - adb.setPositiveButton(R.string.add, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if(usernameField.getText().length() > 0) { - server.setUsername(usernameField.getText().toString()); - } else { - server.setUsername(settings.getDefaultUsername()); - } - QRPushToTalkDatabase database = mDatabaseProvider.getDatabase(); - database.addServer(server); - } - }); - adb.setNegativeButton(android.R.string.cancel, null); - adb.show(); - } - - public void setServers(List servers) { - mServers = servers; - mServerProgress.setVisibility(View.GONE); - mServerAdapter = new PublicServerAdapter(getActivity(), servers, this); - mServerGrid.setAdapter(mServerAdapter); - } - - public boolean isFilled() { - return mServerAdapter != null; - } - - private void showMatchDialog() { - AlertDialog.Builder adb = new AlertDialog.Builder(getActivity()); - adb.setTitle(R.string.server_match); - adb.setMessage(R.string.server_match_description); - adb.setPositiveButton(R.string.search, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - findOptimalServer(); - } - }); - adb.setNegativeButton(android.R.string.cancel, null); - adb.show(); - } - - private void findOptimalServer() { - MatchServerTask matchServerTask = new MatchServerTask(); - matchServerTask.execute(Locale.getDefault().getCountry()); - } - - private void showSortDialog() { - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); - alertBuilder.setTitle(R.string.sortBy); - alertBuilder.setItems(new String[] { getString(R.string.name), getString(R.string.country)}, new SortClickListener()); - alertBuilder.show(); - } - - private void showFilterDialog() { - View dialogView = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.dialog_server_search, null); - final EditText nameText = (EditText) dialogView.findViewById(R.id.server_search_name); - final EditText countryText = (EditText) dialogView.findViewById(R.id.server_search_country); - - final AlertDialog dlg = new AlertDialog.Builder(getActivity()). - setTitle(R.string.search). - setView(dialogView). - setPositiveButton(R.string.search, new DialogInterface.OnClickListener() { - public void onClick(final DialogInterface dialog, final int which) - { - String queryName = nameText.getText().toString().toUpperCase(Locale.US); - String queryCountry = countryText.getText().toString().toUpperCase(Locale.US); - mServerAdapter.filter(queryName, queryCountry); - dialog.dismiss(); - } - }).create(); - - nameText.setImeOptions(EditorInfo.IME_ACTION_SEARCH); - nameText.setOnEditorActionListener(new OnEditorActionListener() { - @Override - public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) - { - String queryName = nameText.getText().toString().toUpperCase(Locale.US); - String queryCountry = countryText.getText().toString().toUpperCase(Locale.US); - mServerAdapter.filter(queryName, queryCountry); - dlg.dismiss(); - return true; - } - }); - - countryText.setImeOptions(EditorInfo.IME_ACTION_SEARCH); - countryText.setOnEditorActionListener(new OnEditorActionListener() { - @Override - public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) - { - String queryName = nameText.getText().toString().toUpperCase(Locale.US); - String queryCountry = countryText.getText().toString().toUpperCase(Locale.US); - mServerAdapter.filter(queryName, queryCountry); - dlg.dismiss(); - return true; - } - }); - - // Show keyboard automatically - nameText.setOnFocusChangeListener(new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) { - dlg.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); - } - } - }); - - dlg.show(); - } - - @Override - public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { - mConnectHandler.connectToPublicServer(mServerAdapter.getItem(arg2)); - } - - private void fillPublicList() { - new PublicServerFetchTask() { - protected void onPostExecute(List result) { - super.onPostExecute(result); - - if (result == null) { - // Handle error - //Toast.makeText(getActivity(), R.string.error_fetching_servers, Toast.LENGTH_SHORT).show(); - return; - } - - if(isVisible()) // Prevents NPEs when fragment is detached. - setServers(result); - }; - }.execute(); - } - - private class SortClickListener implements DialogInterface.OnClickListener { - - private static final int SORT_NAME = 0; - private static final int SORT_COUNTRY = 1; - - private Comparator nameComparator = new Comparator() { - @Override - public int compare(PublicServer lhs, PublicServer rhs) { - return lhs.getName().compareTo(rhs.getName()); - } - }; - - private Comparator countryComparator = new Comparator() { - @Override - public int compare(PublicServer lhs, PublicServer rhs) { - if(rhs.getCountry() == null) return -1; - else if(lhs.getCountry() == null) return 1; - return lhs.getCountry().compareTo(rhs.getCountry()); - } - }; - - - @Override - public void onClick(DialogInterface dialog, int which) { - ArrayAdapter arrayAdapter = mServerAdapter; - if(which == SORT_NAME) { - arrayAdapter.sort(nameComparator); - } else if(which == SORT_COUNTRY) { - arrayAdapter.sort(countryComparator); - } - } - } - - /** - * Finds an empty server in the user's country code with low latency. - * By default, it will show a ProgressDialog while it performs this and an AlertDialog allowing the user to connect. - */ - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - private class MatchServerTask extends AsyncTask { - - /** - * Query until we find up to SEARCH_RANGE empty servers that meet the zero user and location requirements. - * Once we have that, then we'll sort them based on latency. - * TODO make this a user-changeable option. - */ - public static final int SEARCH_RANGE = 20; - - private Comparator mLatencyComparator = new Comparator() { - @Override - public int compare(ServerInfoResponse lhs, ServerInfoResponse rhs) { - return lhs.getLatency() == rhs.getLatency() ? 0 : - lhs.getLatency() < rhs.getLatency() ? -1 : 1; - } - }; - - private class MatchServerInfoTask extends ServerInfoTask { - @Override - protected void onPostExecute(ServerInfoResponse serverInfoResponse) { - mResponseCount++; - if(serverInfoResponse == null) { - // TODO handle bad responses - } else if(serverInfoResponse.getCurrentUsers() == 0 && - serverInfoResponse.getVersion() == com.terracom.jumble.Constants.PROTOCOL_VERSION) { - mGoodResponses.add(serverInfoResponse); - } - - // Once we have a good sample of results, shut down the ping threads. - if(mResponseCount >= mResponsesToSend) { - synchronized (mLock) { - mLock.notify(); - } - mPingExecutor.shutdownNow(); - } - } - - } - - private ExecutorService mPingExecutor = Executors.newFixedThreadPool(5); // Run 5 concurrent pings at a time - private Object mLock = new Object(); - - private List mGoodResponses = Collections.synchronizedList(new ArrayList()); - private volatile int mResponseCount = 0; - private int mResponsesToSend = SEARCH_RANGE; - - private ProgressDialog mProgressDialog; - - @Override - protected void onPreExecute() { - super.onPreExecute(); - mProgressDialog = ProgressDialog.show(getActivity(), null, getString(R.string.server_match_progress)); - mProgressDialog.setCancelable(true); - mProgressDialog.setCanceledOnTouchOutside(true); - mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - cancel(true); - } - }); - } - - @Override - protected ServerInfoResponse doInBackground(String... params) { - final String country = params.length > 0 ? params[0] : null; // If a country is provided, search within country - - Collection servers; - if(country != null) { - servers = new LinkedList(); - for (PublicServer server : mServers) { - if (country.equals(server.getCountryCode())) { - servers.add(server); - } - } - } else { - servers = mServers; - } - - // For countries with 0 servers, immediately return null. - if(servers.size() == 0) - return null; - - // If there are less servers than the value of our range, deal with it. - mResponsesToSend = Math.min(SEARCH_RANGE, servers.size()); - - Iterator iterator = servers.iterator(); - while(iterator.hasNext() && mGoodResponses.size() < mResponsesToSend) { - PublicServer server = (PublicServer) iterator.next(); - new MatchServerInfoTask().executeOnExecutor(mPingExecutor, server); - } - try { - synchronized (mLock) { - mLock.wait(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - - Collections.sort(mGoodResponses, mLatencyComparator); - - if(mGoodResponses.size() > 0) - return mGoodResponses.get(0); - else - return null; - } - - @Override - protected void onPostExecute(ServerInfoResponse response) { - super.onPostExecute(response); - final PublicServer publicServer = response == null ? null : (PublicServer) response.getServer(); - mProgressDialog.hide(); - - AlertDialog.Builder adb = new AlertDialog.Builder(getActivity()); - if(publicServer != null) { - adb.setTitle(R.string.server_match_found); - adb.setMessage(getString(R.string.server_match_info, - publicServer.getName(), - publicServer.getHost(), - publicServer.getPort(), - response.getCurrentUsers(), - response.getMaximumUsers(), - response.getVersionString(), - publicServer.getCountry(), - response.getLatency())); - adb.setPositiveButton(R.string.connect, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mConnectHandler.connectToPublicServer(publicServer); - } - }); - } else { - adb.setTitle(R.string.server_match_not_found); - adb.setMessage(R.string.server_match_expand_country); - adb.setPositiveButton(R.string.expand, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - MatchServerTask matchTask = new MatchServerTask(); - matchTask.execute(); - } - }); - } - adb.setNegativeButton(android.R.string.cancel, null); - adb.show(); - } - } -} diff --git a/app/src/main/java/com/terracom/qrpttbeta/servers/ServerAdapter.java b/app/src/main/java/com/terracom/qrpttbeta/servers/ServerAdapter.java old mode 100644 new mode 100755 index 401f94d8..270ec587 --- a/app/src/main/java/com/terracom/qrpttbeta/servers/ServerAdapter.java +++ b/app/src/main/java/com/terracom/qrpttbeta/servers/ServerAdapter.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.servers; import android.content.Context; @@ -37,9 +20,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -/** - * Created by andrew on 05/05/14. - */ public abstract class ServerAdapter extends ArrayAdapter { private static final int MAX_ACTIVE_PINGS = 50; @@ -61,7 +41,7 @@ public long getItemId(int position) { public View getView(int position, View v, ViewGroup parent) { View view = v; - if(v == null) { + if (v == null) { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(mViewResource, parent, false); } @@ -69,21 +49,18 @@ public View getView(int position, View v, ViewGroup parent) { final E server = getItem(position); ServerInfoResponse infoResponse = mInfoResponses.get(server); - // If there is a null value for the server info (rather than none at all), the request must have failed. boolean requestExists = infoResponse != null; boolean requestFailure = infoResponse != null && infoResponse.isDummy(); TextView nameText = (TextView) view.findViewById(R.id.server_row_name); TextView userText = (TextView) view.findViewById(R.id.server_row_user); - TextView addressText = (TextView) view.findViewById(R.id.server_row_address); nameText.setText(server.getName()); - if(userText != null) userText.setText(server.getUsername()); - //if(addressText != null) addressText.setText(server.getHost()+":"+server.getPort()); + if (userText != null) userText.setText(server.getUsername()); final ImageView moreButton = (ImageView) view.findViewById(R.id.server_row_more); - if(moreButton != null) { + if (moreButton != null) { moreButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -99,23 +76,19 @@ public void onClick(View v) { serverVersionText.setVisibility(!requestExists ? View.INVISIBLE : View.VISIBLE); serverUsersText.setVisibility(!requestExists ? View.INVISIBLE : View.VISIBLE); - //serverLatencyText.setVisibility(!requestExists ? View.INVISIBLE : View.VISIBLE); serverInfoProgressBar.setVisibility(!requestExists ? View.VISIBLE : View.INVISIBLE); - if(infoResponse != null && !requestFailure) { - //serverVersionText.setText(getContext().getString(R.string.online)+" ("+infoResponse.getVersionString()+")"); - serverVersionText.setText("Status: "+getContext().getString(R.string.online)+" "); - serverUsersText.setText("Users: "+infoResponse.getCurrentUsers()+"/"+infoResponse.getMaximumUsers()); - serverLatencyText.setText(infoResponse.getLatency()+"ms"); - } else if(requestFailure) { - // serverVersionText.setText("Status: "+"Offline "); h +getContext().getString(R.string.offline) + if (infoResponse != null && !requestFailure) { + serverVersionText.setText("Status: " + getContext().getString(R.string.online) + " "); + serverUsersText.setText("Users: " + infoResponse.getCurrentUsers() + "/" + infoResponse.getMaximumUsers()); + serverLatencyText.setText(infoResponse.getLatency() + "ms"); + } else if (requestFailure) { serverVersionText.setText("Status: Offline"); serverUsersText.setText(""); serverLatencyText.setText(""); } - // Ping server if available - if(infoResponse == null) { + if (infoResponse == null) { ServerInfoTask task = new ServerInfoTask() { protected void onPostExecute(ServerInfoResponse result) { super.onPostExecute(result); @@ -124,8 +97,7 @@ protected void onPostExecute(ServerInfoResponse result) { } }; - // Execute on parallel threads if API >= 11. - if(Build.VERSION.SDK_INT >= 11) { + if (Build.VERSION.SDK_INT >= 11) { task.executeOnExecutor(mPingExecutor, server); } else { task.execute(server); @@ -148,5 +120,6 @@ public boolean onMenuItemClick(MenuItem menuItem) { } public abstract int getPopupMenuResource(); + public abstract boolean onPopupItemClick(Server server, MenuItem menuItem); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/servers/ServerEditFragment.java b/app/src/main/java/com/terracom/qrpttbeta/servers/ServerEditFragment.java old mode 100644 new mode 100755 index a4d40b04..ffb3214d --- a/app/src/main/java/com/terracom/qrpttbeta/servers/ServerEditFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/servers/ServerEditFragment.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.servers; import android.app.Activity; @@ -27,13 +10,15 @@ import android.view.View; import android.widget.EditText; import android.widget.TextView; + import com.terracom.jumble.Constants; import com.terracom.jumble.model.Server; import com.terracom.qrpttbeta.R; -import com.terracom.qrpttbeta.Settings; import com.terracom.qrpttbeta.db.DatabaseProvider; + import org.json.JSONException; import org.json.JSONObject; + import java.util.Random; @@ -45,14 +30,12 @@ public class ServerEditFragment extends DialogFragment { private EditText mUsernameEdit; private EditText mPasswordEdit; private TextView mErrorText; - public String resultFromWebService = "Noresponseyet"; public String uname = ""; - public static String CompanyNameStr= ""; + public static String CompanyNameStr = ""; public String GuardAliasStr = ""; public String errorResultFromJsonStr = ""; public String errorMessageFromJsonStr = ""; - private ServerEditListener mListener; private DatabaseProvider mDatabaseProvider; @@ -60,69 +43,70 @@ public class ServerEditFragment extends DialogFragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setStyle(DialogFragment.STYLE_NO_TITLE, 0); - } @Override public void onAttach(Activity activity) { super.onAttach(activity); - try { mDatabaseProvider = (DatabaseProvider) activity; mListener = (ServerEditListener) activity; } catch (ClassCastException e) { - throw new ClassCastException(activity.toString()+" must implement DatabaseProvider and ServerEditListener!"); + throw new ClassCastException(activity.toString() + " must implement DatabaseProvider and ServerEditListener!"); } } @Override public void onStart() { super.onStart(); - mErrorText.setVisibility(View.VISIBLE); - mErrorText.setText("Pressing Add needs approximately 5 seconds to fetch data from server..."); - // Override positive button to not automatically dismiss on press. - // We can't accomplish this with AlertDialog.Builder. - ((AlertDialog)getDialog()).getButton(Dialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { + mErrorText.setText("Pressing Add may take some time to fetch data from server..."); + ((AlertDialog) getDialog()).getButton(Dialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getFormData(); + try { - Thread.sleep(6000); - resultFromWebService = resultFromWebService.replace("(",""); - resultFromWebService = resultFromWebService.replace(")",""); + + if (uname.equals("")) { + int failedAttempts = 0; + while (resultFromWebService.equals("Noresponseyet") && failedAttempts < 51) { + Thread.sleep(100); + failedAttempts++; + } + } else { + Thread.sleep(800); + } + + resultFromWebService = resultFromWebService.replace("(", ""); + resultFromWebService = resultFromWebService.replace(")", ""); try { JSONObject myjson = new JSONObject(resultFromWebService); errorResultFromJsonStr = myjson.get("result").toString(); errorMessageFromJsonStr = myjson.get("Message").toString(); - if(myjson.get("result").toString().equals("0")){ + if (myjson.get("result").toString().equals("0")) { JSONObject myjsondata = myjson.getJSONObject("data"); - CompanyNameStr = myjsondata.get("CompanyName").toString().replaceAll("\\s","").trim(); - GuardAliasStr = myjsondata.get("GuardAlias").toString().replaceAll("\\s","").trim(); - }else{ + CompanyNameStr = myjsondata.get("CompanyName").toString().replaceAll("\\s", "").trim(); + GuardAliasStr = myjsondata.get("GuardAlias").toString().replaceAll("\\s", "").trim(); + } else { CompanyNameStr = ""; } } catch (JSONException e) { CompanyNameStr = ""; e.printStackTrace(); } - } catch (InterruptedException e) { e.printStackTrace(); } if (validate()) { Server server = createServer(shouldSave()); - - // If we're not committing this server, connect immediately. if (!shouldSave()) mListener.connectToServer(server); - dismiss(); } } }); } - private class HttpAsyncTask extends AsyncTask { @Override @@ -130,7 +114,6 @@ protected String doInBackground(String... urls) { return WebserviceGet(urls[0]); } - // onPostExecute displays the results of the AsyncTask. @Override protected void onPostExecute(String resultAfterPost) { } @@ -138,28 +121,24 @@ protected void onPostExecute(String resultAfterPost) { public String WebserviceGet(String jsonGuard) { String kerverosString = "https://kerveroslive.com:29406/api/?data="; - try{ - HttpRequest req = HttpRequest.get(kerverosString+jsonGuard).trustAllCerts().trustAllHosts(); + try { + HttpRequest req = HttpRequest.get(kerverosString + jsonGuard).trustAllCerts().trustAllHosts(); resultFromWebService = req.trustAllCerts().trustAllHosts().body(); - resultFromWebService = resultFromWebService.replace("(",""); - resultFromWebService = resultFromWebService.replace(")",""); + resultFromWebService = resultFromWebService.replace("(", ""); + resultFromWebService = resultFromWebService.replace(")", ""); return resultFromWebService; - }catch(Exception e){ + } catch (Exception e) { return e.getMessage(); } } - @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder adb = new AlertDialog.Builder(getActivity()); - Settings settings = Settings.getInstance(getActivity()); - int actionTitle; if (shouldSave() && getServer() == null) { actionTitle = R.string.add; } else if (shouldSave()) { - //actionTitle = R.string.save; actionTitle = R.string.add; } else { actionTitle = R.string.connect; @@ -167,10 +146,8 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { adb.setPositiveButton(actionTitle, null); adb.setNegativeButton(android.R.string.cancel, null); - LayoutInflater inflater = LayoutInflater.from(getActivity()); View view = inflater.inflate(R.layout.dialog_server_edit, null, false); - mNameTitle = (TextView) view.findViewById(R.id.server_edit_name_title); mNameEdit = (EditText) view.findViewById(R.id.server_edit_name); mHostEdit = (EditText) view.findViewById(R.id.server_edit_host); @@ -192,11 +169,8 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { mNameEdit.setVisibility(View.GONE); } - // Fixes issues with text colour on light themes with pre-honeycomb devices. adb.setInverseBackgroundForced(true); - adb.setView(view); - return adb.create(); } @@ -208,11 +182,6 @@ private Server getServer() { return getArguments() != null ? (Server) getArguments().getParcelable("server") : null; } - /** - * Creates or updates a server with the information in this fragment. - * @param shouldCommit Whether to commit the created service to the DB. - * @return The new or updated server. - */ public Server createServer(boolean shouldCommit) { String name = (mNameEdit).getText().toString().trim(); String host = (mHostEdit).getText().toString().trim(); @@ -227,38 +196,35 @@ public Server createServer(boolean shouldCommit) { Server server; if (getServer() != null) { - String desktop= getString(R.string.desktop); + String desktop = getString(R.string.desktop); server = getServer(); server.setName(name); server.setHost(host); server.setPort(port); - if(!uname.equals("")){ + if (!uname.equals("")) { server.setUsername(uname); - }else{ + } else { server.setUsername(GuardAliasStr); } - server.setPassword(desktop); - if(shouldCommit) mDatabaseProvider.getDatabase().updateServer(server); + + if (shouldCommit) mDatabaseProvider.getDatabase().updateServer(server); } else { - String desktop= getString(R.string.desktop); - if(!uname.equals("")){ + String desktop = getString(R.string.desktop); + if (!uname.equals("")) { server = new Server(-1, name, host, port, uname, desktop); server.setUsername(uname); - }else{ + } else { server = new Server(-1, name, host, port, GuardAliasStr, desktop); } - - if(shouldCommit) mDatabaseProvider.getDatabase().addServer(server); + if (shouldCommit) mDatabaseProvider.getDatabase().addServer(server); } - - if(shouldCommit) mListener.serverInfoUpdated(); - + if (shouldCommit) mListener.serverInfoUpdated(); return server; } - public void getFormData(){ + public void getFormData() { Random randomNum = new Random(); int randomNumInt; randomNumInt = randomNum.nextInt(9999 - 1 + 1) + 1; @@ -266,15 +232,15 @@ public void getFormData(){ String username = (mUsernameEdit).getText().toString().trim(); String passwordPIN = mPasswordEdit.getText().toString().trim(); - if(username.equals("demo") || username.equals(null) || username.equals("Demo")|| username.equals("DEMO")){ + if (username.equals("demo") || username.equals(null) || username.equals("Demo") || username.equals("DEMO")) { username = randomNumStr; uname = username; mUsernameEdit.setText(uname); - }else{ + } else { JSONObject jsonGuard = new JSONObject(); try { - jsonGuard.put("GuardID",username); - jsonGuard.put("GuardPIN",passwordPIN); + jsonGuard.put("GuardID", username); + jsonGuard.put("GuardPIN", passwordPIN); } catch (JSONException e) { e.printStackTrace(); } @@ -282,53 +248,44 @@ public void getFormData(){ } } - - /** - * Checks all fields in this ServerEditFragment for validity. - * If an invalid field is found, an error is shown and false is returned. - * @return true if the inputted values are valid, false otherwise. - */ public boolean validate() { - String error = null; - - if (mHostEdit.getText().length() == 0) { - error = getString(R.string.invalid_host); - } else if (mPortEdit.getText().length() > 0) { - try { - int port = Integer.parseInt(mPortEdit.getText().toString()); - if (port < 0 || port > 65535) { - error = getString(R.string.invalid_port_range); - } - } catch (NumberFormatException nfe) { - error = getString(R.string.invalid_port_range); - } - } - - if(mUsernameEdit.getText().equals("demo") || mUsernameEdit.getText().toString().startsWith("demo")){ + if (mUsernameEdit.getText().equals("demo") || mUsernameEdit.getText().toString().startsWith("demo")) { CompanyNameStr = ""; mErrorText.setVisibility(View.GONE); - uname = mUsernameEdit.getText().toString().trim().replaceAll("\\s",""); - if(uname.length() == 8){ + uname = mUsernameEdit.getText().toString().trim().replaceAll("\\s", ""); + if (uname.length() == 8) { + resultFromWebService = "Noresponseyet"; return true; - } - else{ + } else { final String randomNumStr = ("demo" + ((new Random()).nextInt(9999 - 1 + 1) + 1) + "").trim(); uname = randomNumStr; return true; } - }else if(!errorResultFromJsonStr.equals("0")){ + } else if (!errorResultFromJsonStr.equals("0")) { mErrorText.setVisibility(View.VISIBLE); - errorMessageFromJsonStr = errorMessageFromJsonStr.substring(14); - mErrorText.setText(errorMessageFromJsonStr); - return false; - }else{ + if (errorMessageFromJsonStr.equals("")) { + mErrorText.setText("You are offline. Check your internet connection."); + resultFromWebService = "Noresponseyet"; + uname = ""; + return false; + } else { + errorMessageFromJsonStr = errorMessageFromJsonStr.substring(14); + mErrorText.setText(errorMessageFromJsonStr); + resultFromWebService = "Noresponseyet"; + uname = ""; + return false; + } + } else { mErrorText.setVisibility(View.GONE); + resultFromWebService = "Noresponseyet"; + uname = ""; return true; } } public interface ServerEditListener { public void serverInfoUpdated(); + public void connectToServer(Server server); } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/servers/ServerInfoResponse.java b/app/src/main/java/com/terracom/qrpttbeta/servers/ServerInfoResponse.java old mode 100644 new mode 100755 index a55a4f2c..97b137d1 --- a/app/src/main/java/com/terracom/qrpttbeta/servers/ServerInfoResponse.java +++ b/app/src/main/java/com/terracom/qrpttbeta/servers/ServerInfoResponse.java @@ -1,93 +1,52 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.servers; import com.terracom.jumble.model.Server; import java.nio.ByteBuffer; -/** - * Response from server pings. - * @see http://mumble.sourceforge.net/Protocol - * @author terracom - */ public class ServerInfoResponse { - private long mIdentifier; - private int mVersion; - private int mCurrentUsers; - private int mMaximumUsers; - private int mAllowedBandwidth; - private int mLatency; + private long mIdentifier; + private int mVersion; + private int mCurrentUsers; + private int mMaximumUsers; + private int mAllowedBandwidth; + private int mLatency; private Server mServer; - /** - * Whether or not this server info response represents a failure to retrieve a response. Used to efficiently denote failed responses. - */ - private boolean mDummy = false; - - /** - * Creates a ServerInfoResponse object with the bytes obtained from the server. - * @param response The response to the UDP pings sent by the server. - * @see http://mumble.sourceforge.net/Protocol - */ - public ServerInfoResponse(Server server, byte[] response, int latency) { - ByteBuffer buffer = ByteBuffer.wrap(response); - mVersion = buffer.getInt(); - mIdentifier = buffer.getLong(); - mCurrentUsers = buffer.getInt(); - mMaximumUsers = buffer.getInt(); - mAllowedBandwidth = buffer.getInt(); + private boolean mDummy = false; + + public ServerInfoResponse(Server server, byte[] response, int latency) { + ByteBuffer buffer = ByteBuffer.wrap(response); + mVersion = buffer.getInt(); + mIdentifier = buffer.getLong(); + mCurrentUsers = buffer.getInt(); + mMaximumUsers = buffer.getInt(); + mAllowedBandwidth = buffer.getInt(); mLatency = latency; mServer = server; - } + } - /** - * Instantiating a ServerInfoResponse with no data will cause it to be considered a 'dummy' response by its handler. - */ - public ServerInfoResponse() { - this.mDummy = true; - } - - public long getIdentifier() { - return mIdentifier; - } + public ServerInfoResponse() { + this.mDummy = true; + } - public int getVersion() { - return mVersion; - } - - public String getVersionString() { - byte[] versionBytes = ByteBuffer.allocate(4).putInt(mVersion).array(); - return String.format("%d.%d.%d", (int)versionBytes[1], (int)versionBytes[2], (int)versionBytes[3]); - } + public int getVersion() { + return mVersion; + } - public int getCurrentUsers() { - return mCurrentUsers; - } + public String getVersionString() { + byte[] versionBytes = ByteBuffer.allocate(4).putInt(mVersion).array(); + return String.format("%d.%d.%d", (int) versionBytes[1], (int) versionBytes[2], (int) versionBytes[3]); + } - public int getMaximumUsers() { - return mMaximumUsers; - } + public int getCurrentUsers() { + return mCurrentUsers; + } - public int getAllowedBandwidth() { - return mAllowedBandwidth; - } + public int getMaximumUsers() { + return mMaximumUsers; + } public int getLatency() { return mLatency; @@ -98,6 +57,6 @@ public Server getServer() { } public boolean isDummy() { - return mDummy; - } + return mDummy; + } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/servers/ServerInfoTask.java b/app/src/main/java/com/terracom/qrpttbeta/servers/ServerInfoTask.java old mode 100644 new mode 100755 index f1c3aacd..c7f531b7 --- a/app/src/main/java/com/terracom/qrpttbeta/servers/ServerInfoTask.java +++ b/app/src/main/java/com/terracom/qrpttbeta/servers/ServerInfoTask.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.servers; import android.os.AsyncTask; @@ -28,54 +11,45 @@ import java.net.InetAddress; import java.nio.ByteBuffer; -/** - * Pings the requested server and returns a ServerInfoResponse. - * Will return a 'dummy' ServerInfoResponse in the case of failure. - * @author terracom - * - */ public class ServerInfoTask extends AsyncTask { - private Server server; - - @Override - protected ServerInfoResponse doInBackground(Server... params) { - server = params[0]; - try { - InetAddress host = InetAddress.getByName(server.getHost()); - - // Create ping message - ByteBuffer buffer = ByteBuffer.allocate(12); - buffer.putInt(0); // Request type - buffer.putLong(server.getId()); // Identifier - DatagramPacket requestPacket = new DatagramPacket(buffer.array(), 12, host, server.getPort()); - - // Send packet and wait for response - DatagramSocket socket = new DatagramSocket(); - socket.setSoTimeout(1000); - socket.setReceiveBufferSize(1024); + private Server server; + + @Override + protected ServerInfoResponse doInBackground(Server... params) { + server = params[0]; + try { + InetAddress host = InetAddress.getByName(server.getHost()); + + ByteBuffer buffer = ByteBuffer.allocate(12); + buffer.putInt(0); + buffer.putLong(server.getId()); + DatagramPacket requestPacket = new DatagramPacket(buffer.array(), 12, host, server.getPort()); + + DatagramSocket socket = new DatagramSocket(); + socket.setSoTimeout(1000); + socket.setReceiveBufferSize(1024); long startTime = System.nanoTime(); socket.send(requestPacket); - - byte[] responseBuffer = new byte[24]; - DatagramPacket responsePacket = new DatagramPacket(responseBuffer, responseBuffer.length); - socket.receive(responsePacket); - - int latencyInMs = (int) ((System.nanoTime()-startTime)/1000000); - - ServerInfoResponse response = new ServerInfoResponse(server, responseBuffer, latencyInMs); - - Log.i(Constants.TAG, "DEBUG: Server version: "+response.getVersionString()+"\nUsers: "+response.getCurrentUsers()+"/"+response.getMaximumUsers()); - - return response; - - } catch (Exception e) { -// e.printStackTrace(); - } - - return new ServerInfoResponse(); // Return dummy in case of failure - } - + + byte[] responseBuffer = new byte[24]; + DatagramPacket responsePacket = new DatagramPacket(responseBuffer, responseBuffer.length); + socket.receive(responsePacket); + + int latencyInMs = (int) ((System.nanoTime() - startTime) / 1000000); + + ServerInfoResponse response = new ServerInfoResponse(server, responseBuffer, latencyInMs); + + Log.i(Constants.TAG, "DEBUG: Server version: " + response.getVersionString() + "\nUsers: " + response.getCurrentUsers() + "/" + response.getMaximumUsers()); + + return response; + + } catch (Exception e) { + } + + return new ServerInfoResponse(); + } + } \ No newline at end of file diff --git a/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkHotCorner.java b/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkHotCorner.java old mode 100644 new mode 100755 index a79162c4..2520ac5d --- a/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkHotCorner.java +++ b/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkHotCorner.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.service; import android.content.Context; @@ -26,10 +9,6 @@ import com.terracom.qrpttbeta.R; -/** - * A hot corner in an area of the screen specified by {@link QRPushToTalkHotCorner#getGravity()}. - * Created by andrew on 07/06/14. - */ public class QRPushToTalkHotCorner implements View.OnTouchListener { private WindowManager mWindowManager; private Context mContext; @@ -40,7 +19,7 @@ public class QRPushToTalkHotCorner implements View.OnTouchListener { private WindowManager.LayoutParams mParams; public QRPushToTalkHotCorner(Context context, int gravity, QRPushToTalkHotCornerListener listener) { - if(listener == null) { + if (listener == null) { throw new NullPointerException("A QRPushToTalkHotCornerListener must be assigned."); } LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -58,12 +37,8 @@ public QRPushToTalkHotCorner(Context context, int gravity, QRPushToTalkHotCorner mHighlightColour = mContext.getResources().getColor(R.color.holo_blue_bright); } - /** - * Updates the hot corner with any new settings applied, recalculating the layout parameters. - * Does nothing if the hot corner is not shown. - */ private void updateLayout() { - if(!isShown()) return; + if (!isShown()) return; mWindowManager.updateViewLayout(mView, mParams); } @@ -84,8 +59,8 @@ public boolean onTouch(View v, MotionEvent event) { } public void setShown(boolean shown) { - if(shown == mShown) return; - if(shown) { + if (shown == mShown) return; + if (shown) { mWindowManager.addView(mView, mParams); } else { mWindowManager.removeView(mView); @@ -108,6 +83,7 @@ public int getGravity() { public static interface QRPushToTalkHotCornerListener { public void onHotCornerDown(); + public void onHotCornerUp(); } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkNotification.java b/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkNotification.java old mode 100644 new mode 100755 index 2d571549..aae7bead --- a/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkNotification.java +++ b/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkNotification.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.service; import android.app.Notification; @@ -33,10 +16,6 @@ import java.util.ArrayList; import java.util.List; -/** - * Wrapper to create QRPushToTalk notifications. - * Created by andrew on 08/08/14. - */ public class QRPushToTalkNotification { private static final int NOTIFICATION_ID = 1; private static final String BROADCAST_MUTE = "b_mute"; @@ -58,26 +37,19 @@ public void onReceive(Context context, Intent intent) { } else if (BROADCAST_DEAFEN.equals(intent.getAction())) { mListener.onDeafenToggled(); } else if (BROADCAST_OVERLAY.equals(intent.getAction())) { -// mListener.onOverlayToggled(); } } }; - /** - * Creates a foreground QRPushToTalk notification for the given service. - * @param service The service to register a foreground notification for. - * @param listener An listener for notification actions. - * @return A new QRPushToTalkNotification instance. - */ public static QRPushToTalkNotification showForeground(Service service, String ticker, String contentText, - OnActionListener listener) { + OnActionListener listener) { QRPushToTalkNotification notification = new QRPushToTalkNotification(service, ticker, contentText, listener); notification.show(); return notification; } private QRPushToTalkNotification(Service service, String ticker, String contentText, - OnActionListener listener) { + OnActionListener listener) { mService = service; mListener = listener; mMessages = new ArrayList(); @@ -100,11 +72,6 @@ public void setActionsShown(boolean actionsShown) { mActionsShown = actionsShown; } - /** - * Updates the notification with the given message. - * Sets the ticker to the current message as well. - * @param message The message to notify. - */ public void addMessage(String message) { mMessages.add(message); mCustomTicker = message; @@ -116,41 +83,29 @@ public void clearMessages() { createNotification(); } - /** - * Shows the notification and registers the notification action button receiver. - */ public void show() { createNotification(); IntentFilter filter = new IntentFilter(); filter.addAction(BROADCAST_DEAFEN); filter.addAction(BROADCAST_MUTE); -// filter.addAction(BROADCAST_OVERLAY); try { mService.registerReceiver(mNotificationReceiver, filter); } catch (IllegalArgumentException e) { - // Thrown if receiver is already registered. e.printStackTrace(); } } - /** - * Hides the notification and unregisters the action receiver. - */ public void hide() { try { mService.unregisterReceiver(mNotificationReceiver); } catch (IllegalArgumentException e) { - // Thrown if receiver is not registered. e.printStackTrace(); } mService.stopForeground(true); } - /** - * Called to update/create the service's foreground QRPushToTalk notification. - */ private Notification createNotification() { NotificationCompat.Builder builder = new NotificationCompat.Builder(mService); builder.setSmallIcon(R.drawable.ic_stat_notify); @@ -161,23 +116,16 @@ private Notification createNotification() { builder.setOngoing(true); if (mActionsShown) { - // Add notification triggers Intent muteIntent = new Intent(BROADCAST_MUTE); Intent deafenIntent = new Intent(BROADCAST_DEAFEN); -// Intent overlayIntent = new Intent(BROADCAST_OVERLAY); - builder.addAction(R.drawable.ic_action_microphone, mService.getString(R.string.mute), PendingIntent.getBroadcast(mService, 1, muteIntent, PendingIntent.FLAG_CANCEL_CURRENT)); builder.addAction(R.drawable.ic_action_audio, mService.getString(R.string.deafen), PendingIntent.getBroadcast(mService, 1, deafenIntent, PendingIntent.FLAG_CANCEL_CURRENT)); -/* builder.addAction(R.drawable.ic_action_channels, - mService.getString(R.string.overlay), PendingIntent.getBroadcast(mService, 2, - overlayIntent, PendingIntent.FLAG_CANCEL_CURRENT));*/ } - // Show unread messages if (mMessages.size() > 0) { NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); for (String message : mMessages) { @@ -188,7 +136,6 @@ private Notification createNotification() { Intent channelListIntent = new Intent(mService, QRPushToTalkActivity.class); channelListIntent.putExtra(QRPushToTalkActivity.EXTRA_DRAWER_FRAGMENT, DrawerAdapter.ITEM_SERVER); - // FLAG_CANCEL_CURRENT ensures that the extra always gets sent. PendingIntent pendingIntent = PendingIntent.getActivity(mService, 0, channelListIntent, PendingIntent.FLAG_CANCEL_CURRENT); builder.setContentIntent(pendingIntent); @@ -199,7 +146,7 @@ private Notification createNotification() { public interface OnActionListener { public void onMuteToggled(); + public void onDeafenToggled(); - public void onOverlayToggled(); } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkOverlay.java b/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkOverlay.java old mode 100644 new mode 100755 index 52acf9f2..d312881d --- a/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkOverlay.java +++ b/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkOverlay.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.service; import android.content.Context; @@ -35,10 +18,6 @@ import com.terracom.qrpttbeta.Settings; import com.terracom.qrpttbeta.channel.ChannelAdapter; -/** - * An onscreen interactive overlay displaying the users in the current channel. - * Created by andrew on 26/09/13. - */ public class QRPushToTalkOverlay { public static final int DEFAULT_WIDTH = 200; @@ -52,15 +31,15 @@ public void onUserTalkStateUpdated(User user) throws RemoteException { @Override public void onUserStateUpdated(User user) throws RemoteException { - if(user.getChannelId() == mService.getBinder().getSessionChannel().getId()) + if (user.getChannelId() == mService.getBinder().getSessionChannel().getId()) mChannelAdapter.notifyDataSetChanged(); } @Override public void onUserJoinedChannel(User user, Channel newChannel, Channel oldChannel) throws RemoteException { - if(user.getSession() == mService.getBinder().getSession()) // Session user has changed channels + if (user.getSession() == mService.getBinder().getSession()) // Session user has changed channels mChannelAdapter.setChannel(mService.getBinder().getSessionChannel()); - else if(newChannel.getId() == mService.getBinder().getSessionChannel().getId() || + else if (newChannel.getId() == mService.getBinder().getSessionChannel().getId() || oldChannel.getId() == mService.getBinder().getSessionChannel().getId()) mChannelAdapter.notifyDataSetChanged(); } @@ -70,13 +49,11 @@ else if(newChannel.getId() == mService.getBinder().getSessionChannel().getId() | private ListView mOverlayList; private ChannelAdapter mChannelAdapter; private ImageView mTalkButton; -// private ImageView mToggleButton; private ImageView mCloseButton; private ImageView mDragButton; private View mTitleView; private WindowManager.LayoutParams mOverlayParams; private boolean mShown = false; -// private boolean mShowChat = false; private QRPushToTalkService mService; @@ -86,7 +63,6 @@ public QRPushToTalkOverlay(QRPushToTalkService service) { mTalkButton = (ImageView) mOverlayView.findViewById(R.id.overlay_talk); mDragButton = (ImageView) mOverlayView.findViewById(R.id.overlay_drag); mCloseButton = (ImageView) mOverlayView.findViewById(R.id.overlay_close); -// mToggleButton = (ImageView) mOverlayView.findViewById(R.id.overlay_mode_toggle); mTitleView = mOverlayView.findViewById(R.id.overlay_title); mOverlayList = (ListView) mOverlayView.findViewById(R.id.overlay_list); @@ -97,11 +73,11 @@ public QRPushToTalkOverlay(QRPushToTalkService service) { @Override public boolean onTouch(View v, MotionEvent event) { - if(MotionEvent.ACTION_DOWN == event.getAction()) { + if (MotionEvent.ACTION_DOWN == event.getAction()) { mInitialX = event.getRawX() - mOverlayParams.x; mInitialY = event.getRawY() - mOverlayParams.y; return true; - } else if(MotionEvent.ACTION_MOVE == event.getAction()) { + } else if (MotionEvent.ACTION_MOVE == event.getAction()) { mOverlayParams.x = (int) (event.getRawX() - mInitialX); mOverlayParams.y = (int) (event.getRawY() - mInitialY); mWindowManager.updateViewLayout(mOverlayView, mOverlayParams); @@ -138,30 +114,14 @@ public boolean onTouch(View v, MotionEvent event) { } }); - /* - mToggleButton.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - mShowChat = !mShowChat; - // TODO implement chat - if(mShowChat) { - - } else { - - } - } - }); - */ - mTalkButton.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { try { - if(MotionEvent.ACTION_DOWN == event.getAction()) { + if (MotionEvent.ACTION_DOWN == event.getAction()) { mService.getBinder().setTalkingState(true); return true; - } else if(MotionEvent.ACTION_UP == event.getAction()) { + } else if (MotionEvent.ACTION_UP == event.getAction()) { mService.getBinder().setTalkingState(false); return true; } @@ -184,8 +144,8 @@ public void onClick(View v) { }); DisplayMetrics metrics = mService.getResources().getDisplayMetrics(); - mOverlayParams = new WindowManager.LayoutParams((int)(DEFAULT_WIDTH*metrics.density), - (int)(DEFAULT_HEIGHT*metrics.density), + mOverlayParams = new WindowManager.LayoutParams((int) (DEFAULT_WIDTH * metrics.density), + (int) (DEFAULT_HEIGHT * metrics.density), WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH @@ -200,7 +160,7 @@ public boolean isShown() { } public void show() { - if(mShown) + if (mShown) return; mShown = true; try { @@ -217,7 +177,7 @@ public void show() { } public void hide() { - if(!mShown) + if (!mShown) return; mShown = false; try { diff --git a/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkService.java b/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkService.java old mode 100644 new mode 100755 index 0ebe4110..1250c3a1 --- a/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkService.java +++ b/app/src/main/java/com/terracom/qrpttbeta/service/QRPushToTalkService.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.service; import android.content.BroadcastReceiver; @@ -38,45 +21,33 @@ import com.terracom.qrpttbeta.Settings; import com.terracom.qrpttbeta.service.ipc.TalkBroadcastReceiver; -/** - * An extension of the Jumble service with some added QRPushToTalk-exclusive non-standard Mumble features. - * Created by andrew on 28/07/13. - */ public class QRPushToTalkService extends JumbleService implements SharedPreferences.OnSharedPreferenceChangeListener, QRPushToTalkNotification.OnActionListener, QRPushToTalkReconnectNotification.OnActionListener { - /** Undocumented constant that permits a proximity-sensing wake lock. */ + public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32; - public static final int TTS_THRESHOLD = 250; // Maximum number of characters to read + public static final int TTS_THRESHOLD = 250; public static final int RECONNECT_DELAY = 10000; private QRPushToTalkBinder mBinder = new QRPushToTalkBinder(); private Settings mSettings; private QRPushToTalkNotification mNotification; private QRPushToTalkReconnectNotification mReconnectNotification; - /** Channel view overlay. */ private QRPushToTalkOverlay mChannelOverlay; - /** Proximity lock for handset mode. */ private PowerManager.WakeLock mProximityLock; - /** Play sound when push to talk key is pressed */ private boolean mPTTSoundEnabled; - /** - * True if an error causing disconnection has been dismissed by the user. - * This should serve as a hint not to bother the user. - */ - private boolean mErrorShown; + private boolean mErrorShown; private TextToSpeech mTTS; private TextToSpeech.OnInitListener mTTSInitListener = new TextToSpeech.OnInitListener() { @Override public void onInit(int status) { - if(status == TextToSpeech.ERROR) + if (status == TextToSpeech.ERROR) log(Message.Type.WARNING, getString(R.string.tts_failed)); } }; - /** The view representing the hot corner. */ private QRPushToTalkHotCorner mHotCorner; private QRPushToTalkHotCorner.QRPushToTalkHotCornerListener mHotCornerListener = new QRPushToTalkHotCorner.QRPushToTalkHotCornerListener() { @Override @@ -90,7 +61,7 @@ public void onHotCornerDown() { @Override public void onHotCornerUp() { - if(!mSettings.isPushToTalkToggle()) { + if (!mSettings.isPushToTalkToggle()) { try { mBinder.setTalkingState(false); } catch (RemoteException e) { @@ -106,7 +77,6 @@ public void onHotCornerUp() { @Override public void onConnecting() throws RemoteException { - // Remove old notification left from reconnect, if (mReconnectNotification != null) { mReconnectNotification.hide(); mReconnectNotification = null; @@ -116,7 +86,7 @@ public void onConnecting() throws RemoteException { getString(R.string.qrpttConnecting), getString(R.string.connecting), QRPushToTalkService.this); - mErrorShown = false; + mErrorShown = false; } @Override @@ -140,23 +110,22 @@ public void onDisconnected(JumbleException e) throws RemoteException { QRPushToTalkReconnectNotification.show(QRPushToTalkService.this, e.getMessage(), getBinder().isReconnecting(), QRPushToTalkService.this); - } + } } @Override public void onUserConnected(User user) throws RemoteException { if (user.getTextureHash() != null && user.getTexture() == null) { - // Request avatar data if available. getBinder().requestAvatar(user.getSession()); } } @Override public void onUserStateUpdated(User user) throws RemoteException { - if(user.getSession() == mBinder.getSession()) { - mSettings.setMutedAndDeafened(user.isSelfMuted(), user.isSelfDeafened()); // Update settings mute/deafen state - if(mNotification != null) { + if (user.getSession() == mBinder.getSession()) { + mSettings.setMutedAndDeafened(user.isSelfMuted(), user.isSelfDeafened()); + if (mNotification != null) { String contentText; if (user.isSelfMuted() && user.isSelfDeafened()) contentText = getString(R.string.status_notify_muted_and_deafened); @@ -171,28 +140,24 @@ else if (user.isSelfMuted()) if (user.getTextureHash() != null && user.getTexture() == null) { - // Update avatar data if available. getBinder().requestAvatar(user.getSession()); } } @Override public void onMessageLogged(Message message) throws RemoteException { - // Strip all HTML tags. String strippedMessage = message.getMessage().replaceAll("<[^>]*>", ""); - // Only read text messages. TODO: make this an option. - if(message.getType() == Message.Type.TEXT_MESSAGE) { + if (message.getType() == Message.Type.TEXT_MESSAGE) { String formattedMessage = getString(R.string.notification_message, message.getActorName(), strippedMessage); - if(mSettings.isChatNotifyEnabled() && mNotification != null) { + if (mSettings.isChatNotifyEnabled() && mNotification != null) { mNotification.addMessage(formattedMessage); mNotification.show(); } - // Read if TTS is enabled, the message is less than threshold, is a text message, and not deafened - if(mSettings.isTextToSpeechEnabled() && + if (mSettings.isTextToSpeechEnabled() && mTTS != null && message.getType() == Message.Type.TEXT_MESSAGE && strippedMessage.length() <= TTS_THRESHOLD && @@ -205,7 +170,7 @@ public void onMessageLogged(Message message) throws RemoteException { @Override public void onPermissionDenied(String reason) throws RemoteException { - if(mSettings.isChatNotifyEnabled() && + if (mSettings.isChatNotifyEnabled() && mNotification != null) { mNotification.setCustomTicker(reason); mNotification.show(); @@ -234,22 +199,16 @@ public void onCreate() { e.printStackTrace(); } - // Register for preference changes mSettings = Settings.getInstance(this); mPTTSoundEnabled = mSettings.isPttSoundEnabled(); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); preferences.registerOnSharedPreferenceChangeListener(this); - - // Manually set theme to style overlay views - // XML theme does NOT do this! setTheme(R.style.Theme_QRPushToTalk); - // Instantiate overlay view mChannelOverlay = new QRPushToTalkOverlay(this); mHotCorner = new QRPushToTalkHotCorner(this, mSettings.getHotCornerGravity(), mHotCornerListener); - // Set up TTS - if(mSettings.isTextToSpeechEnabled()) + if (mSettings.isTextToSpeechEnabled()) mTTS = new TextToSpeech(this, mTTSInitListener); mTalkReceiver = new TalkBroadcastReceiver(getBinder()); @@ -260,11 +219,11 @@ public void onDestroy() { if (mNotification != null) { mNotification.hide(); mNotification = null; - } + } if (mReconnectNotification != null) { mReconnectNotification.hide(); mReconnectNotification = null; - } + } SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); preferences.unregisterOnSharedPreferenceChangeListener(this); try { @@ -278,15 +237,14 @@ public void onDestroy() { } catch (RemoteException e) { e.printStackTrace(); } - if(mTTS != null) mTTS.shutdown(); + if (mTTS != null) mTTS.shutdown(); super.onDestroy(); } @Override public void onConnectionEstablished() { super.onConnectionEstablished(); - // Restore mute/deafen state - if(mSettings.isMuted() || mSettings.isDeafened()) { + if (mSettings.isMuted() || mSettings.isDeafened()) { try { getBinder().setSelfMuteDeafState(mSettings.isMuted(), mSettings.isDeafened()); } catch (RemoteException e) { @@ -305,7 +263,6 @@ public void onConnectionSynchronized() { if (mSettings.isHotCornerEnabled()) { mHotCorner.setShown(true); } - // Configure proximity sensor if (mSettings.isHandsetMode()) { setProximitySensorOn(true); } @@ -319,23 +276,17 @@ public void onConnectionDisconnected(JumbleException e) { } catch (IllegalArgumentException iae) { } - // Remove overlay if present. mChannelOverlay.hide(); mHotCorner.setShown(false); setProximitySensorOn(false); -} + } - /** - * Called when the user makes a change to their preferences. - * Should update all preferences relevant to the service. - */ @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { switch (key) { case Settings.PREF_INPUT_METHOD: - /* Convert input method defined in settings to an integer format used by Jumble. */ int inputMethod = mSettings.getJumbleInputMethod(); try { if (isConnected()) { @@ -395,12 +346,12 @@ else if (mTTS != null && !mSettings.isTextToSpeechEnabled()) { } private void setProximitySensorOn(boolean on) { - if(on) { + if (on) { PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); mProximityLock = pm.newWakeLock(PROXIMITY_SCREEN_OFF_WAKE_LOCK, "qrptt_proximity"); mProximityLock.acquire(); } else { - if(mProximityLock != null) mProximityLock.release(); + if (mProximityLock != null) mProximityLock.release(); mProximityLock = null; } } @@ -441,18 +392,10 @@ public void onDeafenToggled() { } } - @Override - public void onOverlayToggled() { - if (!mChannelOverlay.isShown()) { - mChannelOverlay.show(); - } else { - mChannelOverlay.hide(); - } - } @Override public void onReconnectNotificationDismissed() { mErrorShown = true; - } + } @Override public void reconnect() { @@ -468,36 +411,22 @@ public void cancelReconnect() { } } - /** - * An extension of JumbleBinder to add QRPushToTalk-specific functionality. - */ public class QRPushToTalkBinder extends JumbleBinder { - public void setOverlayShown(boolean showOverlay) { - if(!mChannelOverlay.isShown()) { - mChannelOverlay.show(); - } else { - mChannelOverlay.hide(); - } - } - - public boolean isOverlayShown() { - return mChannelOverlay.isShown(); - } public void clearChatNotifications() throws RemoteException { if (mNotification != null) { mNotification.clearMessages(); mNotification.show(); - } + } } public void markErrorShown() { mErrorShown = true; - } + } public boolean isErrorShown() { return mErrorShown; - } + } public void cancelReconnect() throws RemoteException { if (mReconnectNotification != null) { diff --git a/app/src/main/java/com/terracom/qrpttbeta/service/ipc/TalkBroadcastReceiver.java b/app/src/main/java/com/terracom/qrpttbeta/service/ipc/TalkBroadcastReceiver.java old mode 100644 new mode 100755 index 91a67dfb..cbfbad30 --- a/app/src/main/java/com/terracom/qrpttbeta/service/ipc/TalkBroadcastReceiver.java +++ b/app/src/main/java/com/terracom/qrpttbeta/service/ipc/TalkBroadcastReceiver.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.service.ipc; import android.content.BroadcastReceiver; @@ -24,9 +7,6 @@ import com.terracom.jumble.IJumbleService; -/** - * Created by andrew on 08/08/14. - */ public class TalkBroadcastReceiver extends BroadcastReceiver { public static final String BROADCAST_TALK = "com.terracom.qrpttbeta.action.TALK"; public static final String EXTRA_TALK_STATUS = "status"; diff --git a/app/src/main/java/com/terracom/qrpttbeta/util/JumbleServiceFragment.java b/app/src/main/java/com/terracom/qrpttbeta/util/JumbleServiceFragment.java old mode 100644 new mode 100755 index d38f8678..07007b7a --- a/app/src/main/java/com/terracom/qrpttbeta/util/JumbleServiceFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/util/JumbleServiceFragment.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.util; import android.app.Activity; @@ -22,20 +5,14 @@ import android.os.RemoteException; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; -import android.view.View; import com.terracom.jumble.IJumbleObserver; import com.terracom.jumble.IJumbleService; -/** - * Fragment class intended to make binding the Jumble service to fragments easier. - * Created by andrew on 04/08/13. - */ public abstract class JumbleServiceFragment extends Fragment { private JumbleServiceProvider mServiceProvider; - /** State boolean to make sure we don't double initialize a fragment once a service has been bound. */ private boolean mBound; @Override @@ -53,22 +30,21 @@ public void onAttach(Activity activity) { public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mServiceProvider.addServiceFragment(this); - if(mServiceProvider.getService() != null && !mBound) + if (mServiceProvider.getService() != null && !mBound) onServiceAttached(mServiceProvider.getService()); } @Override public void onDestroy() { mServiceProvider.removeServiceFragment(this); - if(mServiceProvider.getService() != null && mBound) + if (mServiceProvider.getService() != null && mBound) onServiceDetached(mServiceProvider.getService()); super.onDestroy(); } - /** The definitive place where data from the service will be used to initialize the fragment. Only called once per bind, whether the fragment loads first or the service. */ - public void onServiceBound(IJumbleService service) { } + public void onServiceBound(IJumbleService service) { + } - /** If implemented, will register the returned observer to the service upon binding. */ public IJumbleObserver getServiceObserver() { return null; } @@ -76,7 +52,7 @@ public IJumbleObserver getServiceObserver() { private void onServiceAttached(IJumbleService service) { mBound = true; try { - if(getServiceObserver() != null) + if (getServiceObserver() != null) service.registerObserver(getServiceObserver()); } catch (RemoteException e) { e.printStackTrace(); @@ -88,7 +64,7 @@ private void onServiceAttached(IJumbleService service) { private void onServiceDetached(IJumbleService service) { mBound = false; try { - if(getServiceObserver() != null) + if (getServiceObserver() != null) service.unregisterObserver(getServiceObserver()); } catch (RemoteException e) { e.printStackTrace(); @@ -97,9 +73,9 @@ private void onServiceDetached(IJumbleService service) { } public void setServiceBound(boolean bound) { - if(bound && !mBound) + if (bound && !mBound) onServiceAttached(mServiceProvider.getService()); - else if(mBound && !bound) + else if (mBound && !bound) onServiceDetached(mServiceProvider.getService()); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/util/JumbleServiceProvider.java b/app/src/main/java/com/terracom/qrpttbeta/util/JumbleServiceProvider.java old mode 100644 new mode 100755 index cef9ba13..0c61c720 --- a/app/src/main/java/com/terracom/qrpttbeta/util/JumbleServiceProvider.java +++ b/app/src/main/java/com/terracom/qrpttbeta/util/JumbleServiceProvider.java @@ -1,29 +1,11 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.util; import com.terracom.jumble.IJumbleService; -/** - * Created by andrew on 03/08/13. - */ public interface JumbleServiceProvider { public IJumbleService getService(); + public void addServiceFragment(JumbleServiceFragment fragment); + public void removeServiceFragment(JumbleServiceFragment fragment); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/util/ModelUtils.java b/app/src/main/java/com/terracom/qrpttbeta/util/ModelUtils.java old mode 100644 new mode 100755 index aad4222c..f055f9c6 --- a/app/src/main/java/com/terracom/qrpttbeta/util/ModelUtils.java +++ b/app/src/main/java/com/terracom/qrpttbeta/util/ModelUtils.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.util; import android.os.RemoteException; @@ -26,17 +9,8 @@ import java.util.LinkedList; import java.util.List; -/** - * Tools for dealing with the recursive user-channel hierarchy. - * Created by andrew on 18/10/14. - */ public class ModelUtils { - /** - * Flattens the channel hierarchy, returning an array of channels in hierarchical order. - * @param channel The root channel to flatten from. - * @param service The service to fetch subchannel information from. - * @return A list of channels. - */ + public static List getChannelList(Channel channel, IJumbleService service) throws RemoteException { LinkedList channels = new LinkedList(); diff --git a/app/src/main/java/com/terracom/qrpttbeta/util/MumbleImageGetter.java b/app/src/main/java/com/terracom/qrpttbeta/util/MumbleImageGetter.java old mode 100644 new mode 100755 index 59dbf7e4..665385dd --- a/app/src/main/java/com/terracom/qrpttbeta/util/MumbleImageGetter.java +++ b/app/src/main/java/com/terracom/qrpttbeta/util/MumbleImageGetter.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.util; import android.content.Context; @@ -38,14 +21,9 @@ import java.util.HashMap; import java.util.Map; -/** - * Implementation of ImageGetter designed for Mumble MOTDs and messages. - * Can read base64-embedded images and references. Caches them too. - * Created by andrew on 07/02/14. - */ public class MumbleImageGetter implements Html.ImageGetter { - /** The maximum image size in bytes to load. */ + private static final int MAX_LENGTH = 64000; private Context mContext; @@ -57,7 +35,6 @@ public MumbleImageGetter(Context context) { mSettings = Settings.getInstance(context); mBitmapCache = new HashMap(); - // We have to enable network on the main thread here. FIXME StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); } @@ -65,9 +42,9 @@ public MumbleImageGetter(Context context) { @Override public Drawable getDrawable(String source) { Drawable cachedDrawable = mBitmapCache.get(source); - if(cachedDrawable != null) return cachedDrawable; + if (cachedDrawable != null) return cachedDrawable; - String decodedSource; // Decode from URL encoding + String decodedSource; try { decodedSource = URLDecoder.decode(source, "UTF-8"); } catch (UnsupportedEncodingException e) { @@ -77,20 +54,20 @@ public Drawable getDrawable(String source) { Bitmap bitmap = null; try { - if(decodedSource.startsWith("data:image")) { + if (decodedSource.startsWith("data:image")) { bitmap = getBase64Image(decodedSource.split(",")[1]); - } else if(mSettings.shouldLoadExternalImages()) { + } else if (mSettings.shouldLoadExternalImages()) { bitmap = getURLImage(decodedSource); } } catch (IllegalArgumentException e) { e.printStackTrace(); return null; } - if(bitmap == null) return null; + if (bitmap == null) return null; BitmapDrawable drawable = new BitmapDrawable(mContext.getResources(), bitmap); DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); // Use display metrics to scale image to mdpi - drawable.setBounds(0, 0, (int)((float)drawable.getIntrinsicWidth()*metrics.density), (int)((float)drawable.getIntrinsicHeight()*metrics.density)); + drawable.setBounds(0, 0, (int) ((float) drawable.getIntrinsicWidth() * metrics.density), (int) ((float) drawable.getIntrinsicHeight() * metrics.density)); mBitmapCache.put(source, drawable); return drawable; } @@ -104,7 +81,7 @@ private Bitmap getURLImage(String source) { try { URL url = new URL(source); URLConnection conn = url.openConnection(); - if(conn.getContentLength() > MAX_LENGTH) return null; + if (conn.getContentLength() > MAX_LENGTH) return null; return BitmapFactory.decodeStream(conn.getInputStream()); } catch (MalformedURLException e) { e.printStackTrace(); diff --git a/app/src/main/java/com/terracom/qrpttbeta/util/QRPushToTalkTrustStore.java b/app/src/main/java/com/terracom/qrpttbeta/util/QRPushToTalkTrustStore.java old mode 100644 new mode 100755 index 689f1252..6b886c0f --- a/app/src/main/java/com/terracom/qrpttbeta/util/QRPushToTalkTrustStore.java +++ b/app/src/main/java/com/terracom/qrpttbeta/util/QRPushToTalkTrustStore.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.util; import android.content.Context; @@ -29,19 +12,12 @@ import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; -/** - * Created by andrew on 05/04/14. - */ public class QRPushToTalkTrustStore { private static final String STORE_FILE = "qrptt-store.bks"; private static final String STORE_PASS = ""; private static final String STORE_FORMAT = "BKS"; - /** - * Loads the app's trust store of certificates. - * @return A loaded KeyStore with the user's trusted certificates. - */ public static KeyStore getTrustStore(Context context) throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException { KeyStore store = KeyStore.getInstance(STORE_FORMAT); try { @@ -64,13 +40,9 @@ public static void clearTrustStore(Context context) { context.deleteFile(STORE_FILE); } - /** - * Gets the app's trust store path. - * @return null if the store has not yet been initialized, or the absolute path if it has. - */ public static String getTrustStorePath(Context context) { File trustPath = new File(context.getFilesDir(), STORE_FILE); - if(trustPath.exists()) return trustPath.getAbsolutePath(); + if (trustPath.exists()) return trustPath.getAbsolutePath(); return null; } diff --git a/app/src/main/java/com/terracom/qrpttbeta/util/TintedMenuInflater.java b/app/src/main/java/com/terracom/qrpttbeta/util/TintedMenuInflater.java old mode 100644 new mode 100755 index 55d03311..7c471a49 --- a/app/src/main/java/com/terracom/qrpttbeta/util/TintedMenuInflater.java +++ b/app/src/main/java/com/terracom/qrpttbeta/util/TintedMenuInflater.java @@ -1,20 +1,3 @@ -/* - * Copyright (C) 2014 Andrew Comminos - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package com.terracom.qrpttbeta.util; import android.content.Context; @@ -27,19 +10,10 @@ import com.terracom.qrpttbeta.R; -/** - * A wrapper around a {@link android.view.MenuInflater} that tints menu items to the control color - * of the action bar's theme. - * Created by andrew on 27/10/14. - */ public class TintedMenuInflater { private MenuInflater mInflater; private int mTintColour; - public TintedMenuInflater(Context context) { - this(context, new MenuInflater(context)); - } - public TintedMenuInflater(Context context, MenuInflater inflater) { mInflater = inflater; TypedArray actionBarThemeArray = diff --git a/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardActivity.java b/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardActivity.java old mode 100644 new mode 100755 index da2a5cc0..dbf81c13 --- a/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardActivity.java +++ b/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardActivity.java @@ -125,15 +125,15 @@ public void next() { @Override public void back() { - if(mViewPager.getCurrentItem() == 0) + if (mViewPager.getCurrentItem() == 0) showConfirmQuitDialog(); // If cancel is pressed at the beginning of the pager, prompt the user to quit. else - mViewPager.setCurrentItem(mViewPager.getCurrentItem()-1, true); + mViewPager.setCurrentItem(mViewPager.getCurrentItem() - 1, true); } private class WizardPagerAdapter extends FragmentPagerAdapter { - private final Class WIZARD_FRAGMENTS[] = new Class[] { + private final Class WIZARD_FRAGMENTS[] = new Class[]{ WizardWelcomeFragment.class, WizardCertificateFragment.class, WizardAudioFragment.class, diff --git a/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardAudioFragment.java b/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardAudioFragment.java old mode 100644 new mode 100755 index 9d52aad1..2bfb8968 --- a/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardAudioFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardAudioFragment.java @@ -74,7 +74,7 @@ public long getItemId(int position) { @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; - if(view == null) { + if (view == null) { LayoutInflater inflater = getActivity().getLayoutInflater(); view = inflater.inflate(android.R.layout.simple_spinner_item, parent, false); } @@ -86,7 +86,7 @@ public View getView(int position, View convertView, ViewGroup parent) { @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { View view = convertView; - if(view == null) { + if (view == null) { LayoutInflater inflater = getActivity().getLayoutInflater(); view = inflater.inflate(android.R.layout.simple_spinner_dropdown_item, parent, false); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardCertificateFragment.java b/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardCertificateFragment.java old mode 100644 new mode 100755 index 230d48a0..20b08a56 --- a/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardCertificateFragment.java +++ b/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardCertificateFragment.java @@ -45,7 +45,7 @@ public void onAttach(Activity activity) { try { mNavigation = (WizardNavigation) activity; } catch (ClassCastException e) { - throw new RuntimeException(activity.getClass().getName()+" must implement WizardNavigation!"); + throw new RuntimeException(activity.getClass().getName() + " must implement WizardNavigation!"); } } diff --git a/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardNavigation.java b/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardNavigation.java old mode 100644 new mode 100755 index 745b35a5..6b428d19 --- a/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardNavigation.java +++ b/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardNavigation.java @@ -22,5 +22,6 @@ */ public interface WizardNavigation { public void back(); + public void next(); } diff --git a/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardWelcomeFragment.java b/app/src/main/java/com/terracom/qrpttbeta/wizard/WizardWelcomeFragment.java old mode 100644 new mode 100755 diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml old mode 100644 new mode 100755 index 61209250..64da7214 --- a/app/src/main/res/anim/fade_in.xml +++ b/app/src/main/res/anim/fade_in.xml @@ -1,21 +1,4 @@ - - diff --git a/app/src/main/res/anim/fade_out.xml b/app/src/main/res/anim/fade_out.xml old mode 100644 new mode 100755 index a46bf5f9..95ac4e32 --- a/app/src/main/res/anim/fade_out.xml +++ b/app/src/main/res/anim/fade_out.xml @@ -1,21 +1,4 @@ - - diff --git a/app/src/main/res/anim/slide_down.xml b/app/src/main/res/anim/slide_down.xml old mode 100644 new mode 100755 index dea32727..fad9d83d --- a/app/src/main/res/anim/slide_down.xml +++ b/app/src/main/res/anim/slide_down.xml @@ -1,22 +1,4 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/anim/slide_up.xml b/app/src/main/res/anim/slide_up.xml old mode 100644 new mode 100755 index 836ec33d..c13605b9 --- a/app/src/main/res/anim/slide_up.xml +++ b/app/src/main/res/anim/slide_up.xml @@ -1,22 +1,4 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi-v11/ic_stat_notify.png b/app/src/main/res/drawable-hdpi-v11/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi-v9/ic_stat_notify.png b/app/src/main/res/drawable-hdpi-v9/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_add_dark.png b/app/src/main/res/drawable-hdpi/ic_action_add_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_add_light.png b/app/src/main/res/drawable-hdpi/ic_action_add_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_audio.png b/app/src/main/res/drawable-hdpi/ic_action_audio.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_audio_muted.png b/app/src/main/res/drawable-hdpi/ic_action_audio_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_audio_on.png b/app/src/main/res/drawable-hdpi/ic_action_audio_on.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_channels.png b/app/src/main/res/drawable-hdpi/ic_action_channels.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_chat.png b/app/src/main/res/drawable-hdpi/ic_action_chat.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_collapsed.png b/app/src/main/res/drawable-hdpi/ic_action_collapsed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_comment.png b/app/src/main/res/drawable-hdpi/ic_action_comment.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_delete_dark.png b/app/src/main/res/drawable-hdpi/ic_action_delete_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_delete_light.png b/app/src/main/res/drawable-hdpi/ic_action_delete_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_drag_handle.png b/app/src/main/res/drawable-hdpi/ic_action_drag_handle.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_edit_dark.png b/app/src/main/res/drawable-hdpi/ic_action_edit_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_expanded.png b/app/src/main/res/drawable-hdpi/ic_action_expanded.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_favourite_on.png b/app/src/main/res/drawable-hdpi/ic_action_favourite_on.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_fullscreen.png b/app/src/main/res/drawable-hdpi/ic_action_fullscreen.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_headphones.png b/app/src/main/res/drawable-hdpi/ic_action_headphones.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_info_dark.png b/app/src/main/res/drawable-hdpi/ic_action_info_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_microphone.png b/app/src/main/res/drawable-hdpi/ic_action_microphone.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_microphone_dark.png b/app/src/main/res/drawable-hdpi/ic_action_microphone_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_microphone_muted.png b/app/src/main/res/drawable-hdpi/ic_action_microphone_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_move.png b/app/src/main/res/drawable-hdpi/ic_action_move.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_save.png b/app/src/main/res/drawable-hdpi/ic_action_save.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_search.png b/app/src/main/res/drawable-hdpi/ic_action_search.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_send.png b/app/src/main/res/drawable-hdpi/ic_action_send.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_settings.png b/app/src/main/res/drawable-hdpi/ic_action_settings.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_sort.png b/app/src/main/res/drawable-hdpi/ic_action_sort.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_action_user_dark.png b/app/src/main/res/drawable-hdpi/ic_action_user_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_carriage_return.png b/app/src/main/res/drawable-hdpi/ic_carriage_return.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_deafened.png b/app/src/main/res/drawable-hdpi/ic_deafened.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_drawer.png b/app/src/main/res/drawable-hdpi/ic_drawer.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_home.png b/app/src/main/res/drawable-hdpi/ic_home.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_card_dark_normal.png b/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_card_dark_normal.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_card_dark_pressed.png b/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_card_dark_pressed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_muted.png b/app/src/main/res/drawable-hdpi/ic_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_muted_local.png b/app/src/main/res/drawable-hdpi/ic_muted_local.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_registered.png b/app/src/main/res/drawable-hdpi/ic_registered.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_server_deafened.png b/app/src/main/res/drawable-hdpi/ic_server_deafened.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_server_light.png b/app/src/main/res/drawable-hdpi/ic_server_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_server_location.png b/app/src/main/res/drawable-hdpi/ic_server_location.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_server_muted.png b/app/src/main/res/drawable-hdpi/ic_server_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_stat_notify.png b/app/src/main/res/drawable-hdpi/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_suppressed.png b/app/src/main/res/drawable-hdpi/ic_suppressed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_talking_off.png b/app/src/main/res/drawable-hdpi/ic_talking_off.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_talking_on.png b/app/src/main/res/drawable-hdpi/ic_talking_on.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/ic_user_light.png b/app/src/main/res/drawable-hdpi/ic_user_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/list_longpressed.9.png b/app/src/main/res/drawable-hdpi/list_longpressed.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/list_pressed.9.png b/app/src/main/res/drawable-hdpi/list_pressed.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/list_selector_disabled.9.png b/app/src/main/res/drawable-hdpi/list_selector_disabled.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/list_selector_focused.9.png b/app/src/main/res/drawable-hdpi/list_selector_focused.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-hdpi/server_card.9.png b/app/src/main/res/drawable-hdpi/server_card.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi-v11/ic_stat_notify.png b/app/src/main/res/drawable-mdpi-v11/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi-v9/ic_stat_notify.png b/app/src/main/res/drawable-mdpi-v9/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/drawer_shadow.9.png b/app/src/main/res/drawable-mdpi/drawer_shadow.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_add_dark.png b/app/src/main/res/drawable-mdpi/ic_action_add_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_add_light.png b/app/src/main/res/drawable-mdpi/ic_action_add_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_audio.png b/app/src/main/res/drawable-mdpi/ic_action_audio.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_audio_muted.png b/app/src/main/res/drawable-mdpi/ic_action_audio_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_audio_on.png b/app/src/main/res/drawable-mdpi/ic_action_audio_on.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_channels.png b/app/src/main/res/drawable-mdpi/ic_action_channels.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_chat.png b/app/src/main/res/drawable-mdpi/ic_action_chat.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_collapsed.png b/app/src/main/res/drawable-mdpi/ic_action_collapsed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_comment.png b/app/src/main/res/drawable-mdpi/ic_action_comment.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_delete_dark.png b/app/src/main/res/drawable-mdpi/ic_action_delete_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_delete_light.png b/app/src/main/res/drawable-mdpi/ic_action_delete_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_drag_handle.png b/app/src/main/res/drawable-mdpi/ic_action_drag_handle.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_edit_dark.png b/app/src/main/res/drawable-mdpi/ic_action_edit_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_expanded.png b/app/src/main/res/drawable-mdpi/ic_action_expanded.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_favourite_on.png b/app/src/main/res/drawable-mdpi/ic_action_favourite_on.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_fullscreen.png b/app/src/main/res/drawable-mdpi/ic_action_fullscreen.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_headphones.png b/app/src/main/res/drawable-mdpi/ic_action_headphones.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_info_dark.png b/app/src/main/res/drawable-mdpi/ic_action_info_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_microphone.png b/app/src/main/res/drawable-mdpi/ic_action_microphone.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_microphone_dark.png b/app/src/main/res/drawable-mdpi/ic_action_microphone_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_microphone_muted.png b/app/src/main/res/drawable-mdpi/ic_action_microphone_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_move.png b/app/src/main/res/drawable-mdpi/ic_action_move.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_save.png b/app/src/main/res/drawable-mdpi/ic_action_save.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_search.png b/app/src/main/res/drawable-mdpi/ic_action_search.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_send.png b/app/src/main/res/drawable-mdpi/ic_action_send.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_settings.png b/app/src/main/res/drawable-mdpi/ic_action_settings.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_sort.png b/app/src/main/res/drawable-mdpi/ic_action_sort.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_action_user_dark.png b/app/src/main/res/drawable-mdpi/ic_action_user_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_carriage_return.png b/app/src/main/res/drawable-mdpi/ic_carriage_return.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_deafened.png b/app/src/main/res/drawable-mdpi/ic_deafened.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_drawer.png b/app/src/main/res/drawable-mdpi/ic_drawer.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_home.png b/app/src/main/res/drawable-mdpi/ic_home.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_launcher.png b/app/src/main/res/drawable-mdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_menu_moreoverflow_card_dark_normal.png b/app/src/main/res/drawable-mdpi/ic_menu_moreoverflow_card_dark_normal.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_menu_moreoverflow_card_dark_pressed.png b/app/src/main/res/drawable-mdpi/ic_menu_moreoverflow_card_dark_pressed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_muted.png b/app/src/main/res/drawable-mdpi/ic_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_muted_local.png b/app/src/main/res/drawable-mdpi/ic_muted_local.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_registered.png b/app/src/main/res/drawable-mdpi/ic_registered.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_server_deafened.png b/app/src/main/res/drawable-mdpi/ic_server_deafened.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_server_light.png b/app/src/main/res/drawable-mdpi/ic_server_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_server_location.png b/app/src/main/res/drawable-mdpi/ic_server_location.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_server_muted.png b/app/src/main/res/drawable-mdpi/ic_server_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_stat_notify.png b/app/src/main/res/drawable-mdpi/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_suppressed.png b/app/src/main/res/drawable-mdpi/ic_suppressed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_talking_off.png b/app/src/main/res/drawable-mdpi/ic_talking_off.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_talking_on.png b/app/src/main/res/drawable-mdpi/ic_talking_on.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/ic_user_light.png b/app/src/main/res/drawable-mdpi/ic_user_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/list_longpressed.9.png b/app/src/main/res/drawable-mdpi/list_longpressed.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/list_pressed.9.png b/app/src/main/res/drawable-mdpi/list_pressed.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/list_selector_disabled.9.png b/app/src/main/res/drawable-mdpi/list_selector_disabled.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/list_selector_focused.9.png b/app/src/main/res/drawable-mdpi/list_selector_focused.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-mdpi/server_card.9.png b/app/src/main/res/drawable-mdpi/server_card.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi-v11/ic_stat_notify.png b/app/src/main/res/drawable-xhdpi-v11/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi-v9/ic_stat_notify.png b/app/src/main/res/drawable-xhdpi-v9/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_add_dark.png b/app/src/main/res/drawable-xhdpi/ic_action_add_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_add_light.png b/app/src/main/res/drawable-xhdpi/ic_action_add_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_audio.png b/app/src/main/res/drawable-xhdpi/ic_action_audio.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_audio_muted.png b/app/src/main/res/drawable-xhdpi/ic_action_audio_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_bad.png b/app/src/main/res/drawable-xhdpi/ic_action_bad.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_channels.png b/app/src/main/res/drawable-xhdpi/ic_action_channels.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_chat.png b/app/src/main/res/drawable-xhdpi/ic_action_chat.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_collapsed.png b/app/src/main/res/drawable-xhdpi/ic_action_collapsed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_comment.png b/app/src/main/res/drawable-xhdpi/ic_action_comment.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_delete_dark.png b/app/src/main/res/drawable-xhdpi/ic_action_delete_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_delete_light.png b/app/src/main/res/drawable-xhdpi/ic_action_delete_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_drag_handle.png b/app/src/main/res/drawable-xhdpi/ic_action_drag_handle.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_edit_dark.png b/app/src/main/res/drawable-xhdpi/ic_action_edit_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_error.png b/app/src/main/res/drawable-xhdpi/ic_action_error.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_expanded.png b/app/src/main/res/drawable-xhdpi/ic_action_expanded.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_favourite_on.png b/app/src/main/res/drawable-xhdpi/ic_action_favourite_on.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_fullscreen.png b/app/src/main/res/drawable-xhdpi/ic_action_fullscreen.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_headphones.png b/app/src/main/res/drawable-xhdpi/ic_action_headphones.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_info_dark.png b/app/src/main/res/drawable-xhdpi/ic_action_info_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_match.png b/app/src/main/res/drawable-xhdpi/ic_action_match.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_microphone.png b/app/src/main/res/drawable-xhdpi/ic_action_microphone.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_microphone_dark.png b/app/src/main/res/drawable-xhdpi/ic_action_microphone_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_microphone_muted.png b/app/src/main/res/drawable-xhdpi/ic_action_microphone_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_move.png b/app/src/main/res/drawable-xhdpi/ic_action_move.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_save.png b/app/src/main/res/drawable-xhdpi/ic_action_save.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_search.png b/app/src/main/res/drawable-xhdpi/ic_action_search.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_send.png b/app/src/main/res/drawable-xhdpi/ic_action_send.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_settings.png b/app/src/main/res/drawable-xhdpi/ic_action_settings.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_sort.png b/app/src/main/res/drawable-xhdpi/ic_action_sort.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_user_dark.png b/app/src/main/res/drawable-xhdpi/ic_action_user_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_carriage_return.png b/app/src/main/res/drawable-xhdpi/ic_carriage_return.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_deafened.png b/app/src/main/res/drawable-xhdpi/ic_deafened.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer.png b/app/src/main/res/drawable-xhdpi/ic_drawer.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_home.png b/app/src/main/res/drawable-xhdpi/ic_home.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_card_dark_normal.png b/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_card_dark_normal.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_card_dark_pressed.png b/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_card_dark_pressed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_muted.png b/app/src/main/res/drawable-xhdpi/ic_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_muted_local.png b/app/src/main/res/drawable-xhdpi/ic_muted_local.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_registered.png b/app/src/main/res/drawable-xhdpi/ic_registered.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_server_deafened.png b/app/src/main/res/drawable-xhdpi/ic_server_deafened.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_server_light.png b/app/src/main/res/drawable-xhdpi/ic_server_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_server_location.png b/app/src/main/res/drawable-xhdpi/ic_server_location.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_server_muted.png b/app/src/main/res/drawable-xhdpi/ic_server_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_notify.png b/app/src/main/res/drawable-xhdpi/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_suppressed.png b/app/src/main/res/drawable-xhdpi/ic_suppressed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_talking_off.png b/app/src/main/res/drawable-xhdpi/ic_talking_off.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_talking_on.png b/app/src/main/res/drawable-xhdpi/ic_talking_on.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/ic_user_light.png b/app/src/main/res/drawable-xhdpi/ic_user_light.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/list_longpressed.9.png b/app/src/main/res/drawable-xhdpi/list_longpressed.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/list_pressed.9.png b/app/src/main/res/drawable-xhdpi/list_pressed.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/list_selector_disabled.9.png b/app/src/main/res/drawable-xhdpi/list_selector_disabled.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/list_selector_focused.9.png b/app/src/main/res/drawable-xhdpi/list_selector_focused.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xhdpi/server_card.9.png b/app/src/main/res/drawable-xhdpi/server_card.9.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi-v11/ic_stat_notify.png b/app/src/main/res/drawable-xxhdpi-v11/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi-v9/ic_stat_notify.png b/app/src/main/res/drawable-xxhdpi-v9/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_audio.png b/app/src/main/res/drawable-xxhdpi/ic_action_audio.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_audio_muted.png b/app/src/main/res/drawable-xxhdpi/ic_action_audio_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_chat.png b/app/src/main/res/drawable-xxhdpi/ic_action_chat.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_collapsed.png b/app/src/main/res/drawable-xxhdpi/ic_action_collapsed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_drag_handle.png b/app/src/main/res/drawable-xxhdpi/ic_action_drag_handle.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_expanded.png b/app/src/main/res/drawable-xxhdpi/ic_action_expanded.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_headphones.png b/app/src/main/res/drawable-xxhdpi/ic_action_headphones.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_microphone.png b/app/src/main/res/drawable-xxhdpi/ic_action_microphone.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_microphone_dark.png b/app/src/main/res/drawable-xxhdpi/ic_action_microphone_dark.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_microphone_muted.png b/app/src/main/res/drawable-xxhdpi/ic_action_microphone_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_move.png b/app/src/main/res/drawable-xxhdpi/ic_action_move.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_deafened.png b/app/src/main/res/drawable-xxhdpi/ic_deafened.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_home.png b/app/src/main/res/drawable-xxhdpi/ic_home.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/app/src/main/res/drawable-xxhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_muted.png b/app/src/main/res/drawable-xxhdpi/ic_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_muted_local.png b/app/src/main/res/drawable-xxhdpi/ic_muted_local.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_server_deafened.png b/app/src/main/res/drawable-xxhdpi/ic_server_deafened.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_server_muted.png b/app/src/main/res/drawable-xxhdpi/ic_server_muted.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_stat_notify.png b/app/src/main/res/drawable-xxhdpi/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_suppressed.png b/app/src/main/res/drawable-xxhdpi/ic_suppressed.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_talking_off.png b/app/src/main/res/drawable-xxhdpi/ic_talking_off.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable-xxhdpi/ic_talking_on.png b/app/src/main/res/drawable-xxhdpi/ic_talking_on.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/ic_card_overflow.xml b/app/src/main/res/drawable/ic_card_overflow.xml old mode 100644 new mode 100755 index 8caf1360..ebcd50ef --- a/app/src/main/res/drawable/ic_card_overflow.xml +++ b/app/src/main/res/drawable/ic_card_overflow.xml @@ -1,22 +1,4 @@ - - - diff --git a/app/src/main/res/drawable/ic_stat_notify.png b/app/src/main/res/drawable/ic_stat_notify.png old mode 100644 new mode 100755 diff --git a/app/src/main/res/drawable/outline_circle.xml b/app/src/main/res/drawable/outline_circle.xml old mode 100644 new mode 100755 index 9a5fb33f..7ccc0d62 --- a/app/src/main/res/drawable/outline_circle.xml +++ b/app/src/main/res/drawable/outline_circle.xml @@ -1,23 +1,4 @@ - - - - diff --git a/app/src/main/res/drawable/outline_circle_deafened.xml b/app/src/main/res/drawable/outline_circle_deafened.xml old mode 100644 new mode 100755 index ef4f9ebb..4f5e732c --- a/app/src/main/res/drawable/outline_circle_deafened.xml +++ b/app/src/main/res/drawable/outline_circle_deafened.xml @@ -1,23 +1,4 @@ - - - - diff --git a/app/src/main/res/drawable/outline_circle_muted.xml b/app/src/main/res/drawable/outline_circle_muted.xml old mode 100644 new mode 100755 index 5ea80985..f487c9cd --- a/app/src/main/res/drawable/outline_circle_muted.xml +++ b/app/src/main/res/drawable/outline_circle_muted.xml @@ -1,23 +1,4 @@ - - - - diff --git a/app/src/main/res/drawable/outline_circle_server_deafened.xml b/app/src/main/res/drawable/outline_circle_server_deafened.xml old mode 100644 new mode 100755 index fa0a3445..097a9d65 --- a/app/src/main/res/drawable/outline_circle_server_deafened.xml +++ b/app/src/main/res/drawable/outline_circle_server_deafened.xml @@ -1,23 +1,4 @@ - - - - diff --git a/app/src/main/res/drawable/outline_circle_server_muted.xml b/app/src/main/res/drawable/outline_circle_server_muted.xml old mode 100644 new mode 100755 index a9943898..55e2ef60 --- a/app/src/main/res/drawable/outline_circle_server_muted.xml +++ b/app/src/main/res/drawable/outline_circle_server_muted.xml @@ -1,23 +1,4 @@ - - - - diff --git a/app/src/main/res/drawable/outline_circle_suppressed.xml b/app/src/main/res/drawable/outline_circle_suppressed.xml old mode 100644 new mode 100755 index 650df2df..86b2bf5d --- a/app/src/main/res/drawable/outline_circle_suppressed.xml +++ b/app/src/main/res/drawable/outline_circle_suppressed.xml @@ -1,23 +1,4 @@ - - - - diff --git a/app/src/main/res/drawable/outline_circle_talking_off.xml b/app/src/main/res/drawable/outline_circle_talking_off.xml old mode 100644 new mode 100755 index 19c148d9..9b1c8ab9 --- a/app/src/main/res/drawable/outline_circle_talking_off.xml +++ b/app/src/main/res/drawable/outline_circle_talking_off.xml @@ -1,23 +1,4 @@ - - - - diff --git a/app/src/main/res/drawable/outline_circle_talking_on.xml b/app/src/main/res/drawable/outline_circle_talking_on.xml old mode 100644 new mode 100755 index e03e81a8..487a533e --- a/app/src/main/res/drawable/outline_circle_talking_on.xml +++ b/app/src/main/res/drawable/outline_circle_talking_on.xml @@ -1,23 +1,4 @@ - - - - diff --git a/app/src/main/res/drawable/overlay_background.xml b/app/src/main/res/drawable/overlay_background.xml old mode 100644 new mode 100755 index 8f9e692c..eec256f2 --- a/app/src/main/res/drawable/overlay_background.xml +++ b/app/src/main/res/drawable/overlay_background.xml @@ -1,22 +1,4 @@ - - - diff --git a/app/src/main/res/drawable/popup_menu_item_background.xml b/app/src/main/res/drawable/popup_menu_item_background.xml old mode 100644 new mode 100755 index 1818fbd0..91b0d740 --- a/app/src/main/res/drawable/popup_menu_item_background.xml +++ b/app/src/main/res/drawable/popup_menu_item_background.xml @@ -1,22 +1,4 @@ - - - diff --git a/app/src/main/res/drawable/ptt_indicator_background.xml b/app/src/main/res/drawable/ptt_indicator_background.xml old mode 100644 new mode 100755 index ae1b88dd..7b42c5f1 --- a/app/src/main/res/drawable/ptt_indicator_background.xml +++ b/app/src/main/res/drawable/ptt_indicator_background.xml @@ -1,22 +1,4 @@ - - - - - - - . - --> - - - - - - - - - - - - - - - - - - - - - + + android:visibility="invisible" /> + android:visibility="invisible" /> + android:visibility="invisible" /> + android:visibility="invisible" /> + android:textStyle="bold" /> + android:text="Error: error text here." + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/holo_red_dark" + android:visibility="gone" /> diff --git a/app/src/main/res/layout/dialog_server_search.xml b/app/src/main/res/layout/dialog_server_search.xml old mode 100644 new mode 100755 index 85f7db0c..d0a86fdf --- a/app/src/main/res/layout/dialog_server_search.xml +++ b/app/src/main/res/layout/dialog_server_search.xml @@ -1,21 +1,4 @@ - - . - --> - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_channel_edit.xml b/app/src/main/res/layout/fragment_channel_edit.xml old mode 100644 new mode 100755 index 6fd20b4d..63c2bf54 --- a/app/src/main/res/layout/fragment_channel_edit.xml +++ b/app/src/main/res/layout/fragment_channel_edit.xml @@ -1,22 +1,4 @@ - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_server_list.xml b/app/src/main/res/layout/fragment_server_list.xml old mode 100644 new mode 100755 index 762b3f04..ce2d5549 --- a/app/src/main/res/layout/fragment_server_list.xml +++ b/app/src/main/res/layout/fragment_server_list.xml @@ -1,20 +1,4 @@ - - - - diff --git a/app/src/main/res/layout/fragment_tokens.xml b/app/src/main/res/layout/fragment_tokens.xml old mode 100644 new mode 100755 index cedbf04a..4bb67ad3 --- a/app/src/main/res/layout/fragment_tokens.xml +++ b/app/src/main/res/layout/fragment_tokens.xml @@ -1,20 +1,4 @@ - - - - - - -