Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java

Issue 2670083002: [Download Home] Displaying offline page bundle per day (Closed)
Patch Set: nits Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.download.ui; 5 package org.chromium.chrome.browser.download.ui;
6 6
7 import android.content.ComponentName; 7 import android.content.ComponentName;
8 import android.support.v7.widget.RecyclerView.ViewHolder; 8 import android.support.v7.widget.RecyclerView.ViewHolder;
9 import android.text.TextUtils; 9 import android.text.TextUtils;
10 import android.view.LayoutInflater; 10 import android.view.LayoutInflater;
(...skipping 10 matching lines...) Expand all
21 import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.Downlo adItemWrapper; 21 import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.Downlo adItemWrapper;
22 import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.Offlin ePageItemWrapper; 22 import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.Offlin ePageItemWrapper;
23 import org.chromium.chrome.browser.download.ui.DownloadManagerUi.DownloadUiObser ver; 23 import org.chromium.chrome.browser.download.ui.DownloadManagerUi.DownloadUiObser ver;
24 import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBri dge; 24 import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBri dge;
25 import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadIte m; 25 import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadIte m;
26 import org.chromium.chrome.browser.widget.DateDividedAdapter; 26 import org.chromium.chrome.browser.widget.DateDividedAdapter;
27 import org.chromium.chrome.browser.widget.selection.SelectionDelegate; 27 import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
28 import org.chromium.content_public.browser.DownloadState; 28 import org.chromium.content_public.browser.DownloadState;
29 29
30 import java.util.ArrayList; 30 import java.util.ArrayList;
31 import java.util.Calendar;
32 import java.util.Date;
33 import java.util.HashMap;
34 import java.util.Iterator;
31 import java.util.List; 35 import java.util.List;
36 import java.util.Map;
37 import java.util.Map.Entry;
32 import java.util.Set; 38 import java.util.Set;
33 39
34 /** Bridges the user's download history and the UI used to display it. */ 40 /** Bridges the user's download history and the UI used to display it. */
35 public class DownloadHistoryAdapter extends DateDividedAdapter 41 public class DownloadHistoryAdapter extends DateDividedAdapter
36 implements DownloadUiObserver, DownloadSharedPreferenceHelper.Observer { 42 implements DownloadUiObserver, DownloadSharedPreferenceHelper.Observer {
37 43
38 /** Alerted about changes to internal state. */ 44 /** Alerted about changes to internal state. */
39 static interface TestObserver { 45 static interface TestObserver {
40 abstract void onDownloadItemCreated(DownloadItem item); 46 abstract void onDownloadItemCreated(DownloadItem item);
41 abstract void onDownloadItemUpdated(DownloadItem item); 47 abstract void onDownloadItemUpdated(DownloadItem item);
42 } 48 }
43 49
44 private class BackendItemsImpl extends BackendItems { 50 private class BackendItemsImpl extends BackendItems {
45 @Override 51 @Override
46 public DownloadHistoryItemWrapper removeItem(String guid) { 52 public DownloadHistoryItemWrapper removeItem(String guid) {
47 DownloadHistoryItemWrapper wrapper = super.removeItem(guid); 53 DownloadHistoryItemWrapper wrapper = super.removeItem(guid);
48 54
49 if (wrapper != null) { 55 if (wrapper != null) {
50 mFilePathsToItemsMap.removeItem(wrapper); 56 mFilePathsToItemsMap.removeItem(wrapper);
51 if (getSelectionDelegate().isItemSelected(wrapper)) { 57 if (getSelectionDelegate().isItemSelected(wrapper)) {
52 getSelectionDelegate().toggleSelectionForItem(wrapper); 58 getSelectionDelegate().toggleSelectionForItem(wrapper);
53 } 59 }
54 } 60 }
55 61
56 return wrapper; 62 return wrapper;
57 } 63 }
58 } 64 }
59 65
66 /** Represents the subsection header of the suggested pages for a given date . */
67 public class SubsectionHeader extends TimedItem {
68 private final Date mDate;
69 private final int mItemCount;
70 private final long mTotalFileSize;
71 private final Long mStableId;
72
73 public SubsectionHeader(Date date, int itemCount, long totalFileSize) {
74 mDate = date;
75 mItemCount = itemCount;
76 mTotalFileSize = totalFileSize;
77
78 // Generate a stable ID based on timestamp.
79 mStableId = 0xFFFFFFFF00000000L + (getTimestamp() & 0x0FFFFFFFF);
80 }
81
82 @Override
83 public long getTimestamp() {
84 return mDate.getTime();
85 }
86
87 public int getItemCount() {
88 return mItemCount;
89 }
90
91 public long getTotalFileSize() {
92 return mTotalFileSize;
93 }
94
95 @Override
96 public long getStableId() {
97 return mStableId;
98 }
99 }
100
60 /** 101 /**
61 * Tracks externally deleted items that have been removed from downloads his tory. 102 * Tracks externally deleted items that have been removed from downloads his tory.
62 * Shared across instances. 103 * Shared across instances.
63 */ 104 */
64 private static final DeletedFileTracker sDeletedFileTracker = new DeletedFil eTracker(); 105 private static final DeletedFileTracker sDeletedFileTracker = new DeletedFil eTracker();
65 106
66 private static final String EMPTY_QUERY = null; 107 private static final String EMPTY_QUERY = null;
67 108
68 private final BackendItems mRegularDownloadItems = new BackendItemsImpl(); 109 private final BackendItems mRegularDownloadItems = new BackendItemsImpl();
69 private final BackendItems mIncognitoDownloadItems = new BackendItemsImpl(); 110 private final BackendItems mIncognitoDownloadItems = new BackendItemsImpl();
70 private final BackendItems mOfflinePageItems = new BackendItemsImpl(); 111 private final BackendItems mOfflinePageItems = new BackendItemsImpl();
71 112
72 private final BackendItems mFilteredItems = new BackendItemsImpl();
73 private final FilePathsToDownloadItemsMap mFilePathsToItemsMap = 113 private final FilePathsToDownloadItemsMap mFilePathsToItemsMap =
74 new FilePathsToDownloadItemsMap(); 114 new FilePathsToDownloadItemsMap();
75 115
116 private final Map<Date, Boolean> mSubsectionExpanded = new HashMap<>();
76 private final ComponentName mParentComponent; 117 private final ComponentName mParentComponent;
77 private final boolean mShowOffTheRecord; 118 private final boolean mShowOffTheRecord;
78 private final LoadingStateDelegate mLoadingDelegate; 119 private final LoadingStateDelegate mLoadingDelegate;
79 private final ObserverList<TestObserver> mObservers = new ObserverList<>(); 120 private final ObserverList<TestObserver> mObservers = new ObserverList<>();
80 private final List<DownloadItemView> mViews = new ArrayList<>(); 121 private final List<DownloadItemView> mViews = new ArrayList<>();
81 122
82 private BackendProvider mBackendProvider; 123 private BackendProvider mBackendProvider;
83 private OfflinePageDownloadBridge.Observer mOfflinePageObserver; 124 private OfflinePageDownloadBridge.Observer mOfflinePageObserver;
84 private int mFilter = DownloadFilter.FILTER_ALL; 125 private int mFilter = DownloadFilter.FILTER_ALL;
85 private String mSearchQuery = EMPTY_QUERY; 126 private String mSearchQuery = EMPTY_QUERY;
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 totalSize += mOfflinePageItems.getTotalBytes(); 242 totalSize += mOfflinePageItems.getTotalBytes();
202 return totalSize; 243 return totalSize;
203 } 244 }
204 245
205 @Override 246 @Override
206 protected int getTimedItemViewResId() { 247 protected int getTimedItemViewResId() {
207 return R.layout.date_view; 248 return R.layout.date_view;
208 } 249 }
209 250
210 @Override 251 @Override
252 protected SubsectionHeaderViewHolder createSubsectionHeader(ViewGroup parent ) {
253 OfflineGroupHeaderView offlineHeader =
254 (OfflineGroupHeaderView) LayoutInflater.from(parent.getContext() )
255 .inflate(R.layout.offline_download_header, parent, false );
256 offlineHeader.setAdapter(this);
257 return new SubsectionHeaderViewHolder(offlineHeader);
258 }
259
260 @Override
261 protected void bindViewHolderForSubsectionHeader(
262 SubsectionHeaderViewHolder holder, TimedItem timedItem) {
263 SubsectionHeader headerItem = (SubsectionHeader) timedItem;
264 Date date = new Date(headerItem.getTimestamp());
265 OfflineGroupHeaderView headerView = (OfflineGroupHeaderView) holder.getV iew();
266 headerView.update(date, isSubsectionExpanded(date), headerItem.getItemCo unt(),
267 headerItem.getTotalFileSize());
268 }
269
270 @Override
211 public ViewHolder createViewHolder(ViewGroup parent) { 271 public ViewHolder createViewHolder(ViewGroup parent) {
212 DownloadItemView v = (DownloadItemView) LayoutInflater.from(parent.getCo ntext()).inflate( 272 DownloadItemView v = (DownloadItemView) LayoutInflater.from(parent.getCo ntext()).inflate(
213 R.layout.download_item_view, parent, false); 273 R.layout.download_item_view, parent, false);
214 v.setSelectionDelegate(getSelectionDelegate()); 274 v.setSelectionDelegate(getSelectionDelegate());
215 mViews.add(v); 275 mViews.add(v);
216 return new DownloadHistoryItemViewHolder(v); 276 return new DownloadHistoryItemViewHolder(v);
217 } 277 }
218 278
219 @Override 279 @Override
220 public void bindViewHolderForTimedItem(ViewHolder current, TimedItem timedIt em) { 280 public void bindViewHolderForTimedItem(ViewHolder current, TimedItem timedIt em) {
221 final DownloadHistoryItemWrapper item = (DownloadHistoryItemWrapper) tim edItem; 281 final DownloadHistoryItemWrapper item = (DownloadHistoryItemWrapper) tim edItem;
222 282
223 DownloadHistoryItemViewHolder holder = (DownloadHistoryItemViewHolder) c urrent; 283 DownloadHistoryItemViewHolder holder = (DownloadHistoryItemViewHolder) c urrent;
224 holder.getItemView().displayItem(mBackendProvider, item); 284 holder.getItemView().displayItem(mBackendProvider, item);
225 } 285 }
226 286
287 @Override
288 protected ItemGroup createGroup(long timeStamp) {
289 return new DownloadItemGroup(timeStamp);
290 }
291
227 /** Called when a new DownloadItem has been created by the native DownloadMa nager. */ 292 /** Called when a new DownloadItem has been created by the native DownloadMa nager. */
228 public void onDownloadItemCreated(DownloadItem item) { 293 public void onDownloadItemCreated(DownloadItem item) {
229 boolean isOffTheRecord = item.getDownloadInfo().isOffTheRecord(); 294 boolean isOffTheRecord = item.getDownloadInfo().isOffTheRecord();
230 if (isOffTheRecord && !mShowOffTheRecord) return; 295 if (isOffTheRecord && !mShowOffTheRecord) return;
231 296
232 BackendItems list = getDownloadItemList(isOffTheRecord); 297 BackendItems list = getDownloadItemList(isOffTheRecord);
233 assert list.findItemIndex(item.getId()) == BackendItems.INVALID_INDEX; 298 assert list.findItemIndex(item.getId()) == BackendItems.INVALID_INDEX;
234 299
235 DownloadItemWrapper wrapper = createDownloadItemWrapper(item); 300 DownloadItemWrapper wrapper = createDownloadItemWrapper(item);
236 boolean wasAdded = addDownloadHistoryItemWrapper(wrapper); 301 boolean wasAdded = addDownloadHistoryItemWrapper(wrapper);
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 return mBackendProvider.getOfflinePageBridge(); 450 return mBackendProvider.getOfflinePageBridge();
386 } 451 }
387 452
388 private SelectionDelegate<DownloadHistoryItemWrapper> getSelectionDelegate() { 453 private SelectionDelegate<DownloadHistoryItemWrapper> getSelectionDelegate() {
389 return mBackendProvider.getSelectionDelegate(); 454 return mBackendProvider.getSelectionDelegate();
390 } 455 }
391 456
392 /** Filters the list of downloads to show only files of a specific type. */ 457 /** Filters the list of downloads to show only files of a specific type. */
393 private void filter(int filterType) { 458 private void filter(int filterType) {
394 mFilter = filterType; 459 mFilter = filterType;
395 mFilteredItems.clear(); 460
396 mRegularDownloadItems.filter(mFilter, mSearchQuery, mFilteredItems); 461 List<TimedItem> filteredTimedItems = new ArrayList<>();
397 mIncognitoDownloadItems.filter(mFilter, mSearchQuery, mFilteredItems); 462 mRegularDownloadItems.filter(mFilter, mSearchQuery, filteredTimedItems);
398 mOfflinePageItems.filter(mFilter, mSearchQuery, mFilteredItems); 463 mIncognitoDownloadItems.filter(mFilter, mSearchQuery, filteredTimedItems );
464
gone 2017/02/21 18:32:27 nit: remove newline
shaktisahu 2017/02/21 21:17:13 Done.
465 filterOfflinePageItems(filteredTimedItems);
466
399 clear(false); 467 clear(false);
400 loadItems(mFilteredItems); 468 loadItems(filteredTimedItems);
469 }
470
471 /**
472 * Filters the offline pages based on the current filter and search text.
473 * If there are suggested pages, they are filtered based on whether or not t he subsection for
474 * that date is expanded. Also a TimedItem is added to each subsection to re present the header
475 * for the suggested pages.
476 * @param filteredTimedItems List for appending items that match the filter.
477 */
478 private void filterOfflinePageItems(List<TimedItem> filteredTimedItems) {
479 Map<Date, Integer> suggestedPageCountMap = new HashMap<>();
480 Map<Date, Long> suggestedPageTotalSizeMap = new HashMap<>();
481
482 List<TimedItem> filteredOfflinePageItems = new ArrayList<>();
483 mOfflinePageItems.filter(mFilter, mSearchQuery, filteredOfflinePageItems );
484
485 for (TimedItem item : filteredOfflinePageItems) {
486 OfflinePageItemWrapper offlineItem = (OfflinePageItemWrapper) item;
487
488 // Add the suggested pages to the adapter only if the section is exp anded for that date.
489 if (offlineItem.isSuggested()) {
490 incrementSuggestedPageCount(
491 offlineItem, suggestedPageCountMap, suggestedPageTotalSi zeMap);
492 // TODO(shaktisahu): Check with UX if we need to skip this check and the subsection
493 // headers when filtering for active search text.
494 if (!isSubsectionExpanded(getDateWithoutTime(offlineItem.getTime stamp()))) continue;
495 }
496 filteredTimedItems.add(offlineItem);
497 }
498
499 generateSubsectionHeaders(
500 filteredTimedItems, suggestedPageCountMap, suggestedPageTotalSiz eMap);
501 }
502
503 // Updates the total number of suggested pages and file size grouped by date .
504 private void incrementSuggestedPageCount(OfflinePageItemWrapper offlineItem,
505 Map<Date, Integer> pageCountMap, Map<Date, Long> fileSizeMap) {
506 Date date = getDateWithoutTime(offlineItem.getTimestamp());
507
508 int count = pageCountMap.containsKey(date) ? pageCountMap.get(date) : 0;
509 pageCountMap.put(date, count + 1);
510
511 long fileSize = fileSizeMap.containsKey(date) ? fileSizeMap.get(date) : 0;
512 fileSizeMap.put(date, fileSize + offlineItem.getFileSize());
513 }
514
515 // Creates subsection headers for each date and appends to |filteredTimedIte ms|.
516 private void generateSubsectionHeaders(List<TimedItem> filteredTimedItems,
517 Map<Date, Integer> pageCountMap, Map<Date, Long> fileSizeMap) {
518 for (Date date : pageCountMap.keySet()) {
519 filteredTimedItems.add(
520 new SubsectionHeader(date, pageCountMap.get(date), fileSizeM ap.get(date)));
521 }
522
523 // Remove entry from |mSubsectionExpanded| if there are no more suggeste d pages.
524 Iterator<Entry<Date, Boolean>> iter = mSubsectionExpanded.entrySet().ite rator();
525 while (iter.hasNext()) {
Theresa 2017/02/21 17:07:26 nit: can this be: for (Entry<Date, Booleean> entr
shaktisahu 2017/02/21 21:17:13 I can't call remove on |mSubsectionExpanded| while
526 Entry<Date, Boolean> entry = iter.next();
527 if (!pageCountMap.containsKey(entry.getKey())) {
528 iter.remove();
529 }
530 }
531 }
532
533 /**
534 * Whether the suggested pages section is expanded for a given date.
535 * @param date The download date.
536 * @return Whether the suggested pages section is expanded.
537 */
538 public boolean isSubsectionExpanded(Date date) {
539 // Default state is collpased.
540 if (mSubsectionExpanded.get(date) == null) {
541 mSubsectionExpanded.put(date, false);
542 }
543
544 return mSubsectionExpanded.get(date);
545 }
546
547 /**
548 * Sets the state of a subsection for a particular date and updates the adap ter.
549 * @param date The download date.
550 * @param expanded Whether the suggested pages should be expanded.
551 */
552 public void setSubsectionExpanded(Date date, boolean expanded) {
553 mSubsectionExpanded.put(date, expanded);
554 clear(false);
555 filter(mFilter);
556 }
557
558 @Override
559 protected boolean isSubsectionHeader(TimedItem timedItem) {
560 return timedItem instanceof SubsectionHeader;
401 } 561 }
402 562
403 private void initializeOfflinePageBridge() { 563 private void initializeOfflinePageBridge() {
404 mOfflinePageObserver = new OfflinePageDownloadBridge.Observer() { 564 mOfflinePageObserver = new OfflinePageDownloadBridge.Observer() {
405 @Override 565 @Override
406 public void onItemsLoaded() { 566 public void onItemsLoaded() {
407 onAllOfflinePagesRetrieved(getOfflinePageBridge().getAllItems()) ; 567 onAllOfflinePagesRetrieved(getOfflinePageBridge().getAllItems()) ;
408 } 568 }
409 569
410 @Override 570 @Override
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCou nt.Video", 630 RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCou nt.Video",
471 itemCounts[DownloadFilter.FILTER_VIDEO]); 631 itemCounts[DownloadFilter.FILTER_VIDEO]);
472 } 632 }
473 633
474 private void recordTotalDownloadCountHistogram() { 634 private void recordTotalDownloadCountHistogram() {
475 // The total count intentionally leaves out incognito downloads. This sh ould be revisited 635 // The total count intentionally leaves out incognito downloads. This sh ould be revisited
476 // if/when incognito downloads are persistently available in downloads h ome. 636 // if/when incognito downloads are persistently available in downloads h ome.
477 RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCou nt.Total", 637 RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCou nt.Total",
478 mRegularDownloadItems.size() + mOfflinePageItems.size()); 638 mRegularDownloadItems.size() + mOfflinePageItems.size());
479 } 639 }
640
641 /**
642 * Calculates the {@link Date} for midnight of the date represented by the t imestamp.
643 */
644 private Date getDateWithoutTime(long timestamp) {
645 Calendar cal = Calendar.getInstance();
646 cal.setTimeInMillis(timestamp);
647 cal.set(Calendar.HOUR_OF_DAY, 0);
648 cal.set(Calendar.MINUTE, 0);
649 cal.set(Calendar.SECOND, 0);
650 cal.set(Calendar.MILLISECOND, 0);
651 return cal.getTime();
652 }
480 } 653 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698