Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemGroup.java | 
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemGroup.java | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..72f44d5f8a8b9e15fc08f5be5818f784d254cdbe | 
| --- /dev/null | 
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemGroup.java | 
| @@ -0,0 +1,201 @@ | 
| +// 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. | 
| + | 
| +package org.chromium.chrome.browser.download.ui; | 
| + | 
| +import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.OfflinePageItemWrapper; | 
| +import org.chromium.chrome.browser.widget.DateDividedAdapter; | 
| +import org.chromium.chrome.browser.widget.DateDividedAdapter.TimedItem; | 
| + | 
| +/** | 
| + * A bucket of downloaded items with the same date. It also holds the suggested offline items which | 
| + * are shown at the end of the list for that date. | 
| + */ | 
| +public class DownloadItemGroup extends DateDividedAdapter.ItemGroup { | 
| + private int mNumSuggestedOfflinePages; | 
| + private boolean mIsSuggestedOfflinePagesSectionExpanded; | 
| + | 
| + /** The header representing the offline pages that are automatically downloaded */ | 
| + private TimedItem mSuggestedOfflinePagesHeader; | 
| + | 
| + public DownloadItemGroup(long timestamp) { | 
| + super(timestamp); | 
| + mNumSuggestedOfflinePages = 0; | 
| + mIsSuggestedOfflinePagesSectionExpanded = false; | 
| + } | 
| + | 
| + /** @return Whether the suggested pages are expanded. */ | 
| + public boolean isSuggestedOfflinePagesSectionExpanded() { | 
| + return mIsSuggestedOfflinePagesSectionExpanded; | 
| + } | 
| + | 
| + /** | 
| + * Expands or collapses the suggested offline pages. | 
| + * @param expanded Whether the suggested pages should be shown. | 
| + */ | 
| + public void setIsSuggestedOfflinePagesSectionExpanded(boolean expanded) { | 
| + mIsSuggestedOfflinePagesSectionExpanded = expanded; | 
| + } | 
| + | 
| + /** @return The total number of suggested pages for this date. */ | 
| + public int getSuggestedOfflinePageCount() { | 
| + return mNumSuggestedOfflinePages; | 
| + } | 
| + | 
| + private TimedItem getSuggestedOfflinePagesHeader() { | 
| + if (mSuggestedOfflinePagesHeader == null) { | 
| + mSuggestedOfflinePagesHeader = new TimedItem() { | 
| + private Long mStableId; | 
| + | 
| + @Override | 
| + public long getTimestamp() { | 
| + return getDate().getTime(); | 
| + } | 
| + | 
| + @Override | 
| + public long getStableId() { | 
| + if (mStableId == null) { | 
| + // Generate a stable ID based on timestamp. | 
| + mStableId = 0xFFFFFFFF00000000L + getTimestamp() & 0x0FFFFFFFF; | 
| + } | 
| + return mStableId; | 
| + } | 
| + }; | 
| + } | 
| + | 
| + return mSuggestedOfflinePagesHeader; | 
| + } | 
| + | 
| + @Override | 
| + public void addItem(TimedItem item) { | 
| + super.addItem(item); | 
| + if (isSuggestedOfflinePage(item)) { | 
| + mNumSuggestedOfflinePages++; | 
| + } | 
| + } | 
| + | 
| + @Override | 
| + public void removeItem(TimedItem item) { | 
| + super.removeItem(item); | 
| + if (isSuggestedOfflinePage(item)) { | 
| + mNumSuggestedOfflinePages--; | 
| + } | 
| + } | 
| + | 
| + /** | 
| + * The visible items for the group are set to their respective positions in the list view. | 
| + * Invisible (collpased) items are skipped. | 
| + */ | 
| + @Override | 
| + protected void setPositionForItems(int startIndex) { | 
| + int index = startIndex; | 
| + boolean firstSuggestedItem = true; | 
| + for (TimedItem item : mItems) { | 
| + if (isSuggestedOfflinePage(item)) { | 
| + // Skip one position for the header at the beginning of the suggested items section. | 
| + if (firstSuggestedItem) { | 
| + index += 1; | 
| + firstSuggestedItem = false; | 
| + } | 
| + if (!isSuggestedOfflinePagesSectionExpanded()) break; | 
| + } | 
| + item.setPosition(index); | 
| + index += 1; | 
| + } | 
| + } | 
| + | 
| + @Override | 
| + protected void setPositionForFirstAndLastInGroup() { | 
| + TimedItem first = mItems.get(0); | 
| + first.setIsFirstInGroup(true); | 
| + | 
| + TimedItem last = mItems.get(mItems.size() - 1); | 
| + if (!isSuggestedOfflinePagesSectionExpanded() && mNumSuggestedOfflinePages > 0) { | 
| + last = getSuggestedOfflinePagesHeader(); | 
| + } | 
| + | 
| + last.setIsLastInGroup(true); | 
| + } | 
| + | 
| + @Override | 
| + public int size() { | 
| + int size = super.size(); | 
| + | 
| + // The size should match the number of rows in the list view. So, adjust the size depending | 
| + // on whether the suggested items section is expanded or collapsed. | 
| + if (mNumSuggestedOfflinePages > 0) { | 
| + // First item of the suggested pages section is the section header. | 
| + size += 1; | 
| + if (!isSuggestedOfflinePagesSectionExpanded()) { | 
| + size -= mNumSuggestedOfflinePages; | 
| + } | 
| + } | 
| + | 
| + return size; | 
| + } | 
| + | 
| + /** @return The total file size of the suggested pages for this date. */ | 
| + public long getSuggestedOfflinePagesFileSize() { | 
| + long size = 0; | 
| + for (TimedItem item : mItems) { | 
| + if (isSuggestedOfflinePage(item)) { | 
| + size += ((DownloadHistoryItemWrapper) item).getFileSize(); | 
| + } | 
| + } | 
| + return size; | 
| + } | 
| + | 
| + private boolean isSuggestedOfflinePagesSectionHeader(int index) { | 
| + return index == (mItems.size() - mNumSuggestedOfflinePages + 1) | 
| + && mNumSuggestedOfflinePages > 0; | 
| + } | 
| + | 
| + @Override | 
| + public TimedItem getItemAt(int index) { | 
| + // 0 is allocated to the date header. The list header has no items. | 
| + if (index == 0) return null; | 
| 
 
Theresa
2017/02/07 00:09:05
The history view is going to have a list header vi
 
shaktisahu
2017/02/07 23:35:12
Done.
 
 | 
| + | 
| + sortIfNeeded(); | 
| + | 
| + // The suggested pages start at the end of the group. | 
| + if (index <= mItems.size() - mNumSuggestedOfflinePages) { | 
| + return mItems.get(index - 1); | 
| + } else { | 
| + if (mNumSuggestedOfflinePages > 0 | 
| + && index == mItems.size() - mNumSuggestedOfflinePages + 1) { | 
| 
 
Theresa
2017/02/07 00:09:05
Could this be extracted to something like getOffli
 
shaktisahu
2017/02/07 23:35:12
Done.
 
 | 
| + return getSuggestedOfflinePagesHeader(); | 
| + } else if (isSuggestedOfflinePagesSectionExpanded()) { | 
| + return mItems.get(index - 2); | 
| + } else { | 
| + assert false; | 
| + return null; | 
| + } | 
| + } | 
| + } | 
| + | 
| + @Override | 
| + public int getItemViewType(int position) { | 
| + if (isSuggestedOfflinePagesSectionHeader(position)) { | 
| + return DateDividedAdapter.TYPE_SUBSECTION_HEADER; | 
| + } else { | 
| + return super.getItemViewType(position); | 
| + } | 
| + } | 
| + | 
| + @Override | 
| + public int compareItem(TimedItem lhs, TimedItem rhs) { | 
| + if (isSuggestedOfflinePage(lhs) && !isSuggestedOfflinePage(rhs)) return 1; | 
| + if (!isSuggestedOfflinePage(lhs) && isSuggestedOfflinePage(rhs)) return -1; | 
| + | 
| + return super.compareItem(lhs, rhs); | 
| + } | 
| + | 
| + private boolean isSuggestedOfflinePage(TimedItem timedItem) { | 
| + if (timedItem instanceof OfflinePageItemWrapper) { | 
| + return ((OfflinePageItemWrapper) timedItem).isSuggested(); | 
| + } | 
| + | 
| + return false; | 
| + } | 
| +} |