Chromium Code Reviews| 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..f6615b40be29e50febd815457b9cecc0249971bf |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ConfirmImportantSitesDialogFragment.java |
| @@ -0,0 +1,222 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
|
Finnur
2016/03/03 14:15:43
Nit: 2016 (elsewhere too)
|
| +// 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.Dialog; |
| +import android.app.DialogFragment; |
| +import android.app.ProgressDialog; |
| +import android.content.DialogInterface; |
| +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.text.TextUtils; |
| +import android.util.LruCache; |
| +import android.view.LayoutInflater; |
| +import android.view.View; |
| +import android.view.ViewGroup; |
| +import android.widget.AdapterView; |
| +import android.widget.AdapterView.OnItemClickListener; |
| +import android.widget.ArrayAdapter; |
| +import android.widget.CheckedTextView; |
| + |
| +import org.chromium.base.ApiCompatibilityUtils; |
| +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.List; |
| +import java.util.Set; |
| + |
| +/** |
| + * Modal dialog with options for selection the type of browsing data |
| + * to clear (history, cookies), triggered from a preference. |
| + */ |
| +public class ConfirmImportantSitesDialogFragment extends DialogFragment { |
| + private class ClearBrowsingDataAdapter extends ArrayAdapter<String> { |
| + OriginEntry[] mOrigins; |
| + private final Drawable mDefaultFavicon; |
| + private final int mFaviconSize; |
| + |
| + private ClearBrowsingDataAdapter(OriginEntry[] origins, String[] names) { |
| + super(getActivity(), R.layout.select_dialog_multichoice_material, names); |
| + mOrigins = origins; |
| + 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 mOrigins.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) { |
| + OriginEntry option = mOrigins[position]; |
| + viewHolder.textView.setChecked(!mDeselectedURLs.contains(option.url)); |
| + viewHolder.textView.setText(TextUtils.isEmpty(option.name) ? option.url : option.name); |
| + loadLocalFavicon(viewHolder, option.url); |
| + } |
| + |
| + public void onClick(int position) { |
| + OriginEntry option = mOrigins[position]; |
| + if (mDeselectedURLs.contains(option.url)) { |
| + mDeselectedURLs.remove(option.url); |
| + } else { |
| + mDeselectedURLs.add(option.url); |
| + } |
| + notifyDataSetChanged(); |
| + } |
| + |
| + 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) { |
| + if (image == null) return null; |
| + return new BitmapDrawable(getActivity().getResources(), |
| + Bitmap.createScaledBitmap(image, mFaviconSize, mFaviconSize, true)); |
| + } |
| + } |
| + |
| + private static class FaviconCache { |
| + 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); |
| + } |
| + } |
| + |
| + /** The tag used when showing the clear browsing fragment. */ |
| + public static final String FRAGMENT_TAG = "ConfirmImportantSitesDialogFragment"; |
| + |
| + /** |
| + * 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 { |
| + public CheckedTextView textView; |
| + public FaviconImageCallback imageCallback; |
| + } |
| + |
| + public static class OriginEntry { |
| + public String url; |
| + public String name; |
| + } |
| + |
| + private List<OriginEntry> mOriginList; |
| + private Set<String> mDeselectedURLs; |
| + private AlertDialog mDialog; |
| + private ProgressDialog mProgressDialog; |
| + private ClearBrowsingDataAdapter mAdapter; |
| + private FaviconHelper mFaviconHelper; |
| + private FaviconCache mFaviconCache; |
| + private Profile mProfile; |
| + private DialogInterface.OnClickListener mListener; |
| + |
| + public ConfirmImportantSitesDialogFragment(Profile profile, List<OriginEntry> importantOrigins, |
| + DialogInterface.OnClickListener listener) { |
| + mProfile = profile; |
| + mOriginList = importantOrigins; |
| + mListener = listener; |
| + mFaviconHelper = new FaviconHelper(); |
| + mDeselectedURLs = new HashSet<>(); |
| + mFaviconCache = new FaviconCache(5); |
| + } |
| + |
| + /** |
| + * @return the set of URLs that were deselected by this dialog. |
| + */ |
| + public Set<String> getDeselectedURLs() { |
| + return mDeselectedURLs; |
| + } |
| + |
| + @Override |
| + public Dialog onCreateDialog(Bundle savedInstanceState) { |
| + OriginEntry[] origins = mOriginList.toArray(new OriginEntry[0]); |
| + String[] originNames = new String[origins.length]; |
| + for (int i = 0; i < origins.length; i++) { |
| + originNames[i] = origins[i].name; |
| + } |
| + mAdapter = new ClearBrowsingDataAdapter(origins, originNames); |
| + final AlertDialog.Builder builder = |
| + new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme) |
| + .setTitle(R.string.clear_browsing_data_title) |
| + .setPositiveButton(R.string.clear_data_delete, mListener) |
| + .setNegativeButton(R.string.cancel, mListener) |
| + .setAdapter(mAdapter, null); |
| + // OnClickListener is registered manually. |
| + mDialog = builder.create(); |
| + mDialog.getListView().setOnItemClickListener(new OnItemClickListener() { |
| + @Override |
| + public void onItemClick(AdapterView<?> parent, View v, int position, long id) { |
| + // The present behaviour of AlertDialog is to dismiss after the onClick event. |
| + // Hence we are manually overriding this outside the builder. |
| + mAdapter.onClick(position); |
| + } |
| + }); |
| + |
| + return mDialog; |
| + } |
| +} |