summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-03-13 20:35:25 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-03-13 20:35:25 +0000
commit72af0679d01410e765325c05dbf000df5d722018 (patch)
tree64602c98fd67ad03f022f098f877a720164c46cc
parent03545310fc4b7fad503ce5c032affc00de8dc498 (diff)
parent07306b21ea40b3f7c2bcfb539368ee5f59bd2dda (diff)
downloadMedia-mirror-car-apps-aosp-release.tar.gz
Snap for 11566466 from 07306b21ea40b3f7c2bcfb539368ee5f59bd2dda to car-apps-aosp-releaseub-automotive-master-20240314mirror-car-apps-aosp-release
Change-Id: I0e1243a639bd4e04d4b151e19a5d0feaee42feb5
-rw-r--r--build.gradle2
-rw-r--r--src/com/android/car/media/MediaActivity.java51
-rw-r--r--src/com/android/car/media/browse/BrowseViewHolder.java14
-rw-r--r--src/com/android/car/media/service/MediaConnectorService.java24
-rw-r--r--tests/unittests/src/com/android/car/media/service/MediaConnectorServiceTests.java (renamed from tests/unittests/src/com/android/car/media/MediaConnectorServiceTests.java)31
5 files changed, 63 insertions, 59 deletions
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/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<FutureData<MediaSource>> mBrowsedMediaSource =
dataOf(FutureData.newLoadingData());
- private final Map<MediaSource, MediaServiceState> mStates = new HashMap<>();
private final MutableLiveData<Boolean> 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;
}
}
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;
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/service/MediaConnectorServiceTests.java
index 81b0844..bf275fd 100644
--- a/tests/unittests/src/com/android/car/media/MediaConnectorServiceTests.java
+++ b/tests/unittests/src/com/android/car/media/service/MediaConnectorServiceTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.car.media;
+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;
@@ -38,13 +38,14 @@ 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 com.android.car.media.service.MediaConnectorService;
import org.junit.Before;
import org.junit.Test;
@@ -68,6 +69,7 @@ public class MediaConnectorServiceTests extends BaseMockitoTest {
@Mock private PlaybackStateCompat mState;
@Mock MediaControllerCompat.TransportControls mControls;
+ @UiThreadTest
@Before
public void setup() {
mPlaybackLiveData = dataOf(null);
@@ -83,7 +85,7 @@ public class MediaConnectorServiceTests extends BaseMockitoTest {
String displayName = browseService.getClassName();
Drawable icon = new ColorDrawable();
IconCropper iconCropper = new IconCropper(new Path());
- return new MediaSource(browseService, displayName, icon, iconCropper);
+ return new MediaSource(browseService, null, displayName, icon, iconCropper);
}
private void sendCommand(@Nullable ComponentName source, boolean autoPlay) {
@@ -92,7 +94,7 @@ public class MediaConnectorServiceTests extends BaseMockitoTest {
if (source != null) {
intent.putExtra(CarMediaIntents.EXTRA_MEDIA_COMPONENT, source.flattenToString());
}
- mService.onStartCommand(intent, 0, 0);
+ mService.prepareToStartService(intent, /* startId= */ 0);
}
private PlaybackStateWrapper newState(ComponentName comp) {
@@ -107,15 +109,18 @@ public class MediaConnectorServiceTests extends BaseMockitoTest {
PlaybackStateWrapper state = newState(COMP_1_1);
- mPlaybackLiveData.setValue(state);
+ mPlaybackLiveData.postValue(state);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
verify(mControls, times(0)).prepare();
verify(mControls, times(0)).play();
- mPlaybackLiveData.setValue(state);
+ mPlaybackLiveData.postValue(state);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
verify(mControls, times(1)).prepare();
verify(mControls, times(0)).play();
- mPlaybackLiveData.setValue(state);
+ mPlaybackLiveData.postValue(state);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
verify(mControls, times(1)).prepare();
verify(mControls, times(1)).play();
}
@@ -124,7 +129,8 @@ public class MediaConnectorServiceTests extends BaseMockitoTest {
public void onlyPrepareWhenPlayNotEnabled() {
when(mState.getActions()).thenReturn(ACTION_PREPARE);
sendCommand(COMP_1_1, true);
- mPlaybackLiveData.setValue(newState(COMP_1_1));
+ mPlaybackLiveData.postValue(newState(COMP_1_1));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
verify(mControls, times(1)).prepare();
verify(mControls, times(0)).play();
}
@@ -133,7 +139,8 @@ public class MediaConnectorServiceTests extends BaseMockitoTest {
public void onlyPrepareWhenPlayNotRequested() {
when(mState.getActions()).thenReturn(ACTION_PREPARE | ACTION_PLAY);
sendCommand(COMP_1_1, false);
- mPlaybackLiveData.setValue(newState(COMP_1_1));
+ mPlaybackLiveData.postValue(newState(COMP_1_1));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
verify(mControls, times(1)).prepare();
verify(mControls, times(0)).play();
}
@@ -143,11 +150,13 @@ public class MediaConnectorServiceTests extends BaseMockitoTest {
when(mState.getActions()).thenReturn(ACTION_PREPARE | ACTION_PLAY);
sendCommand(COMP_1_2, true);
- mPlaybackLiveData.setValue(newState(COMP_1_1));
+ mPlaybackLiveData.postValue(newState(COMP_1_1));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
verify(mControls, times(0)).prepare();
verify(mControls, times(0)).play();
- mPlaybackLiveData.setValue(newState(COMP_1_2));
+ mPlaybackLiveData.postValue(newState(COMP_1_2));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
verify(mControls, times(1)).prepare();
verify(mControls, times(1)).play();
}