org.adblockplus.android.Preferences.java Source code

Java tutorial

Introduction

Here is the source code for org.adblockplus.android.Preferences.java

Source

/*
 * 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("&lt;a&gt;(.*?)&lt;/a&gt;",
                "<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);
    }
}