From df527c7dea94e431ee9e51412107ef20d6a4f06a Mon Sep 17 00:00:00 2001 From: Arnaud Berry Date: Wed, 17 Jan 2024 17:18:40 -0800 Subject: Remove packageName and view size extras (rejected api) See aosp/2913726 Bug: 306257301 Test: TestMediaApp Change-Id: I1794cae2909116d59ab7fb810394ad51c569c931 --- src/com/android/car/media/BrowseViewController.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/com/android/car/media/BrowseViewController.java b/src/com/android/car/media/BrowseViewController.java index 75bf306..2e517e9 100644 --- a/src/com/android/car/media/BrowseViewController.java +++ b/src/com/android/car/media/BrowseViewController.java @@ -30,14 +30,11 @@ import static com.android.car.media.browse.BrowseItemViewType.ICON_GRID_ITEM; import static com.android.car.media.browse.BrowseItemViewType.ICON_LIST_ITEM; import static com.android.car.media.browse.BrowseItemViewType.LIST_ITEM; import static com.android.car.media.common.MediaConstants.BROWSE_CUSTOM_ACTIONS_MEDIA_ITEM_ID; -import static com.android.car.media.common.MediaConstants.KEY_HINT_HOST_PACKAGE_NAME; -import static com.android.car.media.common.MediaConstants.KEY_HINT_VIEW_HEIGHT_PIXELS; import static com.android.car.media.common.MediaConstants.KEY_HINT_VIEW_MAX_CATEGORY_GRID_ITEMS_COUNT_PER_ROW; import static com.android.car.media.common.MediaConstants.KEY_HINT_VIEW_MAX_CATEGORY_LIST_ITEMS_COUNT_PER_ROW; import static com.android.car.media.common.MediaConstants.KEY_HINT_VIEW_MAX_GRID_ITEMS_COUNT_PER_ROW; import static com.android.car.media.common.MediaConstants.KEY_HINT_VIEW_MAX_ITEMS_WHILE_RESTRICTED; import static com.android.car.media.common.MediaConstants.KEY_HINT_VIEW_MAX_LIST_ITEMS_COUNT_PER_ROW; -import static com.android.car.media.common.MediaConstants.KEY_HINT_VIEW_WIDTH_PIXELS; import static com.android.car.ui.recyclerview.CarUiRecyclerView.SCROLL_STATE_DRAGGING; import android.app.AlertDialog; @@ -354,9 +351,6 @@ public class BrowseViewController { private static Bundle createItemSubscriptionOptions(View myView, CarUiRecyclerView browseList) { Context ctx = myView.getContext(); Bundle options = new Bundle(); - options.putString(KEY_HINT_HOST_PACKAGE_NAME, ctx.getPackageName()); - options.putInt(KEY_HINT_VIEW_WIDTH_PIXELS, myView.getWidth()); - options.putInt(KEY_HINT_VIEW_HEIGHT_PIXELS, myView.getHeight()); options.putInt(KEY_HINT_VIEW_MAX_ITEMS_WHILE_RESTRICTED, getMaxItemsWhileDriving(ctx)); CarUiLayoutStyle style = browseList.getLayoutStyle(); -- cgit v1.2.3 From 88e1003d50fe61b4dde2831b3c9129778add5bcf Mon Sep 17 00:00:00 2001 From: Eric Chiang Date: Wed, 24 Jan 2024 15:59:07 -0800 Subject: Update tests to use new MediaSource apis Updated robolectric libraries to fix targetSDK > maxSDK error. Fixed some background thread errors when running with soong. Bug: 310687870 Test: Manual, debug gradle tests, and atest CarMediaAppTests Change-Id: Ia578a71a0af8ab1ce114bc7673387873986a83c3 --- build.gradle | 2 +- .../car/media/service/MediaConnectorService.java | 24 +-- .../car/media/MediaConnectorServiceTests.java | 154 ------------------- .../media/service/MediaConnectorServiceTests.java | 163 +++++++++++++++++++++ 4 files changed, 179 insertions(+), 164 deletions(-) delete mode 100644 tests/unittests/src/com/android/car/media/MediaConnectorServiceTests.java create mode 100644 tests/unittests/src/com/android/car/media/service/MediaConnectorServiceTests.java diff --git a/build.gradle b/build.gradle index 740798b..141cd7a 100644 --- a/build.gradle +++ b/build.gradle @@ -138,7 +138,7 @@ dependencies { testImplementation 'com.google.truth:truth:1.1.3' testImplementation 'androidx.test.ext:junit:1.1.3' testImplementation 'junit:junit:4.12' - testImplementation 'org.robolectric:robolectric:4.10.3' + testImplementation 'org.robolectric:robolectric:4.11.1' testImplementation "org.mockito:mockito-core:2.19.0" testImplementation 'androidx.test:runner:1.4.0' testImplementation 'androidx.test:rules:1.4.0' diff --git a/src/com/android/car/media/service/MediaConnectorService.java b/src/com/android/car/media/service/MediaConnectorService.java index c13ae3c..da8c581 100644 --- a/src/com/android/car/media/service/MediaConnectorService.java +++ b/src/com/android/car/media/service/MediaConnectorService.java @@ -209,6 +209,21 @@ public class MediaConnectorService extends LifecycleService { public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); + prepareToStartService(intent, startId); + + // Since this service is started from CarMediaService (which runs in background), we need + // to call startForeground to prevent the system from stopping this service and ANRing. + Notification notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) + .setSmallIcon(R.drawable.ic_music) + .setContentTitle(getResources().getString(R.string.service_notification_title)) + .build(); + startForeground(FOREGROUND_NOTIFICATION_ID, notification); + return START_NOT_STICKY; + } + + /** Setup to perform before the service is started. */ + @VisibleForTesting + void prepareToStartService(Intent intent, int startId) { boolean autoPlay = intent.getBooleanExtra(EXTRA_AUTOPLAY, false); ComponentName mediaComp = getMediaComponentFromIntent(intent); @@ -222,15 +237,6 @@ public class MediaConnectorService extends LifecycleService { // must take precedence, so just create and assign a new TaskInfo. mCurrentTask = new TaskInfo(startId, mediaComp, autoPlay); mPlaybackStateListener.onChanged(mPlaybackLiveData.getValue()); - - // Since this service is started from CarMediaService (which runs in background), we need - // to call startForeground to prevent the system from stopping this service and ANRing. - Notification notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) - .setSmallIcon(R.drawable.ic_music) - .setContentTitle(getResources().getString(R.string.service_notification_title)) - .build(); - startForeground(FOREGROUND_NOTIFICATION_ID, notification); - return START_NOT_STICKY; } private void stopTask() { diff --git a/tests/unittests/src/com/android/car/media/MediaConnectorServiceTests.java b/tests/unittests/src/com/android/car/media/MediaConnectorServiceTests.java deleted file mode 100644 index 81b0844..0000000 --- a/tests/unittests/src/com/android/car/media/MediaConnectorServiceTests.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2023 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; - -import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY; -import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE; - -import static com.android.car.apps.common.util.LiveDataFunctions.dataOf; - -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.car.media.CarMediaIntents; -import android.content.ComponentName; -import android.content.Intent; -import android.graphics.Path; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.support.v4.media.MediaMetadataCompat; -import android.support.v4.media.session.MediaControllerCompat; -import android.support.v4.media.session.PlaybackStateCompat; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.lifecycle.MutableLiveData; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.platform.app.InstrumentationRegistry; - -import com.android.car.apps.common.IconCropper; -import com.android.car.media.common.playback.PlaybackViewModel.PlaybackStateWrapper; -import com.android.car.media.common.source.MediaSource; -import com.android.car.media.service.MediaConnectorService; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; - - -@RunWith(AndroidJUnit4.class) -public class MediaConnectorServiceTests extends BaseMockitoTest { - - private static final String EXTRA_AUTOPLAY = "com.android.car.media.autoplay"; - - private static final ComponentName COMP_1_1 = new ComponentName("package1", "class1"); - private static final ComponentName COMP_1_2 = new ComponentName("package1", "class2"); - - private MutableLiveData mPlaybackLiveData; - private MediaConnectorService mService; - - @Mock private MediaControllerCompat mMediaController; - @Mock private MediaMetadataCompat mMetadata; - @Mock private PlaybackStateCompat mState; - @Mock MediaControllerCompat.TransportControls mControls; - - @Before - public void setup() { - mPlaybackLiveData = dataOf(null); - mService = new MediaConnectorService(mPlaybackLiveData); - mService.attachBaseContext(InstrumentationRegistry.getInstrumentation().getTargetContext()); - mService.onCreate(); - mService.onBind(new Intent()); - - when(mMediaController.getTransportControls()).thenReturn(mControls); - } - - public static MediaSource newFakeMediaSource(@NonNull ComponentName browseService) { - String displayName = browseService.getClassName(); - Drawable icon = new ColorDrawable(); - IconCropper iconCropper = new IconCropper(new Path()); - return new MediaSource(browseService, displayName, icon, iconCropper); - } - - private void sendCommand(@Nullable ComponentName source, boolean autoPlay) { - Intent intent = new Intent(); - intent.putExtra(EXTRA_AUTOPLAY, autoPlay); - if (source != null) { - intent.putExtra(CarMediaIntents.EXTRA_MEDIA_COMPONENT, source.flattenToString()); - } - mService.onStartCommand(intent, 0, 0); - } - - private PlaybackStateWrapper newState(ComponentName comp) { - MediaSource source = newFakeMediaSource(comp); - return new PlaybackStateWrapper(source, mMediaController, mMetadata, mState); - } - - @Test - public void prepareAndPlaySequence() { - when(mState.getActions()).thenReturn(0L, ACTION_PREPARE, ACTION_PLAY); - sendCommand(COMP_1_1, true); - - PlaybackStateWrapper state = newState(COMP_1_1); - - mPlaybackLiveData.setValue(state); - verify(mControls, times(0)).prepare(); - verify(mControls, times(0)).play(); - - mPlaybackLiveData.setValue(state); - verify(mControls, times(1)).prepare(); - verify(mControls, times(0)).play(); - - mPlaybackLiveData.setValue(state); - verify(mControls, times(1)).prepare(); - verify(mControls, times(1)).play(); - } - - @Test - public void onlyPrepareWhenPlayNotEnabled() { - when(mState.getActions()).thenReturn(ACTION_PREPARE); - sendCommand(COMP_1_1, true); - mPlaybackLiveData.setValue(newState(COMP_1_1)); - verify(mControls, times(1)).prepare(); - verify(mControls, times(0)).play(); - } - - @Test - public void onlyPrepareWhenPlayNotRequested() { - when(mState.getActions()).thenReturn(ACTION_PREPARE | ACTION_PLAY); - sendCommand(COMP_1_1, false); - mPlaybackLiveData.setValue(newState(COMP_1_1)); - verify(mControls, times(1)).prepare(); - verify(mControls, times(0)).play(); - } - - @Test - public void waitForMatchingSource() { - when(mState.getActions()).thenReturn(ACTION_PREPARE | ACTION_PLAY); - sendCommand(COMP_1_2, true); - - mPlaybackLiveData.setValue(newState(COMP_1_1)); - verify(mControls, times(0)).prepare(); - verify(mControls, times(0)).play(); - - mPlaybackLiveData.setValue(newState(COMP_1_2)); - verify(mControls, times(1)).prepare(); - verify(mControls, times(1)).play(); - } -} diff --git a/tests/unittests/src/com/android/car/media/service/MediaConnectorServiceTests.java b/tests/unittests/src/com/android/car/media/service/MediaConnectorServiceTests.java new file mode 100644 index 0000000..bf275fd --- /dev/null +++ b/tests/unittests/src/com/android/car/media/service/MediaConnectorServiceTests.java @@ -0,0 +1,163 @@ +/* + * Copyright 2023 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.service; + +import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY; +import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE; + +import static com.android.car.apps.common.util.LiveDataFunctions.dataOf; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.car.media.CarMediaIntents; +import android.content.ComponentName; +import android.content.Intent; +import android.graphics.Path; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.support.v4.media.MediaMetadataCompat; +import android.support.v4.media.session.MediaControllerCompat; +import android.support.v4.media.session.PlaybackStateCompat; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.MutableLiveData; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.car.apps.common.IconCropper; +import com.android.car.media.BaseMockitoTest; +import com.android.car.media.common.playback.PlaybackViewModel.PlaybackStateWrapper; +import com.android.car.media.common.source.MediaSource; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + + +@RunWith(AndroidJUnit4.class) +public class MediaConnectorServiceTests extends BaseMockitoTest { + + private static final String EXTRA_AUTOPLAY = "com.android.car.media.autoplay"; + + private static final ComponentName COMP_1_1 = new ComponentName("package1", "class1"); + private static final ComponentName COMP_1_2 = new ComponentName("package1", "class2"); + + private MutableLiveData mPlaybackLiveData; + private MediaConnectorService mService; + + @Mock private MediaControllerCompat mMediaController; + @Mock private MediaMetadataCompat mMetadata; + @Mock private PlaybackStateCompat mState; + @Mock MediaControllerCompat.TransportControls mControls; + + @UiThreadTest + @Before + public void setup() { + mPlaybackLiveData = dataOf(null); + mService = new MediaConnectorService(mPlaybackLiveData); + mService.attachBaseContext(InstrumentationRegistry.getInstrumentation().getTargetContext()); + mService.onCreate(); + mService.onBind(new Intent()); + + when(mMediaController.getTransportControls()).thenReturn(mControls); + } + + public static MediaSource newFakeMediaSource(@NonNull ComponentName browseService) { + String displayName = browseService.getClassName(); + Drawable icon = new ColorDrawable(); + IconCropper iconCropper = new IconCropper(new Path()); + return new MediaSource(browseService, null, displayName, icon, iconCropper); + } + + private void sendCommand(@Nullable ComponentName source, boolean autoPlay) { + Intent intent = new Intent(); + intent.putExtra(EXTRA_AUTOPLAY, autoPlay); + if (source != null) { + intent.putExtra(CarMediaIntents.EXTRA_MEDIA_COMPONENT, source.flattenToString()); + } + mService.prepareToStartService(intent, /* startId= */ 0); + } + + private PlaybackStateWrapper newState(ComponentName comp) { + MediaSource source = newFakeMediaSource(comp); + return new PlaybackStateWrapper(source, mMediaController, mMetadata, mState); + } + + @Test + public void prepareAndPlaySequence() { + when(mState.getActions()).thenReturn(0L, ACTION_PREPARE, ACTION_PLAY); + sendCommand(COMP_1_1, true); + + PlaybackStateWrapper state = newState(COMP_1_1); + + mPlaybackLiveData.postValue(state); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + verify(mControls, times(0)).prepare(); + verify(mControls, times(0)).play(); + + mPlaybackLiveData.postValue(state); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + verify(mControls, times(1)).prepare(); + verify(mControls, times(0)).play(); + + mPlaybackLiveData.postValue(state); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + verify(mControls, times(1)).prepare(); + verify(mControls, times(1)).play(); + } + + @Test + public void onlyPrepareWhenPlayNotEnabled() { + when(mState.getActions()).thenReturn(ACTION_PREPARE); + sendCommand(COMP_1_1, true); + mPlaybackLiveData.postValue(newState(COMP_1_1)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + verify(mControls, times(1)).prepare(); + verify(mControls, times(0)).play(); + } + + @Test + public void onlyPrepareWhenPlayNotRequested() { + when(mState.getActions()).thenReturn(ACTION_PREPARE | ACTION_PLAY); + sendCommand(COMP_1_1, false); + mPlaybackLiveData.postValue(newState(COMP_1_1)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + verify(mControls, times(1)).prepare(); + verify(mControls, times(0)).play(); + } + + @Test + public void waitForMatchingSource() { + when(mState.getActions()).thenReturn(ACTION_PREPARE | ACTION_PLAY); + sendCommand(COMP_1_2, true); + + mPlaybackLiveData.postValue(newState(COMP_1_1)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + verify(mControls, times(0)).prepare(); + verify(mControls, times(0)).play(); + + mPlaybackLiveData.postValue(newState(COMP_1_2)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + verify(mControls, times(1)).prepare(); + verify(mControls, times(1)).play(); + } +} -- cgit v1.2.3 From 0f6049fb4cb36c37a726144167435945a74e3d7e Mon Sep 17 00:00:00 2001 From: Roma Modi Date: Wed, 31 Jan 2024 11:43:02 -0800 Subject: MediaActivity ViewModel should use MediaWidgetViewModel The NowPlayingController will eventually extend a base Controller called MediaWidgetController. This Controller requires a MediaWidgetViewModel that tracks state as a parameter. Bug: 323211453 Test: Manual Change-Id: I5ec6f6952bb3170e8b3f64d818d47479a182df90 --- src/com/android/car/media/MediaActivity.java | 51 ++++++++-------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/src/com/android/car/media/MediaActivity.java b/src/com/android/car/media/MediaActivity.java index 7076daa..76524bf 100644 --- a/src/com/android/car/media/MediaActivity.java +++ b/src/com/android/car/media/MediaActivity.java @@ -64,7 +64,6 @@ import androidx.annotation.Nullable; import androidx.annotation.OptIn; import androidx.core.view.GestureDetectorCompat; import androidx.fragment.app.FragmentActivity; -import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModelProvider; @@ -83,11 +82,10 @@ import com.android.car.media.common.playback.PlaybackViewModel; import com.android.car.media.common.source.MediaModels; import com.android.car.media.common.source.MediaSource; import com.android.car.media.common.source.MediaSourceViewModel; +import com.android.car.media.common.ui.MediaWidgetViewModel; import com.android.car.ui.AlertDialogBuilder; import com.android.car.ui.utils.CarUxRestrictionsUtil; -import java.util.HashMap; -import java.util.Map; import java.util.Objects; /** @@ -772,21 +770,18 @@ public class MediaActivity extends FragmentActivity implements MediaActivityCont return new ViewModelProvider(this).get(MediaActivity.ViewModel.class); } - public static class ViewModel extends AndroidViewModel { + /** State tracking ViewModel for the MediaActivity */ + public static class ViewModel extends MediaWidgetViewModel { - static class MediaServiceState { - Mode mMode = Mode.BROWSING; - BrowseStack mBrowseStack = new BrowseStack(); - String mSearchQuery; - boolean mQueueVisible = false; - boolean mHasPlayableItem = false; - } + private Mode mMode = Mode.BROWSING; + private BrowseStack mBrowseStack = new BrowseStack(); + private String mSearchQuery; + private boolean mHasPlayableItem = false; private boolean mNeedsInitialization = true; private MediaModels[] mModels; private final MutableLiveData> mBrowsedMediaSource = dataOf(FutureData.newLoadingData()); - private final Map mStates = new HashMap<>(); private final MutableLiveData mIsMiniControlsVisible = new MutableLiveData<>(); public ViewModel(@NonNull Application application) { @@ -836,30 +831,12 @@ public class MediaActivity extends FragmentActivity implements MediaActivityCont .getValue(); } - MediaServiceState getSavedState() { - MediaSource source = getMediaSourceValue(); - MediaServiceState state = mStates.get(source); - if (state == null) { - state = new MediaServiceState(); - mStates.put(source, state); - } - return state; - } - void saveMode(Mode mode) { - getSavedState().mMode = mode; + mMode = mode; } Mode getSavedMode() { - return getSavedState().mMode; - } - - void setQueueVisible(boolean visible) { - getSavedState().mQueueVisible = visible; - } - - boolean getQueueVisible() { - return getSavedState().mQueueVisible; + return mMode; } void saveBrowsedMediaSource(MediaSource mediaSource) { @@ -880,23 +857,23 @@ public class MediaActivity extends FragmentActivity implements MediaActivityCont } @NonNull BrowseStack getBrowseStack() { - return getSavedState().mBrowseStack; + return mBrowseStack; } String getSearchQuery() { - return getSavedState().mSearchQuery; + return mSearchQuery; } void setSearchQuery(String searchQuery) { - getSavedState().mSearchQuery = searchQuery; + mSearchQuery = searchQuery; } void setHasPlayableItem(boolean hasPlayableItem) { - getSavedState().mHasPlayableItem = hasPlayableItem; + mHasPlayableItem = hasPlayableItem; } boolean hasPlayableItem() { - return getSavedState().mHasPlayableItem; + return mHasPlayableItem; } } -- cgit v1.2.3 From 603b8ba3af74167c646a867fddce1896fd44db9a Mon Sep 17 00:00:00 2001 From: Mark Stanford Date: Thu, 29 Feb 2024 20:37:41 +0000 Subject: Check for null container in BrowseViewHolder Test: manual; TestMediaApp Bug: 327259719 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ab5f16d755b50a43c819106e5cab46af42f9ae11) Merged-In: I6a809ab0c1da6d74ae8ecb29ddecae6a0f10d231 Change-Id: I6a809ab0c1da6d74ae8ecb29ddecae6a0f10d231 --- src/com/android/car/media/browse/BrowseViewHolder.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/com/android/car/media/browse/BrowseViewHolder.java b/src/com/android/car/media/browse/BrowseViewHolder.java index 9df2e58..1247258 100644 --- a/src/com/android/car/media/browse/BrowseViewHolder.java +++ b/src/com/android/car/media/browse/BrowseViewHolder.java @@ -18,6 +18,7 @@ package com.android.car.media.browse; import android.content.Context; import android.text.TextUtils; +import android.util.Log; import android.util.Size; import android.view.LayoutInflater; import android.view.View; @@ -44,6 +45,9 @@ import java.util.stream.Collectors; * Generic {@link RecyclerView.ViewHolder} to use for all views in the {@link BrowseAdapter} */ public class BrowseViewHolder extends RecyclerView.ViewHolder { + + public static final String TAG = "BrowseViewHolder"; + private final TextView mTitle; private final TextView mSubtitle; private final ImageView mAlbumArt; @@ -191,11 +195,19 @@ public class BrowseViewHolder extends RecyclerView.ViewHolder { } private void bindBrowseCustomActions(Context context, BrowseViewData browseViewData) { + int maxVisibleActions = context.getResources().getInteger(R.integer.max_visible_actions); + + if (mCustomActionsContainer == null) { + if (maxVisibleActions > 0) { + Log.e(TAG, "Custom action container null when max actions > 0"); + } + return; //We have nothing to bind to. + } + mCustomActionsContainer.removeAllViews(); mBrowseActionIcons.forEach((it) -> it.maybeCancelLoading(context)); mBrowseActionIcons.clear(); - int maxVisibleActions = context.getResources().getInteger(R.integer.max_visible_actions); int numActions = browseViewData.mCustomBrowseActions.size(); boolean willOverflow = numActions > maxVisibleActions; int actionsToShow = willOverflow ? Math.max(0, maxVisibleActions - 1) : maxVisibleActions; -- cgit v1.2.3