Java tutorial
/* * This file is part of Adblock Plus <https://adblockplus.org/>, * Copyright (C) 2006-2016 Eyeo GmbH * * Adblock Plus is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>. */ 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 org.apache.commons.lang.StringUtils; import org.jraf.android.backport.switchwidget.SwitchPreference; import android.app.AlertDialog; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; 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.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.PreferenceManager; import android.text.Html; import android.text.TextUtils; import android.text.format.DateFormat; import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; /** * Main settings UI. */ public class Preferences extends SummarizedPreferences { private static final String TAG = Utils.getTag(Preferences.class); private static final int ABOUT_DIALOG = 1; private static final int HIDEICONWARNING_DIALOG = 2; private static boolean firstRunActionsPending = true; private RefreshableListPreference subscriptionList; private String subscriptionSummary; private ServiceBinder serviceBinder = null; @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.serviceBinder = new ServiceBinder(this).setOnConnectHandler(new ServiceBinder.OnConnectHandler() { @Override public void onConnect(final ProxyService proxyService) { if (proxyService.isManual() && !proxyService.isRegistered()) { Preferences.this.showConfigurationMsg(Preferences.this.getString(R.string.msg_configuration)); } } }); PreferenceManager.setDefaultValues(this, R.xml.preferences, true); PreferenceManager.setDefaultValues(this, R.xml.preferences_advanced, true); setContentView(R.layout.preferences); addPreferencesFromResource(R.xml.preferences); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); // Check if we need to update assets final int lastVersion = prefs.getInt(getString(R.string.pref_version), 0); try { final int thisVersion = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode; if (lastVersion != thisVersion) { copyAssets(); final SharedPreferences.Editor editor = prefs.edit(); editor.putInt(getString(R.string.pref_version), thisVersion); editor.commit(); } } catch (final NameNotFoundException e) { copyAssets(); } } @Override protected void onStart() { super.onStart(); final AdblockPlus application = AdblockPlus.getApplication(); application.startEngine(); // Initialize subscription list subscriptionList = (RefreshableListPreference) findPreference(getString(R.string.pref_subscription)); final Subscription[] subscriptions = application.getRecommendedSubscriptions(); final String[] entries = new String[subscriptions.length]; final String[] entryValues = new String[subscriptions.length]; int i = 0; for (final Subscription subscription : subscriptions) { entries[i] = subscription.title; entryValues[i] = subscription.url; i++; } subscriptionList.setEntries(entries); subscriptionList.setEntryValues(entryValues); // Set Acceptable Ads FAQ link final HelpfulCheckBoxPreference acceptableAdsCheckBox = (HelpfulCheckBoxPreference) findPreference( getString(R.string.pref_acceptableads)); acceptableAdsCheckBox.setHelpUrl(AdblockPlus.getApplication().getAcceptableAdsUrl()); } @Override public void onResume() { super.onResume(); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); final AdblockPlus application = AdblockPlus.getApplication(); Subscription current = null; final Subscription[] subscriptions = application.getListedSubscriptions(); if (subscriptions.length > 0) { current = subscriptions[0]; } final boolean firstRun = firstRunActionsPending && application.isFirstRun(); firstRunActionsPending = false; if (firstRun && current != null) { showNotificationDialog(getString(R.string.install_name), String.format(getString(R.string.msg_subscription_offer), current.title), application.getAcceptableAdsUrl()); application.setNotifiedAboutAcceptableAds(true); setAcceptableAdsEnabled(true); } else if (!application.isNotifiedAboutAcceptableAds()) { showNotificationDialog(getString(R.string.acceptableads_name), getString(R.string.msg_acceptable_ads), application.getAcceptableAdsUrl()); application.setNotifiedAboutAcceptableAds(true); setAcceptableAdsEnabled(true); } // Enable manual subscription refresh subscriptionList.setOnRefreshClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { application.refreshSubscriptions(); } }); // 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(ProxyService.BROADCAST_STATE_CHANGED)); registerReceiver(receiver, new IntentFilter(ProxyService.BROADCAST_PROXY_FAILED)); // Update service and UI state according to user settings if (current != null) { subscriptionList.setValue(current.url); application.updateSubscriptionStatus(current.url); } final boolean enabled = prefs.getBoolean(getString(R.string.pref_enabled), false); final boolean proxyenabled = prefs.getBoolean(getString(R.string.pref_proxyenabled), true); final boolean autoconfigured = prefs.getBoolean(getString(R.string.pref_proxyautoconfigured), false); // This is weird but UI does not update on back button (when returning from advanced preferences) ((SwitchPreference) findPreference(getString(R.string.pref_enabled))).setChecked(enabled); if (enabled || firstRun) setFilteringEnabled(true); if (enabled || firstRun || (proxyenabled && !autoconfigured)) setProxyEnabled(true); this.serviceBinder.bind(); } private void showNotificationDialog(final String title, String message, String url) { url = TextUtils.htmlEncode(url); message = TextUtils.htmlEncode(message).replaceAll("<a>(.*?)</a>", "<a href=\"" + url + "\">$1</a>"); final TextView messageView = new TextView(this); messageView.setText(Html.fromHtml(message)); messageView.setMovementMethod(LinkMovementMethod.getInstance()); final int padding = 10; messageView.setPadding(padding, padding, padding, padding); new AlertDialog.Builder(this).setTitle(title).setView(messageView) .setIcon(android.R.drawable.ic_dialog_info).setPositiveButton(R.string.ok, null).create().show(); } @Override public void onPause() { super.onPause(); try { unregisterReceiver(receiver); } catch (final IllegalArgumentException e) { // ignore - it is thrown if receiver is not registered but it can not be // true in normal conditions } this.serviceBinder.unbind(); hideConfigurationMsg(); } @Override protected void onStop() { super.onStop(); final AdblockPlus application = AdblockPlus.getApplication(); if (!application.isFilteringEnabled()) application.stopEngine(); } @Override public boolean onCreateOptionsMenu(final Menu menu) { final MenuInflater inflater = getSupportMenuInflater(); inflater.inflate(R.menu.menu_preferences, menu); return true; } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.menu_help: final Uri uri = Uri.parse(getString(R.string.configuring_url)); final Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); return true; case R.id.menu_about: showDialog(ABOUT_DIALOG); return true; case R.id.menu_advanced: startActivity(new Intent(this, AdvancedPreferences.class)); return true; default: return super.onOptionsItemSelected(item); } } private void setAcceptableAdsEnabled(final boolean enabled) { final CheckBoxPreference acceptableAdsPreference = (CheckBoxPreference) findPreference( getString(R.string.pref_acceptableads)); acceptableAdsPreference.setChecked(enabled); final AdblockPlus application = AdblockPlus.getApplication(); application.setAcceptableAdsEnabled(enabled); } private void setFilteringEnabled(final boolean enabled) { final SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit(); editor.putBoolean(getString(R.string.pref_enabled), enabled); editor.commit(); ((SwitchPreference) findPreference(getString(R.string.pref_enabled))).setChecked(enabled); final AdblockPlus application = AdblockPlus.getApplication(); application.setFilteringEnabled(enabled); } private void setProxyEnabled(final boolean enabled) { final SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit(); editor.putBoolean(getString(R.string.pref_proxyenabled), enabled); editor.commit(); final AdblockPlus application = AdblockPlus.getApplication(); if (enabled && !application.isServiceRunning()) startService(new Intent(this, ProxyService.class)); } /** * Copies file assets from installation package to filesystem. */ private void copyAssets() { final AssetManager assetManager = getAssets(); String[] files = null; try { files = assetManager.list("install"); } catch (final IOException e) { Log.e(TAG, "Failed to get assets list", e); } for (int i = 0; i < files.length; i++) { try { Log.d(TAG, "Copy: install/" + files[i]); final InputStream in = assetManager.open("install/" + files[i]); final OutputStream out = openFileOutput(files[i], MODE_PRIVATE); final byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } in.close(); out.flush(); out.close(); } catch (final Exception e) { Log.e(TAG, "Asset copy error", e); } } } public void showProxySettings(final View v) { final ProxyService proxyService = this.serviceBinder.get(); if (proxyService != null) { startActivity(new Intent(this, ProxyConfigurationActivity.class).putExtra("port", proxyService.port)); } } @Override protected Dialog onCreateDialog(final int id) { Dialog dialog = null; switch (id) { case ABOUT_DIALOG: dialog = new AboutDialog(this); break; case HIDEICONWARNING_DIALOG: final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.warning); builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setCancelable(false); final StringBuffer message = new StringBuffer(); message.append(getString(R.string.msg_hideicon_warning)); builder.setPositiveButton(R.string.gotit, new DialogInterface.OnClickListener() { @Override public void onClick(final DialogInterface dialog, final int id) { dialog.cancel(); } }); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { message.append("<br/><br/>"); message.append(getString(R.string.msg_hideicon_native)); builder.setNeutralButton(R.string.showme, new DialogInterface.OnClickListener() { @Override public void onClick(final DialogInterface dialog, final int id) { AdblockPlus.showAppDetails(getApplicationContext()); dialog.cancel(); } }); } builder.setMessage(Html.fromHtml(message.toString())); dialog = builder.create(); break; } return dialog; } @Override public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { final AdblockPlus application = AdblockPlus.getApplication(); if (getString(R.string.pref_enabled).equals(key)) { final boolean enabled = sharedPreferences.getBoolean(key, false); final boolean autoconfigured = sharedPreferences .getBoolean(getString(R.string.pref_proxyautoconfigured), false); final boolean serviceRunning = application.isServiceRunning(); application.setFilteringEnabled(enabled); if (enabled) { // If user has enabled filtering, enable proxy as well setProxyEnabled(true); } else if (serviceRunning && autoconfigured) { // If user disabled filtering disable proxy only if it was autoconfigured stopService(new Intent(this, ProxyService.class)); } } else if (getString(R.string.pref_acceptableads).equals(key)) { final boolean enabled = sharedPreferences.getBoolean(key, false); application.setAcceptableAdsEnabled(enabled); } else if (getString(R.string.pref_subscription).equals(key)) { final String url = sharedPreferences.getString(key, null); if (url != null) { application.setSubscription(url); application.updateSubscriptionStatus(url); } } else if (getString(R.string.pref_hideicon).equals(key)) { final boolean hideIcon = sharedPreferences.getBoolean(key, false); if (hideIcon) showDialog(HIDEICONWARNING_DIALOG); final ProxyService proxyService = this.serviceBinder.get(); if (proxyService != null) proxyService.setEmptyIcon(hideIcon); } super.onSharedPreferenceChanged(sharedPreferences, key); } private void showConfigurationMsg(final String message) { final ViewGroup grp = (ViewGroup) findViewById(R.id.grp_configuration); final TextView msg = (TextView) findViewById(R.id.txt_configuration); msg.setText(Html.fromHtml(message)); grp.setVisibility(View.VISIBLE); } private void hideConfigurationMsg() { final ViewGroup grp = (ViewGroup) findViewById(R.id.grp_configuration); grp.setVisibility(View.GONE); } private final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); final Bundle extra = intent.getExtras(); if (action.equals(ProxyService.BROADCAST_STATE_CHANGED)) { if (extra.getBoolean("enabled")) { // Service is enabled in manual mode if (extra.getBoolean("manual")) { // Proxy is properly configured if (extra.getBoolean("configured")) hideConfigurationMsg(); else showConfigurationMsg(getString(R.string.msg_configuration)); } } else { setFilteringEnabled(false); hideConfigurationMsg(); } } if (action.equals(ProxyService.BROADCAST_PROXY_FAILED)) { final 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(); setFilteringEnabled(false); } if (action.equals(AdblockPlus.BROADCAST_SUBSCRIPTION_STATUS)) { // TODO Should check if url matches active subscription final String text = extra.getString("status"); final long time = extra.getLong("time"); runOnUiThread(new Runnable() { @Override 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(final String text, final long time) { final ListPreference subscriptionList = (ListPreference) findPreference( getString(R.string.pref_subscription)); final CharSequence summary = subscriptionList.getEntry(); final StringBuilder builder = new StringBuilder(); if (summary != null) { builder.append(summary); if (StringUtils.isNotEmpty(text)) { builder.append(" ("); final int id = getResources().getIdentifier(text, "string", getPackageName()); if (id > 0) builder.append(getString(id, text)); else builder.append(text); if (time > 0) { builder.append(": "); final Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(time); final 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(final Bundle state) { super.onRestoreInstanceState(state); subscriptionSummary = state.getString("subscriptionSummary"); } @Override protected void onSaveInstanceState(final Bundle outState) { outState.putString("subscriptionSummary", subscriptionSummary); super.onSaveInstanceState(outState); } }