Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java |
| index f3f9905fe82789bc1f0b637f02c36efe92864074..41fd5f5652e38e6a462eb28b87199676ac16edd0 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java |
| @@ -16,10 +16,12 @@ import org.chromium.base.metrics.RecordUserAction; |
| import org.chromium.chrome.R; |
| import org.chromium.chrome.browser.download.DownloadItem; |
| import org.chromium.chrome.browser.download.DownloadSharedPreferenceHelper; |
| +import org.chromium.chrome.browser.download.DownloadUtils; |
| import org.chromium.chrome.browser.download.ui.BackendProvider.DownloadDelegate; |
| import org.chromium.chrome.browser.download.ui.BackendProvider.OfflinePageDelegate; |
| import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.DownloadItemWrapper; |
| import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.OfflinePageItemWrapper; |
| +import org.chromium.chrome.browser.download.ui.DownloadManagerUi.DownloadBackendProvider; |
| import org.chromium.chrome.browser.download.ui.DownloadManagerUi.DownloadUiObserver; |
| import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBridge; |
| import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadItem; |
| @@ -28,9 +30,9 @@ import org.chromium.chrome.browser.widget.selection.SelectionDelegate; |
| import org.chromium.content_public.browser.DownloadState; |
| import java.util.ArrayList; |
| -import java.util.Calendar; |
| import java.util.Date; |
| import java.util.HashMap; |
| +import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| @@ -66,14 +68,13 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| /** Represents the subsection header of the suggested pages for a given date. */ |
| public class SubsectionHeader extends TimedItem { |
| private final long mTimestamp; |
| - private final int mItemCount; |
| - private final long mTotalFileSize; |
| + private int mItemCount; |
| + private long mTotalFileSize; |
| private final Long mStableId; |
| + private boolean mIsExpanded; |
| - public SubsectionHeader(Date date, int itemCount, long totalFileSize) { |
| + public SubsectionHeader(Date date) { |
| mTimestamp = date.getTime(); |
| - mItemCount = itemCount; |
| - mTotalFileSize = totalFileSize; |
| // Generate a stable ID based on timestamp. |
| mStableId = 0xFFFFFFFF00000000L + (getTimestamp() & 0x0FFFFFFFF); |
| @@ -96,6 +97,98 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| public long getStableId() { |
| return mStableId; |
| } |
| + |
| + /** @return Whether the subsection is currently expanded. */ |
| + public boolean isExpanded() { |
| + return mIsExpanded; |
| + } |
| + |
| + /** |
| + * @param isExpanded Whether the subsection is currently expanded. |
| + */ |
| + public void setIsExpanded(boolean isExpanded) { |
| + this.mIsExpanded = isExpanded; |
|
Theresa
2017/03/03 18:35:50
nit: "this." isn't necessary.
shaktisahu
2017/03/04 03:56:09
Done.
|
| + } |
| + |
| + /** |
| + * Helper method to set the properties of this class. |
| + */ |
| + public void update(int itemCount, long totalFileSize) { |
| + mItemCount = itemCount; |
| + mTotalFileSize = totalFileSize; |
| + } |
| + } |
| + |
| + /** |
| + * Separately maintains the selected state of the headers in addition to the other selected |
| + * items. |
| + */ |
| + public class DownloadItemSelectionDelegate |
| + extends SelectionDelegate<DownloadHistoryItemWrapper> { |
| + private Set<SubsectionHeader> mSelectedHeaders = new HashSet<>(); |
| + |
| + @Override |
| + public boolean isSelectionEnabled() { |
| + return !mSelectedHeaders.isEmpty() || super.isSelectionEnabled(); |
|
Theresa
2017/03/03 18:35:50
If any header is selected, doesn't that mean it's
shaktisahu
2017/03/04 03:56:09
Actually, this might be redundant in the current m
|
| + } |
| + |
| + /** |
| + * True if the header is currently selected. False otherwise. |
| + * @param header The given header. |
| + * @return Whether the header is selected. |
| + */ |
| + public boolean isHeaderSelected(SubsectionHeader header) { |
| + return mSelectedHeaders.contains(header); |
| + } |
| + |
| + @Override |
| + public void clearSelection() { |
| + mSelectedHeaders.clear(); |
| + super.clearSelection(); |
| + } |
| + |
| + /** |
| + * Toggles selection for a given header and sets the associated items to correct selection |
| + * state. |
| + * @param header The given header. |
| + * @return True if the header is selected after the toggle, false otherwise. |
| + */ |
| + public boolean toggleSelectionForHeader(SubsectionHeader header) { |
| + boolean newSelectedState = !isHeaderSelected(header); |
| + List<DownloadHistoryItemWrapper> items = header.isExpanded() |
| + ? getSuggestedItemsForDate(header.getTimestamp()) |
| + : mOfflinePageItems; |
| + |
| + for (DownloadHistoryItemWrapper item : items) { |
| + if (!DownloadUtils.isSameDay(header.getTimestamp(), item.getTimestamp())) { |
| + continue; |
| + } |
| + |
| + if (!((OfflinePageItemWrapper) item).isSuggested()) continue; |
| + |
| + if (newSelectedState != isItemSelected(item)) { |
| + toggleSelectionForItem(item); |
| + } |
| + } |
| + |
| + return setSelectionForHeader(header, newSelectedState); |
| + } |
| + |
| + /** |
| + * Sets the selection state for a given header. Doesn't affect the associated items. |
| + * @param header The given header. |
| + * @param selected The new selected state. |
| + * @return Whether the header was successfully selected. |
| + */ |
| + public boolean setSelectionForHeader(SubsectionHeader header, boolean selected) { |
| + if (selected) { |
| + mSelectedHeaders.add(header); |
| + } else { |
| + mSelectedHeaders.remove(header); |
| + } |
| + |
| + return isHeaderSelected(header); |
| + } |
| } |
| /** |
| @@ -113,7 +206,7 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| private final FilePathsToDownloadItemsMap mFilePathsToItemsMap = |
| new FilePathsToDownloadItemsMap(); |
| - private final Map<Date, Boolean> mSubsectionExpanded = new HashMap<>(); |
| + private final Map<Date, SubsectionHeader> mSubsectionHeaders = new HashMap<>(); |
| private final ComponentName mParentComponent; |
| private final boolean mShowOffTheRecord; |
| private final LoadingStateDelegate mLoadingDelegate; |
| @@ -137,6 +230,10 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| public void initialize(BackendProvider provider) { |
| mBackendProvider = provider; |
| + DownloadBackendProvider downloadBackendProvider = |
| + (DownloadBackendProvider) mBackendProvider; |
| + downloadBackendProvider.setSelectionDelegate(new DownloadItemSelectionDelegate()); |
| + |
| // Get all regular and (if necessary) off the record downloads. |
| DownloadDelegate downloadManager = getDownloadDelegate(); |
| downloadManager.addDownloadHistoryAdapter(this); |
| @@ -254,6 +351,7 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| (OfflineGroupHeaderView) LayoutInflater.from(parent.getContext()) |
| .inflate(R.layout.offline_download_header, parent, false); |
| offlineHeader.setAdapter(this); |
| + offlineHeader.setSelectionDelegate(getSelectionDelegate()); |
| return new SubsectionHeaderViewHolder(offlineHeader); |
| } |
| @@ -261,10 +359,8 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| protected void bindViewHolderForSubsectionHeader( |
| SubsectionHeaderViewHolder holder, TimedItem timedItem) { |
| SubsectionHeader headerItem = (SubsectionHeader) timedItem; |
| - Date date = new Date(headerItem.getTimestamp()); |
| OfflineGroupHeaderView headerView = (OfflineGroupHeaderView) holder.getView(); |
| - headerView.update(date, isSubsectionExpanded(date), headerItem.getItemCount(), |
| - headerItem.getTotalFileSize()); |
| + headerView.displayHeader(headerItem); |
| } |
| @Override |
| @@ -281,7 +377,8 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| final DownloadHistoryItemWrapper item = (DownloadHistoryItemWrapper) timedItem; |
| DownloadHistoryItemViewHolder holder = (DownloadHistoryItemViewHolder) current; |
| - holder.getItemView().displayItem(mBackendProvider, item); |
| + DownloadItemView itemView = holder.getItemView(); |
| + itemView.displayItem(mBackendProvider, item); |
| } |
| @Override |
| @@ -450,8 +547,8 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| return mBackendProvider.getOfflinePageBridge(); |
| } |
| - private SelectionDelegate<DownloadHistoryItemWrapper> getSelectionDelegate() { |
| - return mBackendProvider.getSelectionDelegate(); |
| + public DownloadItemSelectionDelegate getSelectionDelegate() { |
| + return (DownloadItemSelectionDelegate) mBackendProvider.getSelectionDelegate(); |
| } |
| /** Filters the list of downloads to show only files of a specific type. */ |
| @@ -461,7 +558,12 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| List<TimedItem> filteredTimedItems = new ArrayList<>(); |
| mRegularDownloadItems.filter(mFilter, mSearchQuery, filteredTimedItems); |
| mIncognitoDownloadItems.filter(mFilter, mSearchQuery, filteredTimedItems); |
| - filterOfflinePageItems(filteredTimedItems); |
| + |
| + if (TextUtils.isEmpty(mSearchQuery)) { |
| + filterOfflinePageItems(filteredTimedItems); |
| + } else { |
| + mOfflinePageItems.filter(mFilter, mSearchQuery, filteredTimedItems); |
| + } |
| clear(false); |
| loadItems(filteredTimedItems); |
| @@ -490,7 +592,10 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| offlineItem, suggestedPageCountMap, suggestedPageTotalSizeMap); |
| // TODO(shaktisahu): Check with UX if we need to skip this check and the subsection |
| // headers when filtering for active search text. |
| - if (!isSubsectionExpanded(getDateWithoutTime(offlineItem.getTimestamp()))) continue; |
| + if (!isSubsectionExpanded( |
| + DownloadUtils.getDateWithoutTime(offlineItem.getTimestamp()))) { |
| + continue; |
| + } |
| } |
| filteredTimedItems.add(offlineItem); |
| } |
| @@ -502,7 +607,7 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| // Updates the total number of suggested pages and file size grouped by date. |
| private void incrementSuggestedPageCount(OfflinePageItemWrapper offlineItem, |
| Map<Date, Integer> pageCountMap, Map<Date, Long> fileSizeMap) { |
| - Date date = getDateWithoutTime(offlineItem.getTimestamp()); |
| + Date date = DownloadUtils.getDateWithoutTime(offlineItem.getTimestamp()); |
| int count = pageCountMap.containsKey(date) ? pageCountMap.get(date) : 0; |
| pageCountMap.put(date, count + 1); |
| @@ -516,14 +621,18 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| Map<Date, Integer> pageCountMap, Map<Date, Long> fileSizeMap) { |
| for (Map.Entry<Date, Integer> entry : pageCountMap.entrySet()) { |
| Date date = entry.getKey(); |
| - filteredTimedItems.add( |
| - new SubsectionHeader(date, pageCountMap.get(date), fileSizeMap.get(date))); |
| + if (!mSubsectionHeaders.containsKey(date)) { |
| + mSubsectionHeaders.put(date, new SubsectionHeader(date)); |
| + } |
| + |
| + mSubsectionHeaders.get(date).update(pageCountMap.get(date), fileSizeMap.get(date)); |
| + filteredTimedItems.add(mSubsectionHeaders.get(date)); |
| } |
| // Remove entry from |mSubsectionExpanded| if there are no more suggested pages. |
| - Iterator<Entry<Date, Boolean>> iter = mSubsectionExpanded.entrySet().iterator(); |
| + Iterator<Entry<Date, SubsectionHeader>> iter = mSubsectionHeaders.entrySet().iterator(); |
| while (iter.hasNext()) { |
| - Entry<Date, Boolean> entry = iter.next(); |
| + Entry<Date, SubsectionHeader> entry = iter.next(); |
| if (!pageCountMap.containsKey(entry.getKey())) { |
| iter.remove(); |
| } |
| @@ -537,11 +646,11 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| */ |
| public boolean isSubsectionExpanded(Date date) { |
| // Default state is collpased. |
| - if (mSubsectionExpanded.get(date) == null) { |
| - mSubsectionExpanded.put(date, false); |
| + if (!mSubsectionHeaders.containsKey(date)) { |
| + return false; |
| } |
| - return mSubsectionExpanded.get(date); |
| + return mSubsectionHeaders.get(date).isExpanded(); |
| } |
| /** |
| @@ -550,11 +659,34 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| * @param expanded Whether the suggested pages should be expanded. |
| */ |
| public void setSubsectionExpanded(Date date, boolean expanded) { |
| - mSubsectionExpanded.put(date, expanded); |
| + mSubsectionHeaders.get(date).setIsExpanded(expanded); |
| clear(false); |
| filter(mFilter); |
| } |
| + /** |
| + * Returns a list of suggested pages for a given date. |
| + * @param timestamp The timestamp of the midnight. |
| + * @return A list containing all the suggested pages for that date. |
| + */ |
| + public List<DownloadHistoryItemWrapper> getSuggestedItemsForDate(long timestamp) { |
| + List<DownloadHistoryItemWrapper> suggestedItems = new ArrayList<>(); |
| + |
| + DownloadItemGroup group = (DownloadItemGroup) getGroupForDate(timestamp); |
| + for (int i = 0; i < group.size(); i++) { |
| + TimedItem item = group.getItemAt(i); |
| + if (item == null || !(item instanceof OfflinePageItemWrapper)) continue; |
| + |
| + OfflinePageItemWrapper offlineItem = (OfflinePageItemWrapper) item; |
| + if (!offlineItem.isSuggested()) continue; |
| + |
| + suggestedItems.add(offlineItem); |
| + } |
| + |
| + System.out.println(suggestedItems.size() + " suggestedItems for " + new Date(timestamp)); |
| + return suggestedItems; |
| + } |
| + |
| @Override |
| protected boolean isSubsectionHeader(TimedItem timedItem) { |
| return timedItem instanceof SubsectionHeader; |
| @@ -637,17 +769,4 @@ public class DownloadHistoryAdapter extends DateDividedAdapter |
| RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Total", |
| mRegularDownloadItems.size() + mOfflinePageItems.size()); |
| } |
| - |
| - /** |
| - * Calculates the {@link Date} for midnight of the date represented by the timestamp. |
| - */ |
| - private Date getDateWithoutTime(long timestamp) { |
| - Calendar cal = Calendar.getInstance(); |
| - cal.setTimeInMillis(timestamp); |
| - cal.set(Calendar.HOUR_OF_DAY, 0); |
| - cal.set(Calendar.MINUTE, 0); |
| - cal.set(Calendar.SECOND, 0); |
| - cal.set(Calendar.MILLISECOND, 0); |
| - return cal.getTime(); |
| - } |
| } |