• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.media.browse;
18 
19 import androidx.annotation.Nullable;
20 import androidx.recyclerview.widget.GridLayoutManager;
21 import androidx.recyclerview.widget.RecyclerView;
22 
23 import com.android.car.media.R;
24 import com.android.car.media.common.MediaItemMetadata;
25 import com.android.car.ui.recyclerview.DelegatingContentLimitingAdapter;
26 
27 import java.util.List;
28 
29 /**
30  * Provides list limiting functionality to {@link BrowseAdapter}.
31  */
32 public class LimitedBrowseAdapter extends DelegatingContentLimitingAdapter<BrowseViewHolder> {
33 
34     private final BrowseAdapter mBrowseAdapter;
35     private final GridLayoutManager mLayoutManager;
36     private final int mMaxSpanSize;
37 
38     @Nullable private String mAnchorId;
39 
LimitedBrowseAdapter(BrowseAdapter browseAdapter, GridLayoutManager manager, BrowseAdapter.Observer browseAdapterObserver)40     public LimitedBrowseAdapter(BrowseAdapter browseAdapter, GridLayoutManager manager,
41             BrowseAdapter.Observer browseAdapterObserver) {
42         super(browseAdapter, R.id.browse_list_uxr_config);
43 
44         mBrowseAdapter = browseAdapter;
45         mLayoutManager = manager;
46         mMaxSpanSize = manager.getSpanCount();
47 
48         mLayoutManager.setSpanSizeLookup(mSpanSizeLookup);
49         mBrowseAdapter.registerObserver(browseAdapterObserver);
50         mBrowseAdapter.setOnListChangedListener(((previousList, currentList) -> {
51             updateUnderlyingDataChanged(currentList.size(), validateAnchor());
52         }));
53     }
54 
55     private final GridLayoutManager.SpanSizeLookup mSpanSizeLookup =
56             new GridLayoutManager.SpanSizeLookup() {
57                 @Override
58                 public int getSpanSize(int position) {
59                     if (getItemViewType(position) == getScrollingLimitedMessageViewType()) {
60                         return mMaxSpanSize;
61                     }
62 
63                     int itemIndex = positionToIndex(position);
64                     return mBrowseAdapter.getSpanSize(itemIndex, mMaxSpanSize);
65                 }
66             };
67 
68     /**
69      * @see BrowseAdapter#submitItems(MediaItemMetadata, List)
70      */
submitItems(@ullable MediaItemMetadata parentItem, @Nullable List<MediaItemMetadata> items)71     public void submitItems(@Nullable MediaItemMetadata parentItem,
72             @Nullable List<MediaItemMetadata> items) {
73         mBrowseAdapter.submitItems(parentItem, items);
74 
75         if (items == null) {
76             updateUnderlyingDataChanged(0, 0);
77             return;
78         }
79         // We can't take any action with the new items as they must first go through the
80         // AsyncListDiffer of ListAdapter. This is handled in the OnListChangedListener.
81     }
82 
validateAnchor()83     private int validateAnchor() {
84         if (mAnchorId == null) {
85             return 0;
86         }
87 
88         List<BrowseViewData> items = mBrowseAdapter.getCurrentList();
89         for (int i = 0; i < items.size(); i++) {
90             MediaItemMetadata mediaItem = items.get(i).mMediaItem;
91             if (mediaItem != null && mAnchorId.equals(mediaItem.getId())) {
92                 return i;
93             }
94         }
95 
96         // The anchor isn't present in the new list, reset it.
97         mAnchorId = null;
98         return 0;
99     }
100 
101 
102     @Override
computeAnchorIndexWhenRestricting()103     public int computeAnchorIndexWhenRestricting() {
104         List<BrowseViewData> items = mBrowseAdapter.getCurrentList();
105         if (items.size() <= 0) {
106             mAnchorId = null;
107             return 0;
108         }
109 
110         int anchorIndex = (getFirstVisibleItemPosition() + getLastVisibleItemPosition()) / 2;
111         if (0 <= anchorIndex && anchorIndex < items.size()) {
112             MediaItemMetadata mediaItem = items.get(anchorIndex).mMediaItem;
113             mAnchorId = mediaItem != null ? mediaItem.getId() : null;
114             return anchorIndex;
115         } else {
116             mAnchorId = null;
117             return 0;
118         }
119     }
120 
getFirstVisibleItemPosition()121     private int getFirstVisibleItemPosition() {
122         int firstItem = mLayoutManager.findFirstCompletelyVisibleItemPosition();
123         if (firstItem == RecyclerView.NO_POSITION) {
124             firstItem = mLayoutManager.findFirstVisibleItemPosition();
125         }
126         return firstItem;
127     }
128 
getLastVisibleItemPosition()129     private int getLastVisibleItemPosition() {
130         int lastItem = mLayoutManager.findLastCompletelyVisibleItemPosition();
131         if (lastItem == RecyclerView.NO_POSITION) {
132             lastItem = mLayoutManager.findLastVisibleItemPosition();
133         }
134         return lastItem;
135     }
136 }
137