// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.chrome.browser.preferences.website; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Vibrator; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.provider.Settings; import android.support.v7.app.AlertDialog; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.R; import org.chromium.ui.UiUtils; /** * A utility class for the UI recording exceptions to the blocked list for site * settings. */ public class AddExceptionPreference extends Preference implements OnPreferenceClickListener { // The callback to notify when the user adds a site. private SiteAddedCallback mSiteAddedCallback; // The accent color to use for the icon and title view. private int mPrefAccentColor; // The custom message to show in the dialog. private String mDialogMessage; /** * An interface to implement to get a callback when a site needs to be added. * @param hostname The hostname to add. */ public interface SiteAddedCallback { public void onAddSite(String hostname); } /** * Construct a AddException preference. * @param context The current context. * @param key The key to use for the preference. * @param message The custom message to show in the dialog. * @param callback A callback to receive notifications that an exception has been added. */ public AddExceptionPreference( Context context, String key, String message, SiteAddedCallback callback) { super(context); mDialogMessage = message; mSiteAddedCallback = callback; setOnPreferenceClickListener(this); setKey(key); Resources resources = getContext().getResources(); mPrefAccentColor = ApiCompatibilityUtils.getColor(resources, R.color.pref_accent_color); Drawable plusIcon = ApiCompatibilityUtils.getDrawable(resources, R.drawable.plus); plusIcon.mutate(); plusIcon.setColorFilter(mPrefAccentColor, PorterDuff.Mode.SRC_IN); setIcon(plusIcon); setTitle(resources.getString(R.string.website_settings_add_site)); } @Override protected void onBindView(View view) { super.onBindView(view); TextView titleView = (TextView) view.findViewById(android.R.id.title); titleView.setAllCaps(true); titleView.setTextColor(mPrefAccentColor); } @Override public boolean onPreferenceClick(Preference preference) { showAddExceptionDialog(); return true; } /** * Show the dialog allowing the user to add a new website as an exception. */ private void showAddExceptionDialog() { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.add_site_dialog, null); final EditText input = (EditText) view.findViewById(R.id.site); DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int button) { if (button == AlertDialog.BUTTON_POSITIVE) { mSiteAddedCallback.onAddSite(input.getText().toString().trim()); } else { dialog.dismiss(); } } }; AlertDialog.Builder alert = new AlertDialog.Builder(getContext(), R.style.AlertDialogTheme); AlertDialog alertDialog = alert .setTitle(R.string.website_settings_add_site_dialog_title) .setMessage(mDialogMessage) .setView(view) .setPositiveButton(R.string.website_settings_add_site_add_button, onClickListener) .setNegativeButton(R.string.cancel, onClickListener) .create(); alertDialog.getDelegate().setHandleNativeActionModesEnabled(false); alertDialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { UiUtils.showKeyboard(input); } }); alertDialog.show(); final Button okButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); okButton.setEnabled(false); input.addTextChangedListener(new TextWatcher() { @Override public void afterTextChanged(Editable s) {} @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // The intent is to capture a hostname and register it as an exception using a // pattern. But a pattern can be used to express things that are not supported, such // as domains, schemes and ports. Therefore we need to filter out invalid values // before passing them on to the validity checker for patterns. String hostname = s.toString().trim(); boolean hasError = hostname.length() > 0 && (hostname.contains(":") || hostname.contains(" ") || hostname.startsWith(".") || !WebsitePreferenceBridge.nativeIsContentSettingsPatternValid(hostname)); // Vibrate when adding characters only, not when deleting them. if (hasError && count != 0) { if (Settings.System.getInt(getContext().getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1) == 1) { ((Vibrator) getContext().getSystemService( Context.VIBRATOR_SERVICE)).vibrate(50); } } okButton.setEnabled(!hasError && hostname.length() > 0); input.setTextColor(hasError ? Color.RED : Color.BLACK); } }); } }