Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(621)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java

Issue 1465363002: [Storage] Android - ManageSpace UI, Important Origins, and CBD Dialog (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java
new file mode 100644
index 0000000000000000000000000000000000000000..fa168082a907986f651a7f9ee8c1eb54cbbaa1f8
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java
@@ -0,0 +1,290 @@
+// Copyright 2016 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.privacy;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.support.v7.app.AlertDialog;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.ListView;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.favicon.LargeIconBridge;
+import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.widget.RoundedIconGenerator;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Modal dialog that shows a list of important domains to the user which they can uncheck. Used to
+ * allow the user to exclude domains from being cleared by the clear browsing data function.
+ * We use proper bundle construction (through the {@link #newInstance(String[], String[])} method)
+ * and onActivityResult return conventions.
+ * TODO(dmurph): Add UMA metrics for cancel and clear (with and without dechecking a site).
+ */
+public class ConfirmImportantSitesDialogFragment extends DialogFragment {
+ private class ClearBrowsingDataAdapter extends ArrayAdapter<String>
+ implements AdapterView.OnItemClickListener {
+ private final String[] mDomains;
+ private final String[] mFaviconURLs;
+ private final int mCornerRadius;
+ private final int mFaviconSize;
+ private RoundedIconGenerator mIconGenerator;
+
+ private ClearBrowsingDataAdapter(
+ String[] domains, String[] faviconURLs, Resources resources) {
+ super(getActivity(), R.layout.confirm_important_sites_list_row, domains);
+ mDomains = domains;
+ mFaviconURLs = faviconURLs;
+ mFaviconSize = resources.getDimensionPixelSize(R.dimen.default_favicon_size);
+ mCornerRadius = resources.getDimensionPixelSize(R.dimen.default_favicon_corner_radius);
+ int textSize = resources.getDimensionPixelSize(R.dimen.default_favicon_icon_text_size);
+ int iconColor = ApiCompatibilityUtils.getColor(
+ resources, R.color.default_favicon_background_color);
+ mIconGenerator = new RoundedIconGenerator(
+ mFaviconSize, mFaviconSize, mCornerRadius, iconColor, textSize);
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View childView = convertView;
+ if (childView == null) {
+ LayoutInflater inflater = LayoutInflater.from(getActivity());
+ childView =
+ inflater.inflate(R.layout.confirm_important_sites_list_row, parent, false);
+
+ ViewAndFaviconHolder viewHolder = new ViewAndFaviconHolder();
+ viewHolder.checkboxView = (CheckBox) childView.findViewById(R.id.icon_row_checkbox);
+ viewHolder.imageView = (ImageView) childView.findViewById(R.id.icon_row_image);
+ childView.setTag(viewHolder);
+ }
+ ViewAndFaviconHolder viewHolder = (ViewAndFaviconHolder) childView.getTag();
+ configureChildView(position, viewHolder);
+ return childView;
+ }
+
+ private void configureChildView(int position, ViewAndFaviconHolder viewHolder) {
+ String domain = mDomains[position];
+ viewHolder.checkboxView.setChecked(!mDeselectedDomains.contains(domain));
+ viewHolder.checkboxView.setText(domain);
+ loadFavicon(viewHolder, mFaviconURLs[position]);
+ }
+
+ /**
+ * Called when a list item is clicked. We toggle the checkbox and update our selected
+ * domains list.
+ */
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ String domain = mDomains[position];
+ ViewAndFaviconHolder viewHolder = (ViewAndFaviconHolder) view.getTag();
+ if (mDeselectedDomains.contains(domain)) {
+ mDeselectedDomains.remove(domain);
+ viewHolder.checkboxView.setChecked(true);
+ } else {
+ mDeselectedDomains.add(domain);
+ viewHolder.checkboxView.setChecked(false);
+ }
+ }
+
+ private void loadFavicon(final ViewAndFaviconHolder viewHolder, final String url) {
+ viewHolder.imageCallback = new LargeIconCallback() {
+ @Override
+ public void onLargeIconAvailable(Bitmap icon, int fallbackColor) {
+ if (this != viewHolder.imageCallback) return;
+ Drawable image = getFaviconDrawable(icon, fallbackColor, url);
+ viewHolder.imageView.setImageDrawable(image);
+ }
+ };
+ mLargeIconBridge.getLargeIconForUrl(url, mFaviconSize, viewHolder.imageCallback);
+ }
+
+ private Drawable getFaviconDrawable(Bitmap icon, int fallbackColor, String url) {
+ if (icon == null) {
+ mIconGenerator.setBackgroundColor(fallbackColor);
+ icon = mIconGenerator.generateIconForUrl(url);
+ return new BitmapDrawable(getResources(), icon);
+ } else {
+ RoundedBitmapDrawable roundedIcon =
+ RoundedBitmapDrawableFactory.create(getResources(),
+ Bitmap.createScaledBitmap(icon, mFaviconSize, mFaviconSize, false));
+ roundedIcon.setCornerRadius(mCornerRadius);
+ return roundedIcon;
+ }
+ }
+ }
+
+ /**
+ * ViewHolder class optimizes looking up table row fields. findViewById is only called once
+ * per row view initialization, and the references are cached here. Also stores a reference to
+ * the favicon image callback so that we can make sure we load the correct favicon.
+ */
+ private static class ViewAndFaviconHolder {
+ public CheckBox checkboxView;
+ public ImageView imageView;
+ public LargeIconCallback imageCallback;
+ }
+
+ /**
+ * Constructs a new instance of the important sites dialog fragment.
+ * @param importantDomains The list of important domains to display.
+ * @param faviconURLs The list of favicon urls that correspond to each importantDomains.
+ * @return An instance of ConfirmImportantSitesDialogFragment with the bundle arguments set.
+ */
+ public static ConfirmImportantSitesDialogFragment newInstance(
+ String[] importantDomains, String[] faviconURLs) {
+ ConfirmImportantSitesDialogFragment dialogFragment =
+ new ConfirmImportantSitesDialogFragment();
+ Bundle bundle = new Bundle();
+ bundle.putStringArray(IMPORTANT_DOMAINS_TAG, importantDomains);
+ bundle.putStringArray(FAVICON_URLS_TAG, faviconURLs);
+ dialogFragment.setArguments(bundle);
+ return dialogFragment;
+ }
+
+ private static final int FAVICON_MAX_CACHE_SIZE_BYTES = 100 * 1024; // 100KB
+
+ /** The tag used when showing the clear browsing fragment. */
+ public static final String FRAGMENT_TAG = "ConfirmImportantSitesDialogFragment";
+
+ /**
+ * The tag used to return the string array of deselected domains. These are meant to NOT be
+ * cleared.
+ */
+ public static final String DESELECTED_DOMAINS_TAG = "DeselectedDomains";
+
+ /** The tag used for logging. */
+ public static final String TAG = "ConfirmImportantSitesDialogFragment";
+
+ /** The tag used to store the important domains in the bundle. */
+ private static final String IMPORTANT_DOMAINS_TAG = "ImportantDomains";
+
+ /** The tag used to store the favicon urls corresponding to each important domain. */
+ private static final String FAVICON_URLS_TAG = "FaviconURLs";
+
+ /** Array of important registerable domains we're showing to the user. */
+ private String[] mImportantDomains;
+ /** Array of favicon urls to use for each important domain above. */
+ private String[] mFaviconURLs;
+ /** The set of domains that the user has deselected. */
+ private Set<String> mDeselectedDomains;
+ /** The alert dialog shown to the user. */
+ private AlertDialog mDialog;
+ /** Our adapter that we use with the list view in the dialog. */
+ private ClearBrowsingDataAdapter mAdapter;
+
+ private LargeIconBridge mLargeIconBridge;
+
+ private Profile mProfile;
+
+ /** We store the custom list view for testing */
+ private ListView mSitesListView;
+
+ public ConfirmImportantSitesDialogFragment() {
+ mDeselectedDomains = new HashSet<>();
+ }
+
+ @Override
+ public void setArguments(Bundle args) {
+ super.setArguments(args);
+ mImportantDomains = args.getStringArray(IMPORTANT_DOMAINS_TAG);
+ mFaviconURLs = args.getStringArray(FAVICON_URLS_TAG);
+ }
+
+ @VisibleForTesting
+ public Set<String> getDeselectedDomains() {
+ return mDeselectedDomains;
+ }
+
+ @VisibleForTesting
+ public ListView getSitesList() {
+ return mSitesListView;
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ if (mLargeIconBridge != null) {
+ mLargeIconBridge.destroy();
+ }
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ if (savedInstanceState != null) {
+ dismiss();
+ }
+ mProfile = Profile.getLastUsedProfile().getOriginalProfile();
+ mLargeIconBridge = new LargeIconBridge(mProfile);
+ ActivityManager activityManager =
+ ((ActivityManager) ContextUtils.getApplicationContext().getSystemService(
+ Context.ACTIVITY_SERVICE));
+ int maxSize = Math.min(
+ activityManager.getMemoryClass() / 16 * 25 * 1024, FAVICON_MAX_CACHE_SIZE_BYTES);
+ mLargeIconBridge.createCache(maxSize);
+
+ mAdapter = new ClearBrowsingDataAdapter(mImportantDomains, mFaviconURLs, getResources());
+ DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ // Return our deselected domains.
+ Intent data = new Intent();
+ String[] deselectedDomains = mDeselectedDomains.toArray(new String[0]);
+ data.putExtra(DESELECTED_DOMAINS_TAG, deselectedDomains);
+ getTargetFragment().onActivityResult(
+ getTargetRequestCode(), Activity.RESULT_OK, data);
+ } else {
+ getTargetFragment().onActivityResult(getTargetRequestCode(),
+ Activity.RESULT_CANCELED, getActivity().getIntent());
+ }
+ }
+ };
+ // We create our own ListView, as AlertDialog doesn't let us set a message and a list
+ // adapter at the same time.
+ View messageAndListView = getActivity().getLayoutInflater().inflate(
+ R.layout.clear_browsing_important_dialog_listview, null);
+ mSitesListView = (ListView) messageAndListView.findViewById(R.id.select_dialog_listview);
+ mSitesListView.setAdapter(mAdapter);
+ mSitesListView.setOnItemClickListener(mAdapter);
+ final AlertDialog.Builder builder =
+ new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme)
+ .setTitle(R.string.storage_clear_site_storage_title)
+ .setPositiveButton(R.string.clear_data_delete, listener)
+ .setNegativeButton(R.string.cancel, listener)
+ .setView(messageAndListView);
+ mDialog = builder.create();
+
+ return mDialog;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698