Index: src/org/adblockplus/android/Preferences.java |
=================================================================== |
new file mode 100755 |
--- /dev/null |
+++ b/src/org/adblockplus/android/Preferences.java |
@@ -0,0 +1,473 @@ |
+package org.adblockplus.android; |
+ |
+import java.io.IOException; |
+import java.io.InputStream; |
+import java.io.OutputStream; |
+import java.util.Calendar; |
+import java.util.Date; |
+import java.util.List; |
+ |
+import android.app.ActivityManager; |
+import android.app.ActivityManager.RunningServiceInfo; |
+import android.app.AlertDialog; |
+import android.content.BroadcastReceiver; |
+import android.content.Context; |
+import android.content.DialogInterface; |
+import android.content.DialogInterface.OnDismissListener; |
+import android.content.Intent; |
+import android.content.IntentFilter; |
+import android.content.SharedPreferences; |
+import android.content.pm.PackageManager.NameNotFoundException; |
+import android.content.res.AssetManager; |
+import android.net.Uri; |
+import android.os.Bundle; |
+import android.preference.CheckBoxPreference; |
+import android.preference.ListPreference; |
+import android.preference.PreferenceManager; |
+import android.text.format.DateFormat; |
+import android.util.Log; |
+import android.view.Menu; |
+import android.view.MenuInflater; |
+import android.view.MenuItem; |
+import android.view.View; |
+import android.view.Window; |
+import android.widget.TextView; |
+ |
+/** |
+ * Main settings UI. |
+ */ |
+public class Preferences extends SummarizedPreferences |
+{ |
+ private final static String TAG = "Preferences"; |
Felix Dahlke
2012/10/09 14:27:29
As in AdvancedPreferences, "static final"?
Andrey Novikov
2012/10/12 13:19:14
Done.
|
+ |
+ private AboutDialog aboutDialog; |
+ private boolean showAbout = false; |
+ private String configurationMsg; |
+ private String subscriptionSummary; |
+ |
+ @Override |
+ public void onCreate(Bundle savedInstanceState) |
+ { |
+ requestWindowFeature(Window.FEATURE_NO_TITLE); |
+ |
+ super.onCreate(savedInstanceState); |
+ |
+ PreferenceManager.setDefaultValues(this, R.xml.preferences, false); |
+ PreferenceManager.setDefaultValues(this, R.xml.preferences_advanced, false); |
+ setContentView(R.layout.preferences); |
+ addPreferencesFromResource(R.xml.preferences); |
+ |
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); |
+ |
+ // Check if we need to update assets |
+ int lastVersion = prefs.getInt(getString(R.string.pref_version), 0); |
+ try |
+ { |
+ int thisVersion = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode; |
+ if (lastVersion != thisVersion) |
+ { |
+ copyAssets(); |
+ SharedPreferences.Editor editor = prefs.edit(); |
+ editor.putInt(getString(R.string.pref_version), thisVersion); |
+ editor.commit(); |
+ } |
+ } |
+ catch (NameNotFoundException e) |
+ { |
+ copyAssets(); |
Felix Dahlke
2012/10/09 14:27:29
Why can this getPackageInfo fail while those in Ab
Andrey Novikov
2012/10/12 13:19:14
It can not. But I prefer to be reinsured in this c
|
+ } |
+ } |
+ |
+ @Override |
+ protected void onStart() |
+ { |
+ super.onStart(); |
+ AdblockPlus application = AdblockPlus.getApplication(); |
+ application.startEngine(); |
+ application.startInteractive(); |
+ } |
+ |
+ @Override |
+ public void onResume() |
Felix Dahlke
2012/10/09 14:27:29
Another long method, same comment as for AdvancedP
Andrey Novikov
2012/10/12 13:19:14
Same comment :) See code comments - they are for y
|
+ { |
+ super.onResume(); |
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); |
+ |
+ final AdblockPlus application = AdblockPlus.getApplication(); |
+ |
+ // Construct subscription list |
+ RefreshableListPreference subscriptionList = (RefreshableListPreference) findPreference(getString(R.string.pref_subscription)); |
+ List<Subscription> subscriptions = application.getSubscriptions(); |
+ String[] entries = new String[subscriptions.size()]; |
+ String[] entryValues = new String[subscriptions.size()]; |
+ String current = prefs.getString(getString(R.string.pref_subscription), (String) null); |
+ int i = 0; |
+ for (Subscription subscription : subscriptions) |
+ { |
+ entries[i] = subscription.title; |
+ entryValues[i] = subscription.url; |
+ i++; |
+ } |
+ subscriptionList.setEntries(entries); |
+ subscriptionList.setEntryValues(entryValues); |
+ |
+ boolean firstRun = false; |
+ |
+ // If there is no current subscription autoselect one |
+ if (current == null) |
+ { |
+ firstRun = true; |
+ Subscription offer = application.offerSubscription(); |
+ current = offer.url; |
+ if (offer != null) |
+ { |
+ subscriptionList.setValue(offer.url); |
+ application.setSubscription(offer); |
+ new AlertDialog.Builder(this).setTitle(R.string.app_name).setMessage(String.format(getString(R.string.msg_subscription_offer, offer.title))).setIcon(android.R.drawable.ic_dialog_info) |
+ .setPositiveButton(R.string.ok, null).create().show(); |
+ } |
+ } |
+ |
+ // Enable manual subscription refresh |
+ subscriptionList.setOnRefreshClickListener(new View.OnClickListener() { |
Felix Dahlke
2012/10/09 14:27:29
Brace on its own line please.
Andrey Novikov
2012/10/12 13:19:14
Done.
|
+ @Override |
+ public void onClick(View v) |
+ { |
+ application.refreshSubscription(); |
+ } |
+ }); |
+ |
+ // Set subscription status message |
+ if (subscriptionSummary != null) |
+ subscriptionList.setSummary(subscriptionSummary); |
+ else |
+ setPrefSummary(subscriptionList); |
+ |
+ // Time to start listening for events |
+ registerReceiver(receiver, new IntentFilter(AdblockPlus.BROADCAST_SUBSCRIPTION_STATUS)); |
+ registerReceiver(receiver, new IntentFilter(AdblockPlus.BROADCAST_FILTER_MATCHES)); |
+ registerReceiver(receiver, new IntentFilter(ProxyService.BROADCAST_STATE_CHANGED)); |
+ registerReceiver(receiver, new IntentFilter(ProxyService.BROADCAST_PROXY_FAILED)); |
+ |
+ final String url = current; |
+ |
+ // Initialize subscription verification |
+ (new Thread() { |
Felix Dahlke
2012/10/09 14:27:29
Brace on its own line please.
Andrey Novikov
2012/10/12 13:19:14
Done.
|
+ @Override |
+ public void run() |
+ { |
+ if (!application.verifySubscriptions()) |
+ { |
+ Subscription subscription = application.getSubscription(url); |
+ application.setSubscription(subscription); |
+ } |
+ } |
+ }).start(); |
+ |
+ // Check if service is running and update UI accordingly |
+ boolean enabled = prefs.getBoolean(getString(R.string.pref_enabled), false); |
+ if (enabled && !isServiceRunning()) |
+ { |
+ setEnabled(false); |
+ enabled = false; |
Felix Dahlke
2012/10/09 14:27:29
enabled isn't read past this point, Setting it to
Andrey Novikov
2012/10/12 13:19:14
Done.
|
+ } |
+ // Run service if this is first application run |
+ else if (!enabled && firstRun) |
+ { |
+ startService(new Intent(this, ProxyService.class)); |
+ setEnabled(true); |
+ } |
+ |
+ // Process screen rotation |
+ if (configurationMsg != null) |
+ showConfigurationMsg(configurationMsg); |
+ |
+ if (showAbout) |
+ onAbout(findViewById(R.id.btn_about)); |
+ } |
+ |
+ @Override |
+ public void onPause() |
+ { |
+ super.onPause(); |
+ unregisterReceiver(receiver); |
+ } |
+ |
+ @Override |
+ protected void onStop() |
+ { |
+ super.onStop(); |
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); |
+ boolean enabled = prefs.getBoolean(getString(R.string.pref_enabled), false); |
+ AdblockPlus application = AdblockPlus.getApplication(); |
+ application.stopInteractive(); |
+ if (!enabled) |
+ application.stopEngine(true); |
+ |
+ if (aboutDialog != null) |
+ aboutDialog.dismiss(); |
+ } |
+ |
+ @Override |
+ public boolean onCreateOptionsMenu(Menu menu) |
+ { |
+ MenuInflater inflater = getMenuInflater(); |
+ inflater.inflate(R.menu.menu_preferences, menu); |
+ return true; |
+ } |
+ |
+ @Override |
+ public boolean onOptionsItemSelected(MenuItem item) |
+ { |
+ switch (item.getItemId()) |
+ { |
+ case R.id.menu_advanced: |
+ startActivity(new Intent(this, AdvancedPreferences.class)); |
+ return true; |
+ default: |
+ return super.onOptionsItemSelected(item); |
+ } |
+ } |
+ |
+ private void setEnabled(boolean enabled) |
+ { |
+ SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit(); |
+ editor.putBoolean(getString(R.string.pref_enabled), enabled); |
+ editor.commit(); |
+ ((CheckBoxPreference) findPreference(getString(R.string.pref_enabled))).setChecked(enabled); |
+ } |
+ |
+ /** |
+ * Checks if ProxyService is running. |
+ * |
+ * @return true if service is running |
+ */ |
+ private boolean isServiceRunning() |
+ { |
+ ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); |
+ // Actually it returns not only running services, so extra check is required |
+ for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) |
+ { |
+ if ("org.adblockplus.android.ProxyService".equals(service.service.getClassName()) && service.pid > 0) |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ /** |
+ * Copies file assets from installation package to filesystem. |
+ */ |
+ private void copyAssets() |
+ { |
+ AssetManager assetManager = getAssets(); |
+ String[] files = null; |
+ try |
+ { |
+ files = assetManager.list("install"); |
+ } |
+ catch (IOException e) |
+ { |
+ Log.e(TAG, e.getMessage()); |
Felix Dahlke
2012/10/09 14:27:29
Why not pass e as the third parameter, like below?
Andrey Novikov
2012/10/12 13:19:14
Done.
|
+ } |
+ for (int i = 0; i < files.length; i++) |
+ { |
+ InputStream in = null; |
Felix Dahlke
2012/10/09 14:27:29
in and out can be declared in the try block, they
Andrey Novikov
2012/10/12 13:19:14
Done.
|
+ OutputStream out = null; |
+ try |
+ { |
+ Log.d(TAG, "Copy: install/" + files[i]); |
+ in = assetManager.open("install/" + files[i]); |
+ out = openFileOutput(files[i], MODE_PRIVATE); |
+ byte[] buffer = new byte[1024]; |
+ int read; |
+ while ((read = in.read(buffer)) != -1) |
+ { |
+ out.write(buffer, 0, read); |
+ } |
+ in.close(); |
+ in = null; |
Felix Dahlke
2012/10/09 14:27:29
You don't need to set in/out to null, they aren't
Andrey Novikov
2012/10/12 13:19:14
Done.
|
+ out.flush(); |
+ out.close(); |
+ out = null; |
+ |
+ } |
+ catch (Exception e) |
+ { |
+ Log.e(TAG, "Asset copy error", e); |
+ } |
+ } |
+ } |
+ |
+ /** |
+ * Redirects user to configuration URL. |
+ */ |
+ public void onHelp(View view) |
+ { |
+ Uri uri = Uri.parse(getString(R.string.configuring_url)); |
+ final Intent intent = new Intent(Intent.ACTION_VIEW, uri); |
Felix Dahlke
2012/10/09 14:27:29
Why make intent final?
Andrey Novikov
2012/10/12 13:19:14
No reason, just copied url opening code from sampl
|
+ startActivity(intent); |
+ } |
+ |
+ /** |
+ * Shows about dialog. |
+ */ |
+ public void onAbout(View view) |
+ { |
+ aboutDialog = new AboutDialog(this); |
+ aboutDialog.setOnDismissListener(new OnDismissListener() { |
+ |
+ @Override |
+ public void onDismiss(DialogInterface dialog) |
+ { |
+ showAbout = false; |
Felix Dahlke
2012/10/09 14:27:29
Naming nit pick: This sounds imperative, how about
Andrey Novikov
2012/10/12 13:19:14
For me name is correct - it flags if have to show
|
+ aboutDialog = null; |
+ } |
+ }); |
+ showAbout = true; |
+ aboutDialog.show(); |
+ } |
+ |
+ @Override |
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) |
+ { |
+ if (getString(R.string.pref_enabled).equals(key)) |
+ { |
+ boolean enabled = sharedPreferences.getBoolean(key, false); |
+ if (enabled && !isServiceRunning()) |
+ startService(new Intent(this, ProxyService.class)); |
+ else if (!enabled && isServiceRunning()) |
Felix Dahlke
2012/10/09 14:27:29
I'd feel safer is isServiceRunning() was called ju
Andrey Novikov
2012/10/12 13:19:14
Done.
|
+ stopService(new Intent(this, ProxyService.class)); |
+ } |
+ if (getString(R.string.pref_subscription).equals(key)) |
+ { |
+ String current = sharedPreferences.getString(key, null); |
+ AdblockPlus application = AdblockPlus.getApplication(); |
+ Subscription subscription = application.getSubscription(current); |
+ application.setSubscription(subscription); |
+ } |
+ super.onSharedPreferenceChanged(sharedPreferences, key); |
+ } |
+ |
+ private void showConfigurationMsg(String message) |
+ { |
+ TextView msg = (TextView) findViewById(R.id.txt_configuration); |
+ msg.setText(message); |
+ msg.setVisibility(View.VISIBLE); |
+ configurationMsg = message; |
+ } |
+ |
+ private void hideConfigurationMsg() |
+ { |
+ if (configurationMsg == null) |
+ return; |
+ TextView msg = (TextView) findViewById(R.id.txt_configuration); |
+ msg.setVisibility(View.GONE); |
+ configurationMsg = null; |
+ } |
+ |
+ private BroadcastReceiver receiver = new BroadcastReceiver() { |
Felix Dahlke
2012/10/09 14:27:29
Brace on a new line please.
Andrey Novikov
2012/10/12 13:19:14
Done.
|
+ @Override |
+ public void onReceive(final Context context, Intent intent) |
Felix Dahlke
2012/10/09 14:27:29
Why make context final?
Andrey Novikov
2012/10/12 13:19:14
It was previously used in a new thread, fixed.
|
+ { |
+ String action = intent.getAction(); |
+ Bundle extra = intent.getExtras(); |
+ if (action.equals(ProxyService.BROADCAST_STATE_CHANGED)) |
+ { |
+ if (extra.getBoolean("enabled")) |
+ { |
+ // If service is enabled in manual mode, show configuration message |
+ if (extra.getBoolean("manual")) |
+ { |
+ showConfigurationMsg(getString(R.string.msg_configuration, extra.getInt("port"))); |
+ } |
+ } |
+ else |
+ { |
+ setEnabled(false); |
+ hideConfigurationMsg(); |
+ } |
+ } |
+ if (action.equals(AdblockPlus.BROADCAST_FILTER_MATCHES)) |
+ { |
+ // Hide configuration message if traffic is detected |
+ hideConfigurationMsg(); |
+ } |
+ if (action.equals(ProxyService.BROADCAST_PROXY_FAILED)) |
+ { |
+ String msg = extra.getString("msg"); |
+ new AlertDialog.Builder(Preferences.this).setTitle(R.string.error).setMessage(msg).setIcon(android.R.drawable.ic_dialog_alert).setPositiveButton(R.string.ok, null).create().show(); |
+ setEnabled(false); |
+ } |
+ if (action.equals(AdblockPlus.BROADCAST_SUBSCRIPTION_STATUS)) |
+ { |
+ final String text = extra.getString("text"); |
+ final long time = extra.getLong("time"); |
+ runOnUiThread(new Runnable() { |
+ public void run() |
+ { |
+ setSubscriptionStatus(text, time); |
+ } |
+ }); |
+ } |
+ } |
+ }; |
+ |
+ /** |
+ * Constructs and updates subscription status text. |
+ * |
+ * @param text |
+ * status message |
+ * @param time |
+ * time of last change |
+ */ |
+ private void setSubscriptionStatus(String text, long time) |
+ { |
+ ListPreference subscriptionList = (ListPreference) findPreference(getString(R.string.pref_subscription)); |
+ CharSequence summary = subscriptionList.getEntry(); |
+ StringBuilder builder = new StringBuilder(); |
+ if (summary != null) |
+ { |
+ builder.append(summary); |
+ if (text != "") |
+ { |
+ builder.append(" ("); |
+ int id = getResources().getIdentifier(text, "string", getPackageName()); |
+ if (id > 0) |
+ builder.append(getString(id, text)); |
+ else |
+ builder.append(text); |
+ if (time > 0) |
+ { |
+ builder.append(": "); |
+ Calendar calendar = Calendar.getInstance(); |
+ calendar.setTimeInMillis(time); |
+ Date date = calendar.getTime(); |
+ builder.append(DateFormat.getDateFormat(this).format(date)); |
+ builder.append(" "); |
+ builder.append(DateFormat.getTimeFormat(this).format(date)); |
+ } |
+ builder.append(")"); |
+ } |
+ subscriptionSummary = builder.toString(); |
+ subscriptionList.setSummary(subscriptionSummary); |
+ } |
+ } |
+ |
+ @Override |
+ protected void onRestoreInstanceState(Bundle state) |
+ { |
+ super.onRestoreInstanceState(state); |
+ showAbout = state.getBoolean("showAbout"); |
+ configurationMsg = state.getString("configurationMsg"); |
+ subscriptionSummary = state.getString("subscriptionSummary"); |
+ } |
+ |
+ @Override |
+ protected void onSaveInstanceState(Bundle outState) |
+ { |
+ outState.putString("subscriptionSummary", subscriptionSummary); |
+ outState.putString("configurationMsg", configurationMsg); |
+ outState.putBoolean("showAbout", showAbout); |
+ super.onSaveInstanceState(outState); |
+ } |
+} |