summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2020-09-17 02:57:05 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-09-17 02:57:05 +0000
commit726305c4941c965aecde4f15dacc354e9d939ec2 (patch)
treec0c71c3bc8f6e93ca9fbc9ee4915bf5392bae77e
parenta92dded71d7a4e9f579586c6ae40db5512e5e4c1 (diff)
parent9a7891eaadb7c9d3e7bfc5cdaccd065e8d72a820 (diff)
downloadMedia-726305c4941c965aecde4f15dacc354e9d939ec2.tar.gz
Merge changes from topic "2020-09-14-spans" into rvc-qpr-dev
* changes: Fix span computation Integrate the list limit updates
-rw-r--r--src/com/android/car/media/BrowseViewController.java44
-rw-r--r--src/com/android/car/media/browse/BrowseAdapter.java29
-rw-r--r--src/com/android/car/media/browse/BrowseViewHolder.java2
-rw-r--r--src/com/android/car/media/browse/LimitedBrowseAdapter.java140
4 files changed, 180 insertions, 35 deletions
diff --git a/src/com/android/car/media/BrowseViewController.java b/src/com/android/car/media/BrowseViewController.java
index 5f7be28..cd67f71 100644
--- a/src/com/android/car/media/BrowseViewController.java
+++ b/src/com/android/car/media/BrowseViewController.java
@@ -20,7 +20,6 @@ import static com.android.car.arch.common.LiveDataFunctions.ifThenElse;
import android.car.content.pm.CarPackageManager;
import android.content.Context;
-import android.content.res.Resources;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
@@ -41,6 +40,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.car.apps.common.util.ViewUtils;
import com.android.car.arch.common.FutureData;
import com.android.car.media.browse.BrowseAdapter;
+import com.android.car.media.browse.LimitedBrowseAdapter;
import com.android.car.media.common.GridSpacingItemDecoration;
import com.android.car.media.common.MediaItemMetadata;
import com.android.car.media.common.browse.BrowsedMediaItems;
@@ -48,7 +48,6 @@ import com.android.car.media.common.browse.MediaBrowserViewModel;
import com.android.car.media.common.source.MediaSource;
import com.android.car.media.widgets.AppBarController;
import com.android.car.ui.FocusArea;
-import com.android.car.ui.recyclerview.DelegatingContentLimitingAdapter;
import com.android.car.ui.baselayout.Insets;
import com.android.car.ui.toolbar.Toolbar;
import com.android.car.uxr.LifeCycleObserverUxrContentLimiter;
@@ -58,8 +57,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Stack;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
/**
* A view controller that implements the content forward browsing experience.
@@ -81,9 +78,7 @@ public class BrowseViewController extends ViewControllerBase {
private final RecyclerView mBrowseList;
private final ImageView mErrorIcon;
private final TextView mMessage;
- private final DelegatingContentLimitingAdapter mLimitedBrowseAdapter;
- private final BrowseAdapter mBrowseAdapter;
- private int mMaxSpanSize = 1;
+ private final LimitedBrowseAdapter mLimitedBrowseAdapter;
private String mSearchQuery;
private final int mFadeDuration;
private final int mLoadingIndicatorDelay;
@@ -240,7 +235,7 @@ public class BrowseViewController extends ViewControllerBase {
updateTabs((mediaSource != null) ? null : new ArrayList<>());
}
- mBrowseAdapter.submitItems(null, null);
+ mLimitedBrowseAdapter.submitItems(null, null);
stopLoadingIndicator();
ViewUtils.hideViewAnimated(mErrorIcon, mFadeDuration);
ViewUtils.hideViewAnimated(mMessage, mFadeDuration);
@@ -294,16 +289,10 @@ public class BrowseViewController extends ViewControllerBase {
mBrowseList.addItemDecoration(new GridSpacingItemDecoration(
activity.getResources().getDimensionPixelSize(R.dimen.grid_item_spacing)));
- mBrowseAdapter = new BrowseAdapter(mBrowseList.getContext());
- mBrowseAdapter.registerObserver(mBrowseAdapterObserver);
- mLimitedBrowseAdapter = new DelegatingContentLimitingAdapter(mBrowseAdapter,
- R.id.browse_list_uxr_config);
- mBrowseList.setAdapter(mLimitedBrowseAdapter);
-
GridLayoutManager manager = (GridLayoutManager) mBrowseList.getLayoutManager();
- mMaxSpanSize = manager.getSpanCount();
- manager.setSpanSizeLookup(mSpanSizeLookup);
-
+ mLimitedBrowseAdapter = new LimitedBrowseAdapter(
+ new BrowseAdapter(mBrowseList.getContext()), manager, mBrowseAdapterObserver);
+ mBrowseList.setAdapter(mLimitedBrowseAdapter);
mUxrContentLimiter = new LifeCycleObserverUxrContentLimiter(
new UxrContentLimiterImpl(activity, R.xml.uxr_config));
@@ -311,9 +300,9 @@ public class BrowseViewController extends ViewControllerBase {
activity.getLifecycle().addObserver(mUxrContentLimiter);
mMediaBrowserViewModel.rootBrowsableHint().observe(activity,
- mBrowseAdapter::setRootBrowsableViewType);
+ hint -> mLimitedBrowseAdapter.getBrowseAdapter().setRootBrowsableViewType(hint));
mMediaBrowserViewModel.rootPlayableHint().observe(activity,
- mBrowseAdapter::setRootPlayableViewType);
+ hint -> mLimitedBrowseAdapter.getBrowseAdapter().setRootPlayableViewType(hint));
LiveData<FutureData<List<MediaItemMetadata>>> mediaItems = ifThenElse(mShowSearchResults,
mMediaBrowserViewModel.getSearchedMediaItems(),
mMediaBrowserViewModel.getBrowsedMediaItems());
@@ -359,19 +348,6 @@ public class BrowseViewController extends ViewControllerBase {
}
};
- private final GridLayoutManager.SpanSizeLookup mSpanSizeLookup =
- new GridLayoutManager.SpanSizeLookup() {
- @Override
- public int getSpanSize(int position) {
- if (mLimitedBrowseAdapter.getItemViewType(position) ==
- mLimitedBrowseAdapter.getScrollingLimitedMessageViewType()) {
- return mMaxSpanSize;
- }
-
- return mBrowseAdapter.getSpanSize(position, mMaxSpanSize);
- }
- };
-
boolean onBackPressed() {
boolean success = navigateBack();
if (!success && (mIsSearchController)) {
@@ -579,7 +555,7 @@ public class BrowseViewController extends ViewControllerBase {
ViewUtils.hideViewAnimated(mMessage, 0);
// TODO(b/139759881) build a jank-free animation of the transition.
mBrowseList.setAlpha(0f);
- mBrowseAdapter.submitItems(null, null);
+ mLimitedBrowseAdapter.submitItems(null, null);
if (forRoot) {
if (Log.isLoggable(TAG, Log.INFO)) {
@@ -605,7 +581,7 @@ public class BrowseViewController extends ViewControllerBase {
mCallbacks.onRootLoaded();
updateTabs(items != null ? items : new ArrayList<>());
} else {
- mBrowseAdapter.submitItems(getCurrentMediaItem(), items);
+ mLimitedBrowseAdapter.submitItems(getCurrentMediaItem(), items);
}
int duration = forRoot ? 0 : mFadeDuration;
diff --git a/src/com/android/car/media/browse/BrowseAdapter.java b/src/com/android/car/media/browse/BrowseAdapter.java
index 1d8ccb6..abf770d 100644
--- a/src/com/android/car/media/browse/BrowseAdapter.java
+++ b/src/com/android/car/media/browse/BrowseAdapter.java
@@ -51,6 +51,17 @@ import java.util.function.Consumer;
*/
public class BrowseAdapter extends ListAdapter<BrowseViewData, BrowseViewHolder> {
private static final String TAG = "BrowseAdapter";
+
+ /**
+ * Listens to the list data changes.
+ */
+ public interface OnListChangedListener {
+ /**
+ * Called when {@link #onCurrentListChanged(List, List)} is called.
+ */
+ void onListChanged(List<BrowseViewData> previousList, List<BrowseViewData> currentList);
+ }
+
@NonNull
private final Context mContext;
@NonNull
@@ -63,6 +74,8 @@ public class BrowseAdapter extends ListAdapter<BrowseViewData, BrowseViewHolder>
private BrowseItemViewType mRootBrowsableViewType = BrowseItemViewType.LIST_ITEM;
private BrowseItemViewType mRootPlayableViewType = BrowseItemViewType.LIST_ITEM;
+ private OnListChangedListener mOnListChangedListener;
+
private static final DiffUtil.ItemCallback<BrowseViewData> DIFF_CALLBACK =
new DiffUtil.ItemCallback<BrowseViewData>() {
@Override
@@ -145,6 +158,13 @@ public class BrowseAdapter extends ListAdapter<BrowseViewData, BrowseViewHolder>
return viewType.getSpanSize(maxSpanSize);
}
+ /**
+ * Sets a listener to listen for the list data changes.
+ */
+ public void setOnListChangedListener(OnListChangedListener onListChangedListener) {
+ mOnListChangedListener = onListChangedListener;
+ }
+
@NonNull
@Override
public BrowseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@@ -176,6 +196,15 @@ public class BrowseAdapter extends ListAdapter<BrowseViewData, BrowseViewHolder>
return getItem(position).mViewType.ordinal();
}
+ @Override
+ public void onCurrentListChanged(@NonNull List<BrowseViewData> previousList,
+ @NonNull List<BrowseViewData> currentList) {
+ super.onCurrentListChanged(previousList, currentList);
+ if (mOnListChangedListener != null) {
+ mOnListChangedListener.onListChanged(previousList, currentList);
+ }
+ }
+
public void submitItems(@Nullable MediaItemMetadata parentItem,
@Nullable List<MediaItemMetadata> children) {
mParentMediaItem = parentItem;
diff --git a/src/com/android/car/media/browse/BrowseViewHolder.java b/src/com/android/car/media/browse/BrowseViewHolder.java
index aa4449f..d30166e 100644
--- a/src/com/android/car/media/browse/BrowseViewHolder.java
+++ b/src/com/android/car/media/browse/BrowseViewHolder.java
@@ -34,7 +34,7 @@ import com.android.car.media.common.MediaItemMetadata;
/**
* Generic {@link RecyclerView.ViewHolder} to use for all views in the {@link BrowseAdapter}
*/
-class BrowseViewHolder extends RecyclerView.ViewHolder {
+public class BrowseViewHolder extends RecyclerView.ViewHolder {
private final TextView mTitle;
private final TextView mSubtitle;
private final ImageView mAlbumArt;
diff --git a/src/com/android/car/media/browse/LimitedBrowseAdapter.java b/src/com/android/car/media/browse/LimitedBrowseAdapter.java
new file mode 100644
index 0000000..bbca980
--- /dev/null
+++ b/src/com/android/car/media/browse/LimitedBrowseAdapter.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.media.browse;
+
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.car.media.R;
+import com.android.car.media.common.MediaItemMetadata;
+import com.android.car.ui.recyclerview.DelegatingContentLimitingAdapter;
+
+import java.util.List;
+
+/**
+ * Provides list limiting functionality to {@link BrowseAdapter}.
+ */
+public class LimitedBrowseAdapter extends DelegatingContentLimitingAdapter<BrowseViewHolder> {
+
+ private final BrowseAdapter mBrowseAdapter;
+ private final GridLayoutManager mLayoutManager;
+ private final int mMaxSpanSize;
+
+ @Nullable private String mAnchorId;
+
+ public LimitedBrowseAdapter(BrowseAdapter browseAdapter, GridLayoutManager manager,
+ BrowseAdapter.Observer browseAdapterObserver) {
+ super(browseAdapter, R.id.browse_list_uxr_config);
+
+ mBrowseAdapter = browseAdapter;
+ mLayoutManager = manager;
+ mMaxSpanSize = manager.getSpanCount();
+
+ mLayoutManager.setSpanSizeLookup(mSpanSizeLookup);
+ mBrowseAdapter.registerObserver(browseAdapterObserver);
+ mBrowseAdapter.setOnListChangedListener(((previousList, currentList) -> {
+ updateUnderlyingDataChanged(currentList.size(), validateAnchor());
+ }));
+ }
+
+ private final GridLayoutManager.SpanSizeLookup mSpanSizeLookup =
+ new GridLayoutManager.SpanSizeLookup() {
+ @Override
+ public int getSpanSize(int position) {
+ if (getItemViewType(position) == getScrollingLimitedMessageViewType()) {
+ return mMaxSpanSize;
+ }
+
+ int itemIndex = positionToIndex(position);
+ return mBrowseAdapter.getSpanSize(itemIndex, mMaxSpanSize);
+ }
+ };
+
+ public BrowseAdapter getBrowseAdapter() {
+ return mBrowseAdapter;
+ }
+
+ /**
+ * @see BrowseAdapter#submitItems(MediaItemMetadata, List)
+ */
+ public void submitItems(@Nullable MediaItemMetadata parentItem,
+ @Nullable List<MediaItemMetadata> items) {
+ mBrowseAdapter.submitItems(parentItem, items);
+
+ if (items == null) {
+ updateUnderlyingDataChanged(0, 0);
+ return;
+ }
+ // We can't take any action with the new items as they must first go through the
+ // AsyncListDiffer of ListAdapter. This is handled in the OnListChangedListener.
+ }
+
+ private int validateAnchor() {
+ if (mAnchorId == null) {
+ return 0;
+ }
+
+ List<BrowseViewData> items = mBrowseAdapter.getCurrentList();
+ for (int i = 0; i < items.size(); i++) {
+ MediaItemMetadata mediaItem = items.get(i).mMediaItem;
+ if (mediaItem != null && mAnchorId.equals(mediaItem.getId())) {
+ return i;
+ }
+ }
+
+ // The anchor isn't present in the new list, reset it.
+ mAnchorId = null;
+ return 0;
+ }
+
+
+ @Override
+ public int computeAnchorIndexWhenRestricting() {
+ List<BrowseViewData> items = mBrowseAdapter.getCurrentList();
+ if (items.size() <= 0) {
+ mAnchorId = null;
+ return 0;
+ }
+
+ int anchorIndex = (getFirstVisibleItemPosition() + getLastVisibleItemPosition()) / 2;
+ if (0 <= anchorIndex && anchorIndex < items.size()) {
+ MediaItemMetadata mediaItem = items.get(anchorIndex).mMediaItem;
+ mAnchorId = mediaItem != null ? mediaItem.getId() : null;
+ return anchorIndex;
+ } else {
+ mAnchorId = null;
+ return 0;
+ }
+ }
+
+ private int getFirstVisibleItemPosition() {
+ int firstItem = mLayoutManager.findFirstCompletelyVisibleItemPosition();
+ if (firstItem == RecyclerView.NO_POSITION) {
+ firstItem = mLayoutManager.findFirstVisibleItemPosition();
+ }
+ return firstItem;
+ }
+
+ private int getLastVisibleItemPosition() {
+ int lastItem = mLayoutManager.findLastCompletelyVisibleItemPosition();
+ if (lastItem == RecyclerView.NO_POSITION) {
+ lastItem = mLayoutManager.findLastVisibleItemPosition();
+ }
+ return lastItem;
+ }
+}