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

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: Comments, working Created 4 years, 8 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..7ec91ddd5c32c9b868bb7d1344206b29f39edd23
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java
@@ -0,0 +1,256 @@
+// 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.Dialog;
+import android.app.DialogFragment;
+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.v7.app.AlertDialog;
+import android.util.LruCache;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.CheckedTextView;
+import android.widget.ListView;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.Log;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.favicon.FaviconHelper;
+import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
+import org.chromium.chrome.browser.profiles.Profile;
+
+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[])} method) and
+ * onActivityResult return conventions.
+ */
+public class ConfirmImportantSitesDialogFragment extends DialogFragment {
+ private class ClearBrowsingDataAdapter extends ArrayAdapter<String> {
+ String[] mDomains;
+ private final Drawable mDefaultFavicon;
+ private final int mFaviconSize;
+
+ private ClearBrowsingDataAdapter(String[] domains) {
+ super(getActivity(), R.layout.select_dialog_multichoice_material, domains);
+ mDomains = domains;
+ Resources resources = getActivity().getResources();
+ mFaviconSize = resources.getDimensionPixelSize(R.dimen.default_favicon_size);
+ mDefaultFavicon =
+ ApiCompatibilityUtils.getDrawable(resources, R.drawable.default_favicon);
+ }
+
+ @Override
+ public int getCount() {
+ return mDomains.length;
+ }
+
+ @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.select_dialog_multichoice_material, parent, false);
+
+ ViewHolder viewHolder = new ViewHolder();
+ viewHolder.textView = (CheckedTextView) childView;
+ childView.setTag(viewHolder);
+ }
+ ViewHolder viewHolder = (ViewHolder) childView.getTag();
+ configureChildView(position, viewHolder);
+ return childView;
+ }
+
+ public void configureChildView(int position, ViewHolder viewHolder) {
+ String domain = mDomains[position];
+ viewHolder.textView.setChecked(!mDeselectedDomains.contains(domain));
+ viewHolder.textView.setText(domain);
+ loadLocalFavicon(viewHolder, transformDomainToOrigin(domain));
+ }
+
+ public void onClick(int position, View view) {
+ String domain = mDomains[position];
+ ViewHolder viewHolder = (ViewHolder) view.getTag();
+ if (mDeselectedDomains.contains(domain)) {
+ mDeselectedDomains.remove(domain);
+ viewHolder.textView.setChecked(true);
Theresa 2016/04/27 21:10:58 Using a CheckedTextView for this seems weird. I th
dmurph 2016/04/29 23:53:48 So this acts weird because it's part of a dialog i
Theresa 2016/05/03 00:04:27 Instead of using select_dialog_multichoice_materia
dmurph 2016/05/05 21:53:29 I explored this for a bit, and I'd personally pref
+ } else {
+ mDeselectedDomains.add(domain);
+ viewHolder.textView.setChecked(false);
+ }
+ }
+
+ private void loadLocalFavicon(final ViewHolder viewHolder, final String url) {
+ Drawable image;
+ if (url == null) {
+ // URL is null for print jobs, for example.
+ image = mDefaultFavicon;
+ } else {
+ image = mFaviconCache.getLocalFaviconImage(url);
+ if (image == null) {
+ FaviconImageCallback imageCallback = new FaviconImageCallback() {
+ @Override
+ public void onFaviconAvailable(Bitmap bitmap, String iconUrl) {
+ if (this != viewHolder.imageCallback) return;
+ Drawable image = faviconDrawable(bitmap);
+ image = (image == null) ? mDefaultFavicon : image;
+ mFaviconCache.putLocalFaviconImage(url, image);
+ viewHolder.textView.setCheckMarkDrawable(image);
+ }
+ };
+ viewHolder.imageCallback = imageCallback;
+ mFaviconHelper.getLocalFaviconImageForURL(
+ mProfile, url, mFaviconSize, imageCallback);
+ image = mDefaultFavicon;
+ }
+ }
+ viewHolder.textView.setCheckMarkDrawable(image);
+ }
+
+ private Drawable faviconDrawable(Bitmap image) {
Theresa 2016/04/27 21:10:58 nit: getFaviconDrawable(Bitmap favicon)?
dmurph 2016/04/29 23:53:48 Done.
+ if (image == null) return null;
+ return new BitmapDrawable(getActivity().getResources(),
+ Bitmap.createScaledBitmap(image, mFaviconSize, mFaviconSize, true));
+ }
+ }
+
+ private static class FaviconCache {
Theresa 2016/04/27 21:10:59 What's the expected flow for this dialog? I would
dmurph 2016/04/29 23:53:48 Yes, it'll be empty. I'm not using that class (I d
Theresa 2016/05/03 00:04:27 Caching for scrolling makes sense. The favicons w
+ private final LruCache<String, Drawable> mMemoryCache;
+
+ public FaviconCache(int size) {
+ mMemoryCache = new LruCache<String, Drawable>(size);
+ }
+
+ public Drawable getLocalFaviconImage(String url) {
+ return mMemoryCache.get(url);
+ }
+
+ public void putLocalFaviconImage(String url, Drawable image) {
+ mMemoryCache.put(url, image);
+ }
+ }
+
+ /**
+ * 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 ViewHolder {
Theresa 2016/04/27 21:10:58 Consider using a different class name. ViewHolder
dmurph 2016/04/29 23:53:48 Done.
+ public CheckedTextView textView;
+ public FaviconImageCallback imageCallback;
+ }
+
+ /**
+ * Constructs a new instance of the important sites dialog fragment.
+ * @param importantDomains The list of important domains to display.
+ * @return An instance of ConfirmImportantSitesDialogFragment with the bundle arguments set.
+ */
+ public static ConfirmImportantSitesDialogFragment newInstance(String[] importantDomains) {
+ Log.i(FRAGMENT_TAG, "Creating dialog");
Finnur 2016/04/27 13:49:15 nit: Debug statement.
dmurph 2016/04/27 20:36:47 removed.
+ ConfirmImportantSitesDialogFragment dialogFragment =
+ new ConfirmImportantSitesDialogFragment();
+ Bundle bundle = new Bundle();
+ bundle.putStringArray(IMPORTANT_DOMAINS_TAG, importantDomains);
+ dialogFragment.setArguments(bundle);
+ return dialogFragment;
+ }
+
+ /** 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. */
+ public static final String DESELECTED_DOMAINS_TAG = "DeselectedDomains";
+
+ /** The tag used to store the important domains in the bundle. */
+ private static final String IMPORTANT_DOMAINS_TAG = "ImportantDomains";
+
+ /* Transforms a domain into an origin for favicon lookup */
Finnur 2016/04/27 13:49:15 Nit: Missing period at end.
dmurph 2016/04/27 20:36:47 Done.
+ private static String transformDomainToOrigin(String domain) {
+ return "http://www." + domain;
+ }
+
+ private String[] mImportantDomains;
Finnur 2016/04/27 13:49:15 nit: I'd go ahead and document those members and f
dmurph 2016/04/27 20:36:47 Done.
+ private Set<String> mDeselectedDomains;
+ private AlertDialog mDialog;
+ private ClearBrowsingDataAdapter mAdapter;
+ private FaviconHelper mFaviconHelper;
+ private FaviconCache mFaviconCache;
+ private Profile mProfile;
+
+ protected ConfirmImportantSitesDialogFragment() {
+ mProfile = Profile.getLastUsedProfile();
+ mFaviconHelper = new FaviconHelper();
+ mDeselectedDomains = new HashSet<>();
+ mFaviconCache = new FaviconCache(5);
Finnur 2016/04/27 13:49:15 Why 5? Seems kind of low to me, but is there a met
dmurph 2016/04/27 20:36:47 We currently only have 5 items max, so this will b
Theresa 2016/04/27 21:10:58 The maximum important sites to fetch in pref_servi
dmurph 2016/04/29 23:53:48 Done.
+ }
+
+ @Override
+ public void setArguments(Bundle args) {
+ super.setArguments(args);
+ mImportantDomains = args.getStringArray(IMPORTANT_DOMAINS_TAG);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ mAdapter = new ClearBrowsingDataAdapter(mImportantDomains);
+ 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 = getActivity().getIntent();
+ 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
Theresa 2016/04/27 21:10:58 nit: ListView
dmurph 2016/04/29 23:53:48 Done.
+ // adapter at the same time.
+ ListView listView = (ListView) getActivity().getLayoutInflater().inflate(
+ R.layout.select_dialog_listview, null);
+ listView.setAdapter(mAdapter);
+ listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+ mAdapter.onClick(position, v);
+ }
+ });
+ final AlertDialog.Builder builder =
+ new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme)
+ .setTitle(R.string.clear_browsing_data_important_dialog_title)
+ .setMessage(R.string.clear_browsing_data_important_dialog_text)
+ .setPositiveButton(R.string.clear_data_delete, listener)
+ .setNegativeButton(R.string.cancel, listener)
+ .setView(listView);
+ // OnClickListener is registered manually.
Theresa 2016/04/27 21:10:58 This comment seems a little out of place here sinc
dmurph 2016/04/29 23:53:48 Removed, it was old.
+ mDialog = builder.create();
+
+ return mDialog;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698