Commit a6ba8d8c authored by twellington's avatar twellington Committed by Commit bot

[Android History] Add clear browsing data button and privacy disclaimers

Adds an optional header to DateDividedAdapter and adds a new layout
with a clear browsing data button and privacy disclaimers as a header
in the history ui.

BUG=654071

Review-Url: https://codereview.chromium.org/2562123003
Cr-Commit-Position: refs/heads/master@{#437931}
parent 7fb93a52
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/signed_in_not_synced"
style="@style/PrivacyDisclaimerText" />
<TextView
android:id="@+id/signed_in_synced"
style="@style/PrivacyDisclaimerText" />
<TextView
android:id="@+id/other_forms_of_browsing_history"
style="@style/PrivacyDisclaimerText" />
<Button
android:id="@+id/clear_browsing_data_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
style="@style/ButtonCompatBorderless"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:gravity="center_vertical|start"
android:text="@string/open_clear_browsing_data_dialog_button"
android:textAllCaps="true"
android:textColor="@color/light_active_color"
android:textSize="16sp" />
</LinearLayout>
\ No newline at end of file
...@@ -582,6 +582,15 @@ ...@@ -582,6 +582,15 @@
<item name="android:textColor">@android:color/white</item> <item name="android:textColor">@android:color/white</item>
<item name="android:textSize">20sp</item> <item name="android:textSize">20sp</item>
</style> </style>
<style name="PrivacyDisclaimerText">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">16dp</item>
<item name="android:paddingStart">16dp</item>
<item name="android:paddingEnd">16dp</item>
<item name="android:textSize">16sp</item>
<item name="android:visibility">gone</item>
</style>
<!-- New tab page RecyclerView overscroll color --> <!-- New tab page RecyclerView overscroll color -->
<style name="NewTabPageRecyclerView"> <style name="NewTabPageRecyclerView">
......
...@@ -340,6 +340,7 @@ public class DownloadHistoryAdapter extends DateDividedAdapter implements Downlo ...@@ -340,6 +340,7 @@ public class DownloadHistoryAdapter extends DateDividedAdapter implements Downlo
mRegularDownloadItems.filter(mFilter, mFilteredItems); mRegularDownloadItems.filter(mFilter, mFilteredItems);
mIncognitoDownloadItems.filter(mFilter, mFilteredItems); mIncognitoDownloadItems.filter(mFilter, mFilteredItems);
mOfflinePageItems.filter(mFilter, mFilteredItems); mOfflinePageItems.filter(mFilter, mFilteredItems);
clear(false);
loadItems(mFilteredItems); loadItems(mFilteredItems);
} }
......
...@@ -30,6 +30,14 @@ public class BrowsingHistoryBridge { ...@@ -30,6 +30,14 @@ public class BrowsingHistoryBridge {
* via this method. * via this method.
*/ */
public void onHistoryDeleted(); public void onHistoryDeleted();
/**
* Called after querying history to indicate whether other forms of browsing history were
* found.
* @param hasOtherForms Whether other forms of browsing history were found.
* @param hasSyncedResults Whether synced results were found.
*/
public void hasOtherFormsOfBrowsingData(boolean hasOtherForms, boolean hasSyncedResults);
} }
private final BrowsingHistoryObserver mObserver; private final BrowsingHistoryObserver mObserver;
...@@ -114,6 +122,11 @@ public class BrowsingHistoryBridge { ...@@ -114,6 +122,11 @@ public class BrowsingHistoryBridge {
mObserver.onHistoryDeleted(); mObserver.onHistoryDeleted();
} }
@CalledByNative
public void hasOtherFormsOfBrowsingData(boolean hasOtherForms, boolean hasSyncedResults) {
mObserver.hasOtherFormsOfBrowsingData(hasOtherForms, hasSyncedResults);
}
private native long nativeInit(Profile profile); private native long nativeInit(Profile profile);
private native void nativeDestroy(long nativeBrowsingHistoryBridge); private native void nativeDestroy(long nativeBrowsingHistoryBridge);
private native void nativeQueryHistory(long nativeBrowsingHistoryBridge, private native void nativeQueryHistory(long nativeBrowsingHistoryBridge,
......
...@@ -5,28 +5,48 @@ ...@@ -5,28 +5,48 @@
package org.chromium.chrome.browser.history; package org.chromium.chrome.browser.history;
import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView;
import org.chromium.base.ContextUtils;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.history.BrowsingHistoryBridge.BrowsingHistoryObserver; import org.chromium.chrome.browser.history.BrowsingHistoryBridge.BrowsingHistoryObserver;
import org.chromium.chrome.browser.widget.DateDividedAdapter; import org.chromium.chrome.browser.widget.DateDividedAdapter;
import org.chromium.chrome.browser.widget.selection.SelectableItemViewHolder; import org.chromium.chrome.browser.widget.selection.SelectableItemViewHolder;
import org.chromium.chrome.browser.widget.selection.SelectionDelegate; import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
import org.chromium.components.signin.ChromeSigninController;
import org.chromium.ui.text.NoUnderlineClickableSpan;
import org.chromium.ui.text.SpanApplier;
import java.util.List; import java.util.List;
import java.util.Locale;
/** /**
* Bridges the user's browsing history and the UI used to display it. * Bridges the user's browsing history and the UI used to display it.
*/ */
public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistoryObserver { public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistoryObserver {
private static final String EMPTY_QUERY = ""; private static final String EMPTY_QUERY = "";
private static final String LEARN_MORE_LINK =
"https://support.google.com/chrome/?p=sync_history&amp;hl="
+ Locale.getDefault().toString();
private static final String GOOGLE_HISTORY_LINK = "history.google.com";
private final SelectionDelegate<HistoryItem> mSelectionDelegate; private final SelectionDelegate<HistoryItem> mSelectionDelegate;
private final BrowsingHistoryBridge mBridge; private final BrowsingHistoryBridge mBridge;
private final HistoryManager mManager; private final HistoryManager mManager;
private TextView mSignedInNotSyncedTextView;
private TextView mSignedInSyncedTextView;
private TextView mOtherFormsOfBrowsingHistoryTextView;
private boolean mHasOtherFormsOfBrowsingData;
private boolean mHasSyncedData;
private boolean mHeaderInflated;
private boolean mDestroyed; private boolean mDestroyed;
public HistoryAdapter(SelectionDelegate<HistoryItem> delegate, HistoryManager manager) { public HistoryAdapter(SelectionDelegate<HistoryItem> delegate, HistoryManager manager) {
...@@ -101,7 +121,11 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor ...@@ -101,7 +121,11 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
// destroyed to avoid unnecessary work. // destroyed to avoid unnecessary work.
if (mDestroyed) return; if (mDestroyed) return;
loadItems(items); clear(true);
if (items.size() > 0) {
addHeader();
loadItems(items);
}
} }
@Override @Override
...@@ -111,4 +135,69 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor ...@@ -111,4 +135,69 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
// This currently removes all items and re-issues a query. // This currently removes all items and re-issues a query.
initialize(); initialize();
} }
@Override
public void hasOtherFormsOfBrowsingData(boolean hasOtherForms, boolean hasSyncedResults) {
mHasOtherFormsOfBrowsingData = hasOtherForms;
mHasSyncedData = hasSyncedResults;
setPrivacyDisclaimerVisibility();
}
@Override
protected HeaderViewHolder createHeader(ViewGroup parent) {
ViewGroup v = (ViewGroup) LayoutInflater.from(parent.getContext()).inflate(
R.layout.history_header, parent, false);
mHeaderInflated = true;
View cbdButton = v.findViewById(R.id.clear_browsing_data_button);
cbdButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mManager.openClearBrowsingDataPreference();
}
});
mSignedInNotSyncedTextView = (TextView) v.findViewById(R.id.signed_in_not_synced);
setPrivacyDisclaimerText(mSignedInNotSyncedTextView,
R.string.android_history_no_synced_results, LEARN_MORE_LINK);
mSignedInSyncedTextView = (TextView) v.findViewById(R.id.signed_in_synced);
setPrivacyDisclaimerText(mSignedInSyncedTextView,
R.string.android_history_has_synced_results, LEARN_MORE_LINK);
mOtherFormsOfBrowsingHistoryTextView = (TextView) v.findViewById(
R.id.other_forms_of_browsing_history);
setPrivacyDisclaimerText(mOtherFormsOfBrowsingHistoryTextView,
R.string.android_history_other_forms_of_history, GOOGLE_HISTORY_LINK);
setPrivacyDisclaimerVisibility();
return new HeaderViewHolder(v);
}
private void setPrivacyDisclaimerText(TextView view, int stringId, final String url) {
NoUnderlineClickableSpan link = new NoUnderlineClickableSpan() {
@Override
public void onClick(View view) {
mManager.openUrl(url, null, true);
}
};
SpannableString spannable = SpanApplier.applySpans(
view.getResources().getString(stringId),
new SpanApplier.SpanInfo("<link>", "</link>", link));
view.setText(spannable);
view.setMovementMethod(LinkMovementMethod.getInstance());
}
private void setPrivacyDisclaimerVisibility() {
if (!mHeaderInflated) return;
boolean isSignedIn =
ChromeSigninController.get(ContextUtils.getApplicationContext()).isSignedIn();
mSignedInNotSyncedTextView.setVisibility(
!mHasSyncedData && isSignedIn ? View.VISIBLE : View.GONE);
mSignedInSyncedTextView.setVisibility(mHasSyncedData ? View.VISIBLE : View.GONE);
mOtherFormsOfBrowsingHistoryTextView.setVisibility(
mHasOtherFormsOfBrowsingData ? View.VISIBLE : View.GONE);
}
} }
...@@ -85,7 +85,7 @@ public class HistoryItem extends TimedItem { ...@@ -85,7 +85,7 @@ public class HistoryItem extends TimedItem {
* Navigates a tab to this item's URL. * Navigates a tab to this item's URL.
*/ */
public void open() { public void open() {
if (mManager != null) mManager.openItem(mUrl, null, false); if (mManager != null) mManager.openUrl(mUrl, null, false);
} }
/** /**
......
...@@ -17,6 +17,8 @@ import android.view.ViewGroup; ...@@ -17,6 +17,8 @@ import android.view.ViewGroup;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.document.ChromeLauncherActivity; import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.chrome.browser.preferences.PreferencesLauncher;
import org.chromium.chrome.browser.preferences.privacy.ClearBrowsingDataPreferences;
import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.chrome.browser.widget.TintedDrawable; import org.chromium.chrome.browser.widget.TintedDrawable;
import org.chromium.chrome.browser.widget.selection.SelectableListLayout; import org.chromium.chrome.browser.widget.selection.SelectableListLayout;
...@@ -114,14 +116,14 @@ public class HistoryManager implements OnMenuItemClickListener { ...@@ -114,14 +116,14 @@ public class HistoryManager implements OnMenuItemClickListener {
} }
/** /**
* Open the history item. * Open the provided url.
* @param url The URL of the history item. * @param url The url to open.
* @param isIncognito Whether to open the history item in an incognito tab. If null, the tab * @param isIncognito Whether to open the url in an incognito tab. If null, the tab
* will open in the current tab model. * will open in the current tab model.
* @param createNewTab Whether a new tab should be created. If false, the item will clobber the * @param createNewTab Whether a new tab should be created. If false, the item will clobber the
* the current tab. * the current tab.
*/ */
public void openItem(String url, Boolean isIncognito, boolean createNewTab) { public void openUrl(String url, Boolean isIncognito, boolean createNewTab) {
// Construct basic intent. // Construct basic intent.
Intent viewIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); Intent viewIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
viewIntent.putExtra(Browser.EXTRA_APPLICATION_ID, viewIntent.putExtra(Browser.EXTRA_APPLICATION_ID,
...@@ -151,9 +153,18 @@ public class HistoryManager implements OnMenuItemClickListener { ...@@ -151,9 +153,18 @@ public class HistoryManager implements OnMenuItemClickListener {
IntentHandler.startActivityForTrustedIntent(viewIntent, mActivity); IntentHandler.startActivityForTrustedIntent(viewIntent, mActivity);
} }
/**
* Opens the clear browsing data preference.
*/
public void openClearBrowsingDataPreference() {
Intent intent = PreferencesLauncher.createIntentForSettingsPage(mActivity,
ClearBrowsingDataPreferences.class.getName());
IntentUtils.safeStartActivity(mActivity, intent);
}
private void openItemsInNewTabs(List<HistoryItem> items, boolean isIncognito) { private void openItemsInNewTabs(List<HistoryItem> items, boolean isIncognito) {
for (HistoryItem item : items) { for (HistoryItem item : items) {
openItem(item.getUrl(), isIncognito, true); openUrl(item.getUrl(), isIncognito, true);
} }
} }
} }
\ No newline at end of file
...@@ -105,6 +105,12 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -105,6 +105,12 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
} }
} }
protected static class HeaderViewHolder extends RecyclerView.ViewHolder {
public HeaderViewHolder(View itemView) {
super(itemView);
}
}
/** /**
* A bucket of items with the same date. * A bucket of items with the same date.
*/ */
...@@ -116,16 +122,16 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -116,16 +122,16 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
private int mIndex; private int mIndex;
private boolean mIsSorted; private boolean mIsSorted;
private boolean mIsListHeader;
public ItemGroup(TimedItem item) { public ItemGroup(long timestamp) {
mDate = new Date(item.getTimestamp()); mDate = new Date(timestamp);
mItems.add(item);
mIsSorted = true; mIsSorted = true;
} }
public void addItem(TimedItem item) { public void addItem(TimedItem item) {
mItems.add(item); mItems.add(item);
mIsSorted = false; mIsSorted = mItems.size() == 1;
} }
public void removeItem(TimedItem item) { public void removeItem(TimedItem item) {
...@@ -161,13 +167,15 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -161,13 +167,15 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
* @return The size of this group. * @return The size of this group.
*/ */
public int size() { public int size() {
if (mIsListHeader) return 1;
// Plus 1 to account for the date header. // Plus 1 to account for the date header.
return mItems.size() + 1; return mItems.size() + 1;
} }
public TimedItem getItemAt(int index) { public TimedItem getItemAt(int index) {
// 0 is allocated to the date header. // 0 is allocated to the date header. The list header has no items.
if (index == 0) return null; if (index == 0 || mIsListHeader) return null;
sortIfNeeded(); sortIfNeeded();
return mItems.get(index - 1); return mItems.get(index - 1);
...@@ -203,10 +211,12 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -203,10 +211,12 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
private static final AsyncTask<Void, Void, Calendar> sCal1 = createCalendar(); private static final AsyncTask<Void, Void, Calendar> sCal1 = createCalendar();
private static final AsyncTask<Void, Void, Calendar> sCal2 = createCalendar(); private static final AsyncTask<Void, Void, Calendar> sCal2 = createCalendar();
public static final int TYPE_HEADER = -1;
public static final int TYPE_DATE = 0; public static final int TYPE_DATE = 0;
public static final int TYPE_NORMAL = 1; public static final int TYPE_NORMAL = 1;
private int mSize; private int mSize;
private boolean mHasListHeader;
private SortedSet<ItemGroup> mGroups = new TreeSet<>(new Comparator<ItemGroup>() { private SortedSet<ItemGroup> mGroups = new TreeSet<>(new Comparator<ItemGroup>() {
@Override @Override
public int compare(ItemGroup lhs, ItemGroup rhs) { public int compare(ItemGroup lhs, ItemGroup rhs) {
...@@ -220,6 +230,14 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -220,6 +230,14 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
*/ */
protected abstract ViewHolder createViewHolder(ViewGroup parent); protected abstract ViewHolder createViewHolder(ViewGroup parent);
/**
* Creates a {@link HeaderViewHolder} in the given parent.
* @see #onCreateViewHolder(ViewGroup, int)
*/
protected HeaderViewHolder createHeader(ViewGroup parent) {
return null;
}
/** /**
* Binds the {@link ViewHolder} with the given {@link TimedItem}. * Binds the {@link ViewHolder} with the given {@link TimedItem}.
* @see #onBindViewHolder(ViewHolder, int) * @see #onBindViewHolder(ViewHolder, int)
...@@ -233,15 +251,10 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -233,15 +251,10 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
protected abstract int getTimedItemViewResId(); protected abstract int getTimedItemViewResId();
/** /**
* Loads a list of {@link TimedItem}s to this adapter. Any previous data will be removed. * Loads a list of {@link TimedItem}s to this adapter. Previous data will not be removed. Call
* {@link #clear(boolean)} to remove previous items.
*/ */
public void loadItems(List<? extends TimedItem> timedItems) { public void loadItems(List<? extends TimedItem> timedItems) {
mSize = 0;
// Unset the positions of all items in the list.
for (ItemGroup group : mGroups) group.resetPosition();
mGroups.clear();
for (TimedItem timedItem : timedItems) { for (TimedItem timedItem : timedItems) {
Date date = new Date(timedItem.getTimestamp()); Date date = new Date(timedItem.getTimestamp());
boolean found = false; boolean found = false;
...@@ -256,7 +269,9 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -256,7 +269,9 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
if (!found) { if (!found) {
// Create a new ItemGroup with the date for the new item. This increases the // Create a new ItemGroup with the date for the new item. This increases the
// size by two because we add new views for the date and the item itself. // size by two because we add new views for the date and the item itself.
mGroups.add(new ItemGroup(timedItem)); ItemGroup newGroup = new ItemGroup(timedItem.getTimestamp());
newGroup.addItem(timedItem);
mGroups.add(newGroup);
mSize += 2; mSize += 2;
} }
} }
...@@ -271,13 +286,33 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -271,13 +286,33 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
notifyDataSetChanged(); notifyDataSetChanged();
} }
/**
* Adds a header as the first group in this adapter.
*/
public void addHeader() {
assert mSize == 0;
ItemGroup header = new ItemGroup(Long.MAX_VALUE);
header.mIsListHeader = true;
mGroups.add(header);
mSize++;
mHasListHeader = true;
}
/** /**
* Removes all items from this adapter. * Removes all items from this adapter.
* @param notifyDataSetChanged Whether to notify that the data set has been changed.
*/ */
public void clear() { public void clear(boolean notifyDataSetChanged) {
mSize = 0; mSize = 0;
mHasListHeader = false;
// Unset the positions of all items in the list.
for (ItemGroup group : mGroups) group.resetPosition();
mGroups.clear(); mGroups.clear();
notifyDataSetChanged();
if (notifyDataSetChanged) notifyDataSetChanged();
} }
@Override @Override
...@@ -289,8 +324,8 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -289,8 +324,8 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
} }
/** /**
* Gets the item at the given position. For date headers, {@link TimedItem} will be null; for * Gets the item at the given position. For date headers and the list header, {@link TimedItem}
* normal items, {@link Date} will be null. * will be null; for normal items, {@link Date} will be null.
*/ */
public Pair<Date, TimedItem> getItemAt(int position) { public Pair<Date, TimedItem> getItemAt(int position) {
Pair<ItemGroup, Integer> pair = getGroupAt(position); Pair<ItemGroup, Integer> pair = getGroupAt(position);
...@@ -301,7 +336,13 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -301,7 +336,13 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
@Override @Override
public final int getItemViewType(int position) { public final int getItemViewType(int position) {
Pair<ItemGroup, Integer> pair = getGroupAt(position); Pair<ItemGroup, Integer> pair = getGroupAt(position);
return pair.second == 0 ? TYPE_DATE : TYPE_NORMAL; if (pair.second == TYPE_HEADER) {
return TYPE_HEADER;
} else if (pair.second == 0) {
return TYPE_DATE;
} else {
return TYPE_NORMAL;
}
} }
@Override @Override
...@@ -311,7 +352,10 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -311,7 +352,10 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
getTimedItemViewResId(), parent, false)); getTimedItemViewResId(), parent, false));
} else if (viewType == TYPE_NORMAL) { } else if (viewType == TYPE_NORMAL) {
return createViewHolder(parent); return createViewHolder(parent);
} else if (viewType == TYPE_HEADER) {
return createHeader(parent);
} }
assert false;
return null; return null;
} }
...@@ -320,7 +364,7 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -320,7 +364,7 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
Pair<Date, TimedItem> pair = getItemAt(position); Pair<Date, TimedItem> pair = getItemAt(position);
if (holder instanceof DateViewHolder) { if (holder instanceof DateViewHolder) {
((DateViewHolder) holder).setDate(pair.first); ((DateViewHolder) holder).setDate(pair.first);
} else { } else if (!(holder instanceof HeaderViewHolder)) {
bindViewHolderForTimedItem(holder, pair.second); bindViewHolderForTimedItem(holder, pair.second);
} }
} }
...@@ -335,6 +379,10 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder ...@@ -335,6 +379,10 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
*/ */
protected Pair<ItemGroup, Integer> getGroupAt(int position) { protected Pair<ItemGroup, Integer> getGroupAt(int position) {
// TODO(ianwen): Optimize the performance if the number of groups becomes too large. // TODO(ianwen): Optimize the performance if the number of groups becomes too large.
if (mHasListHeader && position == 0) {
return new Pair<>(mGroups.first(), TYPE_HEADER);
}
int i = position; int i = position;
for (ItemGroup group : mGroups) { for (ItemGroup group : mGroups) {
if (i >= group.size()) { if (i >= group.size()) {
......
...@@ -537,6 +537,18 @@ Your Google account may have other forms of browsing history like searches and a ...@@ -537,6 +537,18 @@ Your Google account may have other forms of browsing history like searches and a
<message name="IDS_CLEAR_BROWSING_DATA_IMPORTANT_DIALOG_BUTTON" desc="The text of the button to perform the clear action in the dialog presenting the user with 'important' sites that they can exclude from clearing."> <message name="IDS_CLEAR_BROWSING_DATA_IMPORTANT_DIALOG_BUTTON" desc="The text of the button to perform the clear action in the dialog presenting the user with 'important' sites that they can exclude from clearing.">
Clear Clear
</message> </message>
<message name="IDS_OPEN_CLEAR_BROWSING_DATA_DIALOG_BUTTON" desc="Title of the button that will open the clear browsing data dialog.">
Clear browsing data…
</message>
<message name="IDS_ANDROID_HISTORY_NO_SYNCED_RESULTS" desc="The notification at the top of the history page indicating that it does not include visits from other devices.">
Showing history from this device. <ph name="BEGIN_LINK">&lt;link&gt;</ph>Learn more<ph name="END_LINK">&lt;/link&gt;</ph>.
</message>
<message name="IDS_ANDROID_HISTORY_HAS_SYNCED_RESULTS" desc="The notification at the top of the history page indicating that it is showing visits synced from other devices.">
Showing history from your signed-in devices. <ph name="BEGIN_LINK">&lt;link&gt;</ph>Learn more<ph name="END_LINK">&lt;/link&gt;</ph>.
</message>
<message name="IDS_ANDROID_HISTORY_OTHER_FORMS_OF_HISTORY" desc="The notification at the top of the history page indicating that deleting Chrome browsing history will not delete other forms of history stored at Google My Activity.">
Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK">&lt;link&gt;</ph>history.google.com<ph name="END_LINK">&lt;/link&gt;</ph>.
</message>
<message name="IDS_USAGE_AND_CRASH_REPORTS_TITLE" desc="Title for 'Usage and crash reports' preference"> <message name="IDS_USAGE_AND_CRASH_REPORTS_TITLE" desc="Title for 'Usage and crash reports' preference">
Usage and crash reports Usage and crash reports
......
...@@ -43,7 +43,11 @@ void BrowsingHistoryBridge::QueryHistory( ...@@ -43,7 +43,11 @@ void BrowsingHistoryBridge::QueryHistory(
history::QueryOptions options; history::QueryOptions options;
options.max_count = kMaxQueryCount; options.max_count = kMaxQueryCount;
options.end_time = base::Time::FromJavaTime(j_query_end_time); if (j_query_end_time == 0) {
options.end_time = base::Time();
} else {
options.end_time = base::Time::FromJavaTime(j_query_end_time);
}
options.duplicate_policy = history::QueryOptions::REMOVE_DUPLICATES_PER_DAY; options.duplicate_policy = history::QueryOptions::REMOVE_DUPLICATES_PER_DAY;
browsing_history_service_->QueryHistory( browsing_history_service_->QueryHistory(
...@@ -138,7 +142,9 @@ void BrowsingHistoryBridge::HistoryDeleted() { ...@@ -138,7 +142,9 @@ void BrowsingHistoryBridge::HistoryDeleted() {
void BrowsingHistoryBridge::HasOtherFormsOfBrowsingHistory( void BrowsingHistoryBridge::HasOtherFormsOfBrowsingHistory(
bool has_other_forms, bool has_synced_results) { bool has_other_forms, bool has_synced_results) {
// TODO(twellington): implement JNIEnv* env = base::android::AttachCurrentThread();
Java_BrowsingHistoryBridge_hasOtherFormsOfBrowsingData(
env, j_history_service_obj_.obj(), has_other_forms, has_synced_results);
} }
bool RegisterBrowsingHistoryBridge(JNIEnv* env) { bool RegisterBrowsingHistoryBridge(JNIEnv* env) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment