Commit 28b06e6b authored by Becky Zhou's avatar Becky Zhou Committed by Commit Bot

Add animation to history info header

+ Make DateDividedAdapter support multiple header items so that
  privacy disclaimers and clear browsing data button can be seperate
  items in recycler view to support show/hide animation.
+ Hide info button when info header is not visible on scrolling down
  in both history and downloads.
+ Remove header when history items are all deleted.

BUG=689322

Change-Id: Idbcae648ba277eb82b87bbe5a0667373bb09fc1a
Reviewed-on: https://chromium-review.googlesource.com/560672
Commit-Queue: Becky Zhou <huayinz@chromium.org>
Reviewed-by: default avatarTheresa <twellington@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488031}
parent ec9c793c
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2017 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. -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2016 The Chromium Authors. All rights reserved.
<!-- Copyright 2017 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"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="8dp" >
<LinearLayout
android:id="@+id/privacy_disclaimers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="8dp"
android:visibility="gone"
android:layout_marginBottom="16dp" >
<org.chromium.ui.widget.TextViewWithClickableSpans
android:id="@+id/signed_in_not_synced"
style="@style/PrivacyDisclaimerText" />
<org.chromium.ui.widget.TextViewWithClickableSpans
android:id="@+id/signed_in_synced"
style="@style/PrivacyDisclaimerText" />
<org.chromium.ui.widget.TextViewWithClickableSpans
android:id="@+id/other_forms_of_browsing_history"
style="@style/PrivacyDisclaimerText" />
</LinearLayout>
android:paddingBottom="8dp"
android:background="@null" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_item_single" >
<!-- TODO(twellington): change start/end padding back to 16dp
when new assets with correct built in padding
are available. -->
<!-- TODO(twellington): change start/end padding back to 16dp and remove duplicate
FrameLayout when list item background is removed. -->
<Button
android:id="@+id/clear_browsing_data_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
style="@style/ButtonCompatBorderless"
android:paddingTop="16dp"
android:paddingBottom="16dp"
......@@ -54,6 +30,5 @@
android:textAllCaps="true"
android:textColor="@color/blue_when_enabled"
android:textSize="14sp" />
</FrameLayout>
</LinearLayout>
\ No newline at end of file
</FrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2017 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"
android:paddingBottom="16dp" >
<org.chromium.ui.widget.TextViewWithClickableSpans
android:id="@+id/signed_in_not_synced"
style="@style/PrivacyDisclaimerText" />
<org.chromium.ui.widget.TextViewWithClickableSpans
android:id="@+id/signed_in_synced"
style="@style/PrivacyDisclaimerText" />
<org.chromium.ui.widget.TextViewWithClickableSpans
android:id="@+id/other_forms_of_browsing_history"
style="@style/PrivacyDisclaimerText" />
<Space
android:id="@+id/privacy_disclaimer_bottom_space"
android:layout_width="match_parent"
android:layout_height="8dp" />
</LinearLayout>
\ No newline at end of file
......@@ -21,6 +21,8 @@
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="8dp"
android:clipToPadding="false"
android:visibility="gone" />
<TextView
......
......@@ -9,6 +9,7 @@ import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.chromium.base.ContextUtils;
......@@ -167,6 +168,7 @@ public class DownloadHistoryAdapter extends DateDividedAdapter
private int mFilter = DownloadFilter.FILTER_ALL;
private String mSearchQuery = EMPTY_QUERY;
private SpaceDisplay mSpaceDisplay;
private HeaderItem mSpaceDisplayHeaderItem;
private boolean mIsSearching;
private boolean mShouldShowStorageInfoHeader;
......@@ -191,6 +193,8 @@ public class DownloadHistoryAdapter extends DateDividedAdapter
mBackendProvider = provider;
mUiConfig = uiConfig;
generateHeaderItems();
DownloadItemSelectionDelegate selectionDelegate =
(DownloadItemSelectionDelegate) mBackendProvider.getSelectionDelegate();
selectionDelegate.initialize(this);
......@@ -363,27 +367,31 @@ public class DownloadHistoryAdapter extends DateDividedAdapter
holder.getItemView().displayItem(mBackendProvider, item);
}
@Override
protected void bindViewHolderForHeaderItem(ViewHolder viewHolder, HeaderItem headerItem) {
super.bindViewHolderForHeaderItem(viewHolder, headerItem);
mSpaceDisplay.onChanged();
}
@Override
protected ItemGroup createGroup(long timeStamp) {
return new DownloadItemGroup(timeStamp);
}
@Override
protected BasicViewHolder createHeader(ViewGroup parent) {
if (mSpaceDisplay == null) {
mSpaceDisplay = new SpaceDisplay(parent, this);
/**
* Initialize space display view in storage info header and generate header item for it.
*/
void generateHeaderItems() {
mSpaceDisplay = new SpaceDisplay(null, this);
View view = mSpaceDisplay.getView();
registerAdapterDataObserver(mSpaceDisplay);
if (mUiConfig != null) {
MarginResizer.createAndAttach(mSpaceDisplay.getView(), mUiConfig,
parent.getResources().getDimensionPixelSize(
R.dimen.list_item_default_margin),
MarginResizer.createAndAttach(view, mUiConfig,
view.getResources().getDimensionPixelSize(R.dimen.list_item_default_margin),
SelectableListLayout.getDefaultListItemLateralShadowSizePx(
parent.getResources()));
view.getResources()));
}
}
mSpaceDisplay.onChanged();
return new BasicViewHolder(mSpaceDisplay.getView());
mSpaceDisplayHeaderItem = new HeaderItem(0, view);
}
/** Called when a new DownloadItem has been created by the native DownloadManager. */
......@@ -598,7 +606,7 @@ public class DownloadHistoryAdapter extends DateDividedAdapter
clear(false);
if (!filteredTimedItems.isEmpty() && !mIsSearching && mShouldShowStorageInfoHeader) {
addHeader();
setHeaders(mSpaceDisplayHeaderItem);
}
loadItems(filteredTimedItems);
......
......@@ -24,12 +24,20 @@ import java.util.List;
public class DownloadManagerToolbar extends SelectableListToolbar<DownloadHistoryItemWrapper>
implements DownloadUiObserver {
private Spinner mSpinner;
private DownloadManagerUi mManager;
public DownloadManagerToolbar(Context context, AttributeSet attrs) {
super(context, attrs);
inflateMenu(R.menu.download_manager_menu);
}
/**
* @param manager The {@link DownloadManagerUi} associated with this toolbar.
*/
public void setManager(DownloadManagerUi manager) {
mManager = manager;
}
/**
* Initializes the spinner for the download filter.
* @param adapter The adapter associated with the spinner.
......@@ -95,6 +103,12 @@ public class DownloadManagerToolbar extends SelectableListToolbar<DownloadHistor
mSpinner.setAdapter(null);
}
@Override
protected void showNormalView() {
super.showNormalView();
mManager.updateInfoButtonVisibility();
}
@Override
public void showSearchView() {
super.showSearchView();
......
......@@ -9,6 +9,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar.OnMenuItemClickListener;
import android.view.LayoutInflater;
......@@ -200,6 +201,13 @@ public class DownloadManagerUi implements OnMenuItemClickListener, SearchDelegat
// Prevent every progress update from causing a transition animation.
mRecyclerView.getItemAnimator().setChangeDuration(0);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
updateInfoButtonVisibility();
}
});
mFilterAdapter = new FilterAdapter();
mFilterAdapter.initialize(this);
addObserver(mFilterAdapter);
......@@ -207,6 +215,7 @@ public class DownloadManagerUi implements OnMenuItemClickListener, SearchDelegat
mToolbar = (DownloadManagerToolbar) mSelectableListLayout.initializeToolbar(
R.layout.download_manager_toolbar, mBackendProvider.getSelectionDelegate(), 0, null,
R.id.normal_menu_group, R.id.selection_mode_menu_group, null, this, true);
mToolbar.setManager(this);
mToolbar.initializeFilterSpinner(mFilterAdapter);
mToolbar.initializeSearchView(this, R.string.download_manager_search, R.id.search_menu_id);
mToolbar.setInfoMenuItem(R.id.info_menu_id);
......@@ -454,6 +463,23 @@ public class DownloadManagerUi implements OnMenuItemClickListener, SearchDelegat
mSnackbarManager.dismissSnackbars(mUndoDeletionSnackbarController);
}
/**
* @return True if info menu item should be shown on download toolbar, false otherwise.
*/
boolean shouldShowInfoButton() {
return mHistoryAdapter.getItemCount() > 0 && !mToolbar.isSearching();
}
/**
* Update info button visibility based on whether info header is visible on download page.
*/
void updateInfoButtonVisibility() {
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
boolean infoHeaderIsVisible = layoutManager.findFirstVisibleItemPosition() == 0;
mToolbar.updateInfoMenuItem(infoHeaderIsVisible && shouldShowInfoButton(),
mHistoryAdapter.shouldShowStorageInfoHeader());
}
@VisibleForTesting
public SnackbarManager getSnackbarManagerForTesting() {
return mSnackbarManager;
......
......@@ -15,6 +15,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.ObserverList;
import org.chromium.base.VisibleForTesting;
......@@ -114,7 +115,7 @@ public class SpaceDisplay extends RecyclerView.AdapterDataObserver {
SpaceDisplay(final ViewGroup parent, DownloadHistoryAdapter historyAdapter) {
mHistoryAdapter = historyAdapter;
mView = (ViewGroup) LayoutInflater.from(parent.getContext())
mView = LayoutInflater.from(ContextUtils.getApplicationContext())
.inflate(R.layout.download_manager_ui_space_widget, parent, false);
mSpaceUsedByDownloadsTextView = (TextView) mView.findViewById(R.id.size_downloaded);
mSpaceUsedByOtherAppsTextView = (TextView) mView.findViewById(R.id.size_other_apps);
......
......@@ -14,7 +14,7 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Space;
import android.widget.TextView;
import org.chromium.base.VisibleForTesting;
......@@ -53,22 +53,24 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
private final ArrayList<HistoryItemView> mItemViews;
private RecyclerView mRecyclerView;
private ViewGroup mPrivacyDisclaimers;
private TextView mSignedInNotSyncedTextView;
private TextView mSignedInSyncedTextView;
private TextView mOtherFormsOfBrowsingHistoryTextView;
private Space mPrivacyDisclaimerBottomSpace;
private Button mClearBrowsingDataButton;
private FrameLayout mClearBrowsingDataButtonContainer;
private HeaderItem mPrivacyDisclaimerHeaderItem;
private HeaderItem mClearBrowsingDataButtonHeaderItem;
private boolean mHasOtherFormsOfBrowsingData;
private boolean mHasSyncedData;
private boolean mIsHeaderInflated;
private boolean mIsDestroyed;
private boolean mIsInitialized;
private boolean mIsLoadingItems;
private boolean mIsSearching;
private boolean mHasMorePotentialItems;
private boolean mClearOnNextQueryComplete;
private boolean mPrivacyDisclaimersVisible;
private boolean mClearBrowsingDataButtonVisible;
private long mNextQueryEndTime;
private String mQueryText = EMPTY_QUERY;
private int mDefaultTextMargin;
......@@ -194,6 +196,7 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
for (HistoryItemView itemView : mItemViews) {
itemView.onSignInStateChange();
}
initialize();
updateClearBrowsingDataButtonVisibility();
setPrivacyDisclaimerVisibility();
}
......@@ -252,7 +255,7 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
boolean wasInitialized = mIsInitialized;
if (!mIsInitialized) {
if (items.size() > 0 && !mIsSearching) addHeader();
if (items.size() > 0 && !mIsSearching) setHeaders();
mIsInitialized = true;
}
......@@ -298,28 +301,34 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
}
@Override
protected BasicViewHolder createHeader(ViewGroup parent) {
ViewGroup v = (ViewGroup) LayoutInflater.from(parent.getContext()).inflate(
R.layout.history_header, parent, false);
Resources resources = v.getResources();
mIsHeaderInflated = true;
protected BasicViewHolder createFooter(ViewGroup parent) {
return new BasicViewHolder(
LayoutInflater.from(parent.getContext())
.inflate(R.layout.indeterminate_progress_view, parent, false));
}
mClearBrowsingDataButton = (Button) v.findViewById(R.id.clear_browsing_data_button);
mClearBrowsingDataButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mHistoryManager.openClearBrowsingDataPreference();
}
});
mClearBrowsingDataButtonContainer = (FrameLayout) mClearBrowsingDataButton.getParent();
MarginResizer.createAndAttach(mClearBrowsingDataButtonContainer,
protected DateViewHolder createDateViewHolder(ViewGroup parent) {
DateViewHolder viewHolder = super.createDateViewHolder(parent);
MarginResizer.createAndAttach(viewHolder.itemView,
mHistoryManager.getSelectableListLayout().getUiConfig(),
SelectableListLayout.getDefaultListItemLateralMarginPx(resources), 0);
updateClearBrowsingDataButtonVisibility();
mPrivacyDisclaimers = (ViewGroup) v.findViewById(R.id.privacy_disclaimers);
getDefaultTextMargin(parent.getResources()),
SelectableListLayout.getDefaultListItemLateralShadowSizePx(parent.getResources()));
return viewHolder;
}
mSignedInNotSyncedTextView = (TextView) v.findViewById(R.id.signed_in_not_synced);
/**
* Initialize clear browsing data and privacy disclaimer header views and generate header
* items for them.
*/
void generateHeaderItems() {
ViewGroup privacyDisclaimers =
(ViewGroup) View.inflate(mHistoryManager.getSelectableListLayout().getContext(),
R.layout.history_privacy_disclaimer_header, null);
Resources resources = privacyDisclaimers.getResources();
mSignedInNotSyncedTextView =
(TextView) privacyDisclaimers.findViewById(R.id.signed_in_not_synced);
setPrivacyDisclaimerText(mSignedInNotSyncedTextView,
R.string.android_history_no_synced_results, LEARN_MORE_LINK);
MarginResizer.createAndAttach(mSignedInNotSyncedTextView,
......@@ -327,7 +336,7 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
getDefaultTextMargin(resources),
SelectableListLayout.getDefaultListItemLateralShadowSizePx(resources));
mSignedInSyncedTextView = (TextView) v.findViewById(R.id.signed_in_synced);
mSignedInSyncedTextView = (TextView) privacyDisclaimers.findViewById(R.id.signed_in_synced);
setPrivacyDisclaimerText(mSignedInSyncedTextView,
R.string.android_history_has_synced_results, LEARN_MORE_LINK);
MarginResizer.createAndAttach(mSignedInSyncedTextView,
......@@ -335,8 +344,8 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
getDefaultTextMargin(resources),
SelectableListLayout.getDefaultListItemLateralShadowSizePx(resources));
mOtherFormsOfBrowsingHistoryTextView = (TextView) v.findViewById(
R.id.other_forms_of_browsing_history);
mOtherFormsOfBrowsingHistoryTextView =
(TextView) privacyDisclaimers.findViewById(R.id.other_forms_of_browsing_history);
boolean flagEnabled = ChromeFeatureList.isEnabled(ChromeFeatureList.TABS_IN_CBD);
int disclaimerTextId = flagEnabled ? R.string.android_history_other_forms_of_history_new
: R.string.android_history_other_forms_of_history;
......@@ -348,25 +357,39 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
getDefaultTextMargin(resources),
SelectableListLayout.getDefaultListItemLateralShadowSizePx(resources));
setPrivacyDisclaimerVisibility();
mPrivacyDisclaimerBottomSpace =
(Space) privacyDisclaimers.findViewById(R.id.privacy_disclaimer_bottom_space);
return new BasicViewHolder(v);
}
ViewGroup clearBrowsingDataButtonContainer =
(ViewGroup) View.inflate(mHistoryManager.getSelectableListLayout().getContext(),
R.layout.history_clear_browsing_data_header, null);
mClearBrowsingDataButton = (Button) clearBrowsingDataButtonContainer.findViewById(
R.id.clear_browsing_data_button);
mClearBrowsingDataButton.setOnClickListener(new OnClickListener() {
@Override
protected BasicViewHolder createFooter(ViewGroup parent) {
return new BasicViewHolder(LayoutInflater.from(parent.getContext()).inflate(
R.layout.indeterminate_progress_view, parent, false));
public void onClick(View v) {
mHistoryManager.openClearBrowsingDataPreference();
}
@Override
protected DateViewHolder createDateViewHolder(ViewGroup parent) {
DateViewHolder viewHolder = super.createDateViewHolder(parent);
MarginResizer.createAndAttach(viewHolder.itemView,
});
MarginResizer.createAndAttach(clearBrowsingDataButtonContainer,
mHistoryManager.getSelectableListLayout().getUiConfig(),
getDefaultTextMargin(parent.getResources()),
SelectableListLayout.getDefaultListItemLateralShadowSizePx(parent.getResources()));
return viewHolder;
SelectableListLayout.getDefaultListItemLateralMarginPx(resources), 0);
mPrivacyDisclaimerHeaderItem = new HeaderItem(0, privacyDisclaimers);
mClearBrowsingDataButtonHeaderItem = new HeaderItem(1, clearBrowsingDataButtonContainer);
updateClearBrowsingDataButtonVisibility();
setPrivacyDisclaimerVisibility();
}
/**
* Pass header items to {@link #setHeaders(HeaderItem...)} as parameters.
*/
private void setHeaders() {
ArrayList<HeaderItem> args = new ArrayList<>();
if (mPrivacyDisclaimersVisible) args.add(mPrivacyDisclaimerHeaderItem);
if (mClearBrowsingDataButtonVisible) args.add(mClearBrowsingDataButtonHeaderItem);
setHeaders(args.toArray(new HeaderItem[args.size()]));
}
private void setPrivacyDisclaimerText(TextView view, int stringId, final String url) {
......@@ -396,26 +419,29 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
* Set visibility for privacy disclaimer layout and views.
*/
void setPrivacyDisclaimerVisibility() {
if (!mIsHeaderInflated) return;
boolean show = hasPrivacyDisclaimers() && mHistoryManager.shouldShowInfoHeaderIfAvailable();
boolean isSignedIn = ChromeSigninController.get().isSignedIn();
boolean shouldShowPrivacyDisclaimers =
hasPrivacyDisclaimers() && mHistoryManager.shouldShowInfoHeaderIfAvailable();
mSignedInNotSyncedTextView.setVisibility(
!mHasSyncedData && isSignedIn ? View.VISIBLE : View.GONE);
mSignedInSyncedTextView.setVisibility(mHasSyncedData ? View.VISIBLE : View.GONE);
mOtherFormsOfBrowsingHistoryTextView.setVisibility(
mHasOtherFormsOfBrowsingData ? View.VISIBLE : View.GONE);
mPrivacyDisclaimers.setVisibility(show ? View.VISIBLE : View.GONE);
// Prevent from refreshing the recycler view if header visibility is not changed.
if (mPrivacyDisclaimersVisible == shouldShowPrivacyDisclaimers) return;
mPrivacyDisclaimersVisible = shouldShowPrivacyDisclaimers;
if (mIsInitialized) setHeaders();
}
private void updateClearBrowsingDataButtonVisibility() {
// If the history header is not showing (e.g. when there is no browsing history),
// mClearBrowsingDataButton will be null.
if (mClearBrowsingDataButton == null) return;
mClearBrowsingDataButtonContainer.setVisibility(
!PrefServiceBridge.getInstance().canDeleteBrowsingHistory() ? View.GONE :
View.VISIBLE);
boolean shouldShowButton = PrefServiceBridge.getInstance().canDeleteBrowsingHistory();
if (mClearBrowsingDataButtonVisible == shouldShowButton) return;
mClearBrowsingDataButtonVisible = shouldShowButton;
mPrivacyDisclaimerBottomSpace.setVisibility(shouldShowButton ? View.GONE : View.VISIBLE);
if (mIsInitialized) setHeaders();
}
private int getDefaultTextMargin(Resources resources) {
......@@ -441,12 +467,27 @@ public class HistoryAdapter extends DateDividedAdapter implements BrowsingHistor
}
@VisibleForTesting
ViewGroup getPrivacyDisclaimersForTests() {
return mPrivacyDisclaimers;
ItemGroup getFirstGroupForTests() {
return getGroupAt(0).first;
}
@VisibleForTesting
void setClearBrowsingDataButtonVisibilityForTest(boolean isVisible) {
if (mClearBrowsingDataButton == null) return;
if (mClearBrowsingDataButtonVisible == isVisible) return;
mClearBrowsingDataButtonVisible = isVisible;
if (mIsInitialized) setHeaders();
}
@VisibleForTesting
public ArrayList<HistoryItemView> getItemViewsForTests() {
return mItemViews;
}
@VisibleForTesting
void generateHeaderItemsForTest() {
mPrivacyDisclaimerHeaderItem = new HeaderItem(0, null);
mClearBrowsingDataButtonHeaderItem = new HeaderItem(1, null);
mClearBrowsingDataButtonVisible = true;
}
}
......@@ -134,17 +134,23 @@ public class HistoryManager implements OnMenuItemClickListener, SignInStateObser
mLargeIconBridge.createCache(maxSize);
// 7. Initialize the adapter to load items.
mHistoryAdapter.generateHeaderItems();
mHistoryAdapter.initialize();
// 8. Add scroll listener to page in more items when necessary.
// 8. Add scroll listener to show/hide info button on scroll and page in more items
// when necessary.
mRecyclerView.addOnScrollListener(new OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (!mHistoryAdapter.canLoadMoreItems()) return;
// Load more items if the scroll position is close to the bottom of the list.
LinearLayoutManager layoutManager =
(LinearLayoutManager) recyclerView.getLayoutManager();
// Show info button if available if first visible position is close to info header;
// otherwise hide info button.
mToolbar.updateInfoMenuItem(infoHeaderIsVisible() && shouldShowInfoButton(),
shouldShowInfoHeaderIfAvailable());
if (!mHistoryAdapter.canLoadMoreItems()) return;
// Load more items if the scroll position is close to the bottom of the list.
if (layoutManager.findLastVisibleItemPosition()
> (mHistoryAdapter.getItemCount() - 25)) {
mHistoryAdapter.loadMoreItems();
......@@ -414,7 +420,8 @@ public class HistoryManager implements OnMenuItemClickListener, SignInStateObser
* @return True if info menu item should be shown on history toolbar, false otherwise.
*/
boolean shouldShowInfoButton() {
return mHistoryAdapter.hasPrivacyDisclaimers();
return mHistoryAdapter.hasPrivacyDisclaimers() && mHistoryAdapter.getItemCount() > 0
&& !mToolbar.isSearching();
}
/**
......@@ -425,6 +432,14 @@ public class HistoryManager implements OnMenuItemClickListener, SignInStateObser
return mShouldShowInfoHeader;
}
/**
* @return True if info header is visible on history page.
*/
boolean infoHeaderIsVisible() {
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
return (layoutManager.findFirstVisibleItemPosition() == 0);
}
@Override
public void onSignedIn() {
mToolbar.onSignInStateChange();
......
......@@ -44,8 +44,8 @@ public class HistoryManagerToolbar extends SelectableListToolbar<HistoryItem> {
@Override
protected void showNormalView() {
super.showNormalView();
updateInfoMenuItem(
mManager.shouldShowInfoButton(), mManager.shouldShowInfoHeaderIfAvailable());
updateInfoMenuItem(mManager.infoHeaderIsVisible() && mManager.shouldShowInfoButton(),
mManager.shouldShowInfoHeaderIfAvailable());
}
@Override
......@@ -77,9 +77,7 @@ public class HistoryManagerToolbar extends SelectableListToolbar<HistoryItem> {
@Override
protected void onDataChanged(int numItems) {
super.onDataChanged(numItems);
getMenu()
.findItem(R.id.info_menu_id)
.setVisible(mManager.shouldShowInfoButton() && !mIsSearching && numItems > 0);
getMenu().findItem(R.id.info_menu_id).setVisible(mManager.shouldShowInfoButton());
}
/**
......
......@@ -105,6 +105,41 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
public abstract long getStableId();
}
/**
* Contains information of a single header that this adapter uses to manage headers.
*/
public static class HeaderItem extends TimedItem {
private final long mStableId;
private final View mView;
/**
* Initialize stable id and view associated with this HeaderItem.
* @param position Position of this HeaderItem in the header group.
* @param view View associated with this HeaderItem.
*/
public HeaderItem(int position, View view) {
mStableId = getTimestamp() - position;
mView = view;
}
@Override
public long getTimestamp() {
return Long.MAX_VALUE;
}
@Override
public long getStableId() {
return mStableId;
}
/**
* @return The View associated with this HeaderItem.
*/
public View getView() {
return mView;
}
}
/**
* A {@link RecyclerView.ViewHolder} that displays a date header.
*/
......@@ -193,6 +228,10 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
mItems.remove(item);
}
public void removeAllItems() {
mItems.clear();
}
/** Records the position of all the TimedItems in this group, relative to the full list. */
public void setPosition(int index) {
assert mIndex == 0 || mIndex == TimedItem.INVALID_POSITION;
......@@ -225,15 +264,18 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
* @return The size of this group.
*/
public int size() {
if (mIsListHeader || mIsListFooter) return 1;
if (mIsListHeader) return mItems.size();
if (mIsListFooter) return 1;
// Plus 1 to account for the date header.
return mItems.size() + 1;
}
public TimedItem getItemAt(int index) {
// 0 is allocated to the date header. The list header has no items.
if (index <= 0 || mIsListHeader || mIsListFooter) return null;
// 0 is allocated to the date header. Return item if list header has
// header items, otherwise return null.
if (mIsListHeader) return mItems.get(index);
if (index <= 0 || mIsListFooter) return null;
sortIfNeeded();
return mItems.get(index - 1);
......@@ -305,12 +347,15 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
protected abstract ViewHolder createViewHolder(ViewGroup parent);
/**
* Creates a {@link BasicViewHolder} in the given view parent for the header.
* Creates a {@link BasicViewHolder} in the given view parent for the header. The default
* implementation will create an empty FrameLayout container as the view holder.
* @see #onCreateViewHolder(ViewGroup, int)
*/
@Nullable
protected BasicViewHolder createHeader(ViewGroup parent) {
return null;
// Create an empty layout as a container for the header view.
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.date_divided_adapter_header_view_holder, parent, false);
return new BasicViewHolder(v);
}
/**
......@@ -362,6 +407,18 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
protected void bindViewHolderForSubsectionHeader(
SubsectionHeaderViewHolder holder, TimedItem timedItem) {}
/**
* Binds the {@link BasicViewHolder} with the given {@link HeaderItem}.
* @see #onBindViewHolder(ViewHolder, int)
*/
protected void bindViewHolderForHeaderItem(ViewHolder viewHolder, HeaderItem headerItem) {
BasicViewHolder basicViewHolder = (BasicViewHolder) viewHolder;
View v = headerItem.getView();
((ViewGroup) basicViewHolder.itemView).removeAllViews();
if (v.getParent() != null) ((ViewGroup) v.getParent()).removeView(v);
((ViewGroup) basicViewHolder.itemView).addView(v);
}
/**
* Gets the resource id of the view showing the date header.
* Contract for subclasses: this view should be a {@link TextView}.
......@@ -420,17 +477,40 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
}
/**
* Adds a header as the first group in this adapter.
* Add a list of headers as the first group in this adapter. If headerItems has no items,
* the header group will not be created. Otherwise, header items will be added as child items
* to the header group. Note that any previously added header items will be removed.
* {@link #bindViewHolderForHeaderItem(ViewHolder, HeaderItem)} will bind the HeaderItem views
* to the given ViewHolder. Sub-classes may override #bindViewHolderForHeaderItem and
* (@link #createHeader(ViewGroup)} if custom behavior is needed.
*
* @param headerItems Zero or more header items to be add to the header item group.
*/
public void addHeader() {
assert mSize == 0;
public void setHeaders(HeaderItem... headerItems) {
if (headerItems == null || headerItems.length == 0) {
removeHeader();
return;
}
ItemGroup header = new ItemGroup(Long.MAX_VALUE);
ItemGroup header;
if (mHasListHeader) {
header = mGroups.first();
mSize -= header.size();
header.removeAllItems();
} else {
header = new ItemGroup(Long.MAX_VALUE);
header.mIsListHeader = true;
mGroups.add(header);
}
for (HeaderItem item : headerItems) {
header.addItem(item);
mSize++;
}
mHasListHeader = true;
setGroupPositions();
notifyDataSetChanged();
}
/**
......@@ -439,8 +519,8 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
public void removeHeader() {
if (!mHasListHeader) return;
mSize -= mGroups.first().size();
mGroups.remove(mGroups.first());
mSize--;
mHasListHeader = false;
setGroupPositions();
......@@ -510,7 +590,8 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
public Pair<Date, TimedItem> getItemAt(int position) {
Pair<ItemGroup, Integer> pair = getGroupAt(position);
ItemGroup group = pair.first;
return new Pair<>(group.mDate, group.getItemAt(pair.second));
return new Pair<>(group.mDate,
group.mIsListHeader ? group.getItemAt(position) : group.getItemAt(pair.second));
}
@Override
......@@ -556,6 +637,8 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
bindViewHolderForSubsectionHeader((SubsectionHeaderViewHolder) holder, pair.second);
} else if (!(holder instanceof BasicViewHolder)) {
bindViewHolderForTimedItem(holder, pair.second);
} else if (pair.second instanceof HeaderItem) {
bindViewHolderForHeaderItem(holder, (HeaderItem) pair.second);
}
}
......@@ -569,7 +652,7 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
*/
protected Pair<ItemGroup, Integer> getGroupAt(int position) {
// TODO(ianwen): Optimize the performance if the number of groups becomes too large.
if (mHasListHeader && position == 0) {
if (mHasListHeader && position < mGroups.first().size()) {
assert mGroups.first().mIsListHeader;
return new Pair<>(mGroups.first(), TYPE_HEADER);
}
......
......@@ -90,7 +90,7 @@ public class DownloadHistoryAdapterTest {
editor.putBoolean(PREF_SHOW_STORAGE_INFO_HEADER, true).apply();
}
private void initializeAdapter(boolean showOffTheRecord) throws Exception {
private void initializeAdapter(boolean showOffTheRecord, boolean hasHeader) throws Exception {
mObserver = new Observer();
mAdapter = new DownloadHistoryAdapter(showOffTheRecord, null);
mAdapter.registerAdapterDataObserver(mObserver);
......@@ -106,14 +106,17 @@ public class DownloadHistoryAdapterTest {
}
});
mDownloadDelegate.addCallback.waitForCallback(0);
mObserver.onChangedCallback.waitForCallback(callCount, 1);
// If header should be added, onChanged() will be called twice because both setHeaders()
// and loadMoreItems() will call notifyDataSetChanged(). Otherwise, setHeaders() will not
// be called and onChanged() will only be called once.
mObserver.onChangedCallback.waitForCallback(callCount, hasHeader ? 2 : 1);
}
/** Nothing downloaded, nothing shown. */
@Test
@SmallTest
public void testInitialize_Empty() throws Exception {
initializeAdapter(false);
initializeAdapter(false, false);
Assert.assertEquals(0, mAdapter.getItemCount());
Assert.assertEquals(0, mAdapter.getTotalDownloadSize());
......@@ -133,7 +136,7 @@ public class DownloadHistoryAdapterTest {
public void testInitialize_SingleItem() throws Exception {
DownloadItem item = StubbedProvider.createDownloadItem(0, "19840116 12:00");
mDownloadDelegate.regularItems.add(item);
initializeAdapter(false);
initializeAdapter(false, true);
checkAdapterContents(HEADER, null, item);
Assert.assertEquals(1, mAdapter.getTotalDownloadSize());
}
......@@ -146,7 +149,7 @@ public class DownloadHistoryAdapterTest {
DownloadItem item1 = StubbedProvider.createDownloadItem(1, "19840116 12:01");
mDownloadDelegate.regularItems.add(item0);
mDownloadDelegate.regularItems.add(item1);
initializeAdapter(false);
initializeAdapter(false, true);
checkAdapterContents(HEADER, null, item1, item0);
Assert.assertEquals(11, mAdapter.getTotalDownloadSize());
}
......@@ -159,7 +162,7 @@ public class DownloadHistoryAdapterTest {
DownloadItem item1 = StubbedProvider.createDownloadItem(1, "19840117 12:00");
mDownloadDelegate.regularItems.add(item0);
mDownloadDelegate.regularItems.add(item1);
initializeAdapter(false);
initializeAdapter(false, true);
checkAdapterContents(HEADER, null, item1, null, item0);
Assert.assertEquals(11, mAdapter.getTotalDownloadSize());
}
......@@ -172,7 +175,7 @@ public class DownloadHistoryAdapterTest {
editor.putBoolean(PREF_SHOW_STORAGE_INFO_HEADER, false).apply();
DownloadItem item = StubbedProvider.createDownloadItem(0, "19840116 12:00");
mDownloadDelegate.regularItems.add(item);
initializeAdapter(false);
initializeAdapter(false, false);
checkAdapterContents(null, item);
Assert.assertEquals(1, mAdapter.getTotalDownloadSize());
}
......@@ -185,7 +188,7 @@ public class DownloadHistoryAdapterTest {
DownloadItem item1 = StubbedProvider.createDownloadItem(1, "19840116 12:01");
mDownloadDelegate.regularItems.add(item0);
mDownloadDelegate.regularItems.add(item1);
initializeAdapter(false);
initializeAdapter(false, true);
checkAdapterContents(HEADER, null, item1, item0);
Assert.assertEquals(11, mAdapter.getTotalDownloadSize());
......@@ -216,7 +219,7 @@ public class DownloadHistoryAdapterTest {
DownloadItem item1 = StubbedProvider.createDownloadItem(1, "19840116 12:01");
mDownloadDelegate.regularItems.add(item0);
mDownloadDelegate.offTheRecordItems.add(item1);
initializeAdapter(false);
initializeAdapter(false, true);
checkAdapterContents(HEADER, null, item0);
Assert.assertEquals(1, mAdapter.getTotalDownloadSize());
}
......@@ -229,7 +232,7 @@ public class DownloadHistoryAdapterTest {
DownloadItem item1 = StubbedProvider.createDownloadItem(1, "19840116 12:00");
mDownloadDelegate.regularItems.add(item0);
mDownloadDelegate.offTheRecordItems.add(item1);
initializeAdapter(true);
initializeAdapter(true, true);
checkAdapterContents(HEADER, null, item0, item1);
Assert.assertEquals(11, mAdapter.getTotalDownloadSize());
}
......@@ -244,7 +247,7 @@ public class DownloadHistoryAdapterTest {
mDownloadDelegate.regularItems.add(item0);
mDownloadDelegate.offTheRecordItems.add(item1);
mOfflineDelegate.items.add(item2);
initializeAdapter(true);
initializeAdapter(true, true);
checkAdapterContents(HEADER, null, item2, null, item0, item1);
Assert.assertEquals(100011, mAdapter.getTotalDownloadSize());
}
......@@ -254,7 +257,7 @@ public class DownloadHistoryAdapterTest {
@SmallTest
public void testUpdate_UpdateItems() throws Exception {
// Start with an empty Adapter.
initializeAdapter(false);
initializeAdapter(false, false);
Assert.assertEquals(0, mAdapter.getItemCount());
Assert.assertEquals(0, mAdapter.getTotalDownloadSize());
......@@ -267,7 +270,7 @@ public class DownloadHistoryAdapterTest {
Assert.assertEquals(1, mAdapter.getTotalDownloadSize());
// Add a second item with a different date.
Assert.assertEquals(2, mObserver.onChangedCallback.getCallCount());
Assert.assertEquals(3, mObserver.onChangedCallback.getCallCount());
DownloadItem item1 = StubbedProvider.createDownloadItem(1, "19840117 12:00");
mAdapter.onDownloadItemCreated(item1);
mObserver.onChangedCallback.waitForCallback(2);
......@@ -323,26 +326,28 @@ public class DownloadHistoryAdapterTest {
mDownloadDelegate.regularItems.add(regularItem);
mDownloadDelegate.offTheRecordItems.add(offTheRecordItem);
mOfflineDelegate.items.add(offlineItem);
initializeAdapter(true);
initializeAdapter(true, true);
checkAdapterContents(HEADER, null, offlineItem, null, regularItem, offTheRecordItem);
Assert.assertEquals(100011, mAdapter.getTotalDownloadSize());
// Remove an item from the date bucket with two items.
Assert.assertEquals(1, mObserver.onChangedCallback.getCallCount());
// Remove an item from the date bucket with two items. Wait for two callbacks as
// notifyDataSetChanged() is called once when setHeaders() is called and once when items
// are loaded.
Assert.assertEquals(2, mObserver.onChangedCallback.getCallCount());
mAdapter.onDownloadItemRemoved(offTheRecordItem.getId(), true);
mObserver.onChangedCallback.waitForCallback(1);
checkAdapterContents(HEADER, null, offlineItem, null, regularItem);
Assert.assertEquals(100001, mAdapter.getTotalDownloadSize());
// Remove an item from the second bucket, which removes the bucket entirely.
Assert.assertEquals(2, mObserver.onChangedCallback.getCallCount());
Assert.assertEquals(4, mObserver.onChangedCallback.getCallCount());
mOfflineDelegate.observer.onItemDeleted(offlineItem.getGuid());
mObserver.onChangedCallback.waitForCallback(2);
checkAdapterContents(HEADER, null, regularItem);
Assert.assertEquals(1, mAdapter.getTotalDownloadSize());
// Remove the last item in the list.
Assert.assertEquals(3, mObserver.onChangedCallback.getCallCount());
Assert.assertEquals(6, mObserver.onChangedCallback.getCallCount());
mAdapter.onDownloadItemRemoved(regularItem.getId(), false);
mObserver.onChangedCallback.waitForCallback(3);
Assert.assertEquals(0, mAdapter.getItemCount());
......@@ -367,7 +372,7 @@ public class DownloadHistoryAdapterTest {
mDownloadDelegate.offTheRecordItems.add(item4);
mDownloadDelegate.regularItems.add(item5);
mOfflineDelegate.items.add(item6);
initializeAdapter(true);
initializeAdapter(true, true);
checkAdapterContents(
HEADER, null, item5, item4, item6, null, item3, item2, null, item1, item0);
Assert.assertEquals(1666, mAdapter.getTotalDownloadSize());
......@@ -401,7 +406,7 @@ public class DownloadHistoryAdapterTest {
mOfflineDelegate.items.add(item0);
mOfflineDelegate.items.add(item1);
mOfflineDelegate.items.add(item2);
initializeAdapter(false);
initializeAdapter(false, true);
checkAdapterContents(HEADER, null, item2, null, item1, item0);
Assert.assertEquals(111000, mAdapter.getTotalDownloadSize());
......@@ -427,7 +432,7 @@ public class DownloadHistoryAdapterTest {
public void testInProgress_FilePathMapAccurate() throws Exception {
Set<DownloadHistoryItemWrapper> toDelete;
initializeAdapter(false);
initializeAdapter(false, false);
Assert.assertEquals(0, mAdapter.getItemCount());
Assert.assertEquals(0, mAdapter.getTotalDownloadSize());
......@@ -486,7 +491,7 @@ public class DownloadHistoryAdapterTest {
mDownloadDelegate.offTheRecordItems.add(item4);
mDownloadDelegate.regularItems.add(item5);
mOfflineDelegate.items.add(item6);
initializeAdapter(true);
initializeAdapter(true, true);
checkAdapterContents(
HEADER, null, item5, item4, item6, null, item3, item2, null, item1, item0);
......@@ -540,7 +545,7 @@ public class DownloadHistoryAdapterTest {
mDownloadDelegate.offTheRecordItems.add(item4);
mDownloadDelegate.regularItems.add(item5);
mOfflineDelegate.items.add(item6);
initializeAdapter(true);
initializeAdapter(true, true);
checkAdapterContents(
HEADER, null, item5, item4, item6, null, item3, item2, null, item1, item0);
......@@ -586,7 +591,7 @@ public class DownloadHistoryAdapterTest {
mDownloadDelegate.offTheRecordItems.add(item4);
mDownloadDelegate.regularItems.add(item5);
mOfflineDelegate.items.add(item6);
initializeAdapter(true);
initializeAdapter(true, true);
checkAdapterContents(
HEADER, null, item5, item4, item6, null, item3, item2, null, item1, item0);
......
......@@ -34,6 +34,7 @@ import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.signin.SigninManager;
import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
import org.chromium.chrome.browser.widget.DateDividedAdapter;
import org.chromium.chrome.browser.widget.TintedImageButton;
import org.chromium.chrome.browser.widget.selection.SelectableItemView;
import org.chromium.chrome.browser.widget.selection.SelectableItemViewHolder;
......@@ -442,11 +443,10 @@ public class HistoryActivityTest extends BaseActivityInstrumentationTestCase<His
// Not signed in
ChromeSigninController signinController = ChromeSigninController.get();
signinController.setSignedInAccountName(null);
assertEquals(false, infoMenuItem.isVisible());
assertEquals(View.GONE, mAdapter.getSignedInNotSyncedViewForTests().getVisibility());
assertEquals(View.GONE, mAdapter.getSignedInSyncedViewForTests().getVisibility());
assertEquals(
View.GONE, mAdapter.getOtherFormsOfBrowsingHistoryViewForTests().getVisibility());
assertFalse(infoMenuItem.isVisible());
DateDividedAdapter.ItemGroup headerGroup = mAdapter.getFirstGroupForTests();
assertTrue(mAdapter.hasListHeader());
assertEquals(1, headerGroup.size());
// Signed in but not synced and history has items
signinController.setSignedInAccountName("test@gmail.com");
......@@ -457,22 +457,100 @@ public class HistoryActivityTest extends BaseActivityInstrumentationTestCase<His
toolbar.onSignInStateChange();
}
});
assertEquals(true, infoMenuItem.isVisible());
assertTrue(infoMenuItem.isVisible());
// Signed in, synced, has other forms and has items
// Privacy disclaimers should be shown by default
setHasOtherFormsOfBrowsingData(true, true);
assertEquals(true, infoMenuItem.isVisible());
assertEquals(View.VISIBLE, mAdapter.getPrivacyDisclaimersForTests().getVisibility());
assertTrue(infoMenuItem.isVisible());
headerGroup = mAdapter.getFirstGroupForTests();
assertTrue(mAdapter.hasListHeader());
assertEquals(2, headerGroup.size());
// Toggle Info Menu Item
// Toggle Info Menu Item to off
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
mHistoryManager.onMenuItemClick(infoMenuItem);
}
});
assertEquals(View.GONE, mAdapter.getPrivacyDisclaimersForTests().getVisibility());
headerGroup = mAdapter.getFirstGroupForTests();
assertTrue(mAdapter.hasListHeader());
assertEquals(1, headerGroup.size());
// Toggle Info Menu Item to on
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
mHistoryManager.onMenuItemClick(infoMenuItem);
}
});
headerGroup = mAdapter.getFirstGroupForTests();
assertTrue(mAdapter.hasListHeader());
assertEquals(2, headerGroup.size());
signinController.setSignedInAccountName(null);
}
@SmallTest
public void testInfoHeaderInSearchMode() throws Exception {
final HistoryManagerToolbar toolbar = mHistoryManager.getToolbarForTests();
final MenuItem infoMenuItem = toolbar.getItemById(R.id.info_menu_id);
// Sign in
int callCount = mTestObserver.onSelectionCallback.getCallCount();
ChromeSigninController signinController = ChromeSigninController.get();
signinController.setSignedInAccountName("test@gmail.com");
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
toolbar.onSignInStateChange();
mAdapter.onSignInStateChange();
}
});
mTestObserver.onChangedCallback.waitForCallback(callCount, 1);
DateDividedAdapter.ItemGroup firstGroup = mAdapter.getFirstGroupForTests();
assertTrue(infoMenuItem.isVisible());
assertTrue(mAdapter.hasListHeader());
assertEquals(2, firstGroup.size());
// Enter search mode
callCount = mTestObserver.onSelectionCallback.getCallCount();
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
toolbar.getMenu().performIdentifierAction(R.id.search_menu_id, 0);
}
});
mTestObserver.onSelectionCallback.waitForCallback(callCount, 1);
firstGroup = mAdapter.getFirstGroupForTests();
assertFalse(infoMenuItem.isVisible());
// The first group should be the history item group from SetUp()
assertFalse(mAdapter.hasListHeader());
assertEquals(3, firstGroup.size());
signinController.setSignedInAccountName(null);
}
@SmallTest
public void testInvisibleHeader() throws Exception {
assertTrue(mAdapter.hasListHeader());
// Not sign in and set clear browsing data button to invisible
ChromeSigninController signinController = ChromeSigninController.get();
signinController.setSignedInAccountName(null);
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
mAdapter.setClearBrowsingDataButtonVisibilityForTest(false);
mAdapter.setPrivacyDisclaimerVisibility();
}
});
DateDividedAdapter.ItemGroup firstGroup = mAdapter.getFirstGroupForTests();
assertFalse(mAdapter.hasListHeader());
assertEquals(3, firstGroup.size());
}
@SmallTest
......
......@@ -36,6 +36,7 @@ public class HistoryAdapterTest {
public void setUp() throws Exception {
mHistoryProvider = new StubbedHistoryProvider();
mAdapter = new HistoryAdapter(new SelectionDelegate<HistoryItem>(), null, mHistoryProvider);
mAdapter.generateHeaderItemsForTest();
}
private void initializeAdapter() {
......
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