Merge "DO NOT MERGE: Make NIAP a Global Setting toggle." into qt-qpr1-dev
diff --git a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
index e0df8b2..cc8f88d 100644
--- a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
+++ b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
@@ -596,7 +596,7 @@
boolean isConnected() {
synchronized (this) {
- return (getCurrentState() == mConnected);
+ return (getConnectionState() == BluetoothProfile.STATE_CONNECTED);
}
}
diff --git a/src/com/android/bluetooth/avrcp/BrowsablePlayerConnector.java b/src/com/android/bluetooth/avrcp/BrowsablePlayerConnector.java
index b5886c2..3ce2c5d 100644
--- a/src/com/android/bluetooth/avrcp/BrowsablePlayerConnector.java
+++ b/src/com/android/bluetooth/avrcp/BrowsablePlayerConnector.java
@@ -23,6 +23,9 @@
import android.os.Message;
import android.util.Log;
+import com.android.bluetooth.Utils;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -47,6 +50,7 @@
private static final int MSG_CONNECT_CB = 1;
private static final int MSG_TIMEOUT = 2;
+ private static BrowsablePlayerConnector sInjectConnector;
private Handler mHandler;
private Context mContext;
private PlayerListCallback mCallback;
@@ -58,11 +62,19 @@
void run(List<BrowsedPlayerWrapper> result);
}
+ private static void setInstanceForTesting(BrowsablePlayerConnector connector) {
+ Utils.enforceInstrumentationTestMode();
+ sInjectConnector = connector;
+ }
+
static BrowsablePlayerConnector connectToPlayers(
Context context,
Looper looper,
List<ResolveInfo> players,
PlayerListCallback cb) {
+ if (sInjectConnector != null) {
+ return sInjectConnector;
+ }
if (cb == null) {
Log.wtfStack(TAG, "Null callback passed");
return null;
diff --git a/src/com/android/bluetooth/avrcp/GPMWrapper.java b/src/com/android/bluetooth/avrcp/GPMWrapper.java
index 87e5ec0..ea9875d 100644
--- a/src/com/android/bluetooth/avrcp/GPMWrapper.java
+++ b/src/com/android/bluetooth/avrcp/GPMWrapper.java
@@ -17,6 +17,7 @@
package com.android.bluetooth.avrcp;
import android.media.session.MediaSession;
+import android.os.Looper;
import android.util.Log;
/**
@@ -28,6 +29,10 @@
private static final String TAG = "AvrcpGPMWrapper";
private static final boolean DEBUG = true;
+ GPMWrapper(MediaController controller, Looper looper) {
+ super(controller, looper);
+ }
+
@Override
boolean isMetadataSynced() {
if (getQueue() == null) {
diff --git a/src/com/android/bluetooth/avrcp/MediaPlayerList.java b/src/com/android/bluetooth/avrcp/MediaPlayerList.java
index 29f4cf9..5756121 100644
--- a/src/com/android/bluetooth/avrcp/MediaPlayerList.java
+++ b/src/com/android/bluetooth/avrcp/MediaPlayerList.java
@@ -24,6 +24,9 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
@@ -33,6 +36,7 @@
import android.view.KeyEvent;
import com.android.bluetooth.Utils;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Collections;
@@ -79,6 +83,8 @@
private Looper mLooper; // Thread all media player callbacks and timeouts happen on
private PackageManager mPackageManager;
private MediaSessionManager mMediaSessionManager;
+ private MediaData mCurrMediaData = null;
+ private final AudioManager mAudioManager;
private Map<Integer, MediaPlayerWrapper> mMediaPlayers =
Collections.synchronizedMap(new HashMap<Integer, MediaPlayerWrapper>());
@@ -88,6 +94,9 @@
Collections.synchronizedMap(new HashMap<Integer, BrowsedPlayerWrapper>());
private int mActivePlayerId = NO_ACTIVE_PLAYER;
+ @VisibleForTesting
+ private boolean mAudioPlaybackIsActive = false;
+
private AvrcpTargetService.ListCallback mCallback;
private BrowsablePlayerConnector mBrowsablePlayerConnector;
@@ -122,6 +131,9 @@
pkgFilter.addDataScheme(PACKAGE_SCHEME);
context.registerReceiver(mPackageChangedBroadcastReceiver, pkgFilter);
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mAudioManager.registerAudioPlaybackCallback(mAudioPlaybackCallback, new Handler(mLooper));
+
mMediaSessionManager =
(MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
mMediaSessionManager.addOnActiveSessionsChangedListener(
@@ -190,6 +202,8 @@
mMediaSessionManager.setCallback(null, null);
mMediaSessionManager = null;
+ mAudioManager.unregisterAudioPlaybackCallback(mAudioPlaybackCallback);
+
mMediaPlayerIds.clear();
for (MediaPlayerWrapper player : mMediaPlayers.values()) {
@@ -275,7 +289,16 @@
final MediaPlayerWrapper player = getActivePlayer();
if (player == null) return null;
- return player.getPlaybackState();
+ PlaybackState state = player.getPlaybackState();
+ if (mAudioPlaybackIsActive
+ && (state == null || state.getState() != PlaybackState.STATE_PLAYING)) {
+ return new PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PLAYING,
+ state == null ? 0 : state.getPosition(),
+ 1.0f)
+ .build();
+ }
+ return state;
}
@NonNull
@@ -406,12 +429,8 @@
}
}
- // Adds the controller to the MediaPlayerList or updates the controller if we already had
- // a controller for a package. Returns the new ID of the controller where its added or its
- // previous value if it already existed. Returns -1 if the controller passed in is invalid
- int addMediaPlayer(android.media.session.MediaController controller) {
- if (controller == null) return -1;
-
+ @VisibleForTesting
+ int addMediaPlayer(MediaController controller) {
// Each new player has an ID of 1 plus the highest ID. The ID 0 is reserved to signify that
// there is no active player. If we already have a browsable player for the package, reuse
// that key.
@@ -427,7 +446,7 @@
if (mMediaPlayers.containsKey(playerId)) {
d("Already have a controller for the player: " + packageName + ", updating instead");
MediaPlayerWrapper player = mMediaPlayers.get(playerId);
- player.updateMediaController(MediaControllerFactory.wrap(controller));
+ player.updateMediaController(controller);
// If the media controller we updated was the active player check if the media updated
if (playerId == mActivePlayerId) {
@@ -437,8 +456,8 @@
return playerId;
}
- MediaPlayerWrapper newPlayer = MediaPlayerWrapper.wrap(
- MediaControllerFactory.wrap(controller),
+ MediaPlayerWrapper newPlayer = MediaPlayerWrapperFactory.wrap(
+ controller,
mLooper);
Log.i(TAG, "Adding wrapped media player: " + packageName + " at key: "
@@ -448,6 +467,18 @@
return playerId;
}
+ // Adds the controller to the MediaPlayerList or updates the controller if we already had
+ // a controller for a package. Returns the new ID of the controller where its added or its
+ // previous value if it already existed. Returns -1 if the controller passed in is invalid
+ int addMediaPlayer(android.media.session.MediaController controller) {
+ if (controller == null) {
+ e("Trying to add a null MediaController");
+ return -1;
+ }
+
+ return addMediaPlayer(MediaControllerFactory.wrap(controller));
+ }
+
void removeMediaPlayer(int playerId) {
if (!mMediaPlayers.containsKey(playerId)) {
e("Trying to remove nonexistent media player: " + playerId);
@@ -495,7 +526,12 @@
sendFolderUpdate(true, true, false);
}
- sendMediaUpdate(getActivePlayer().getCurrentMediaData());
+ MediaData data = getActivePlayer().getCurrentMediaData();
+ if (mAudioPlaybackIsActive) {
+ data.state = mCurrMediaData.state;
+ Log.d(TAG, "setActivePlayer mAudioPlaybackIsActive=true, state=" + data.state);
+ }
+ sendMediaUpdate(data);
}
// TODO (apanicke): Add logging for media key events in dumpsys
@@ -528,6 +564,8 @@
data.queue.add(data.metadata);
}
+ Log.d(TAG, "sendMediaUpdate state=" + data.state);
+ mCurrMediaData = data;
mCallback.run(data);
}
@@ -591,6 +629,78 @@
}
};
+ void updateMediaForAudioPlayback() {
+ MediaData currMediaData = null;
+ PlaybackState currState = null;
+ if (getActivePlayer() == null) {
+ Log.d(TAG, "updateMediaForAudioPlayback: no active player");
+ PlaybackState.Builder builder = new PlaybackState.Builder()
+ .setState(PlaybackState.STATE_STOPPED, 0L, 0L);
+ List<Metadata> queue = new ArrayList<Metadata>();
+ queue.add(Util.empty_data());
+ currMediaData = new MediaData(
+ Util.empty_data(),
+ builder.build(),
+ queue
+ );
+ } else {
+ currMediaData = getActivePlayer().getCurrentMediaData();
+ currState = currMediaData.state;
+ }
+
+ if (currState != null
+ && currState.getState() == PlaybackState.STATE_PLAYING) {
+ Log.i(TAG, "updateMediaForAudioPlayback: Active player is playing, drop it");
+ return;
+ }
+
+ if (mAudioPlaybackIsActive) {
+ PlaybackState.Builder builder = new PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PLAYING,
+ currState == null ? 0 : currState.getPosition(),
+ 1.0f);
+ currMediaData.state = builder.build();
+ }
+ Log.i(TAG, "updateMediaForAudioPlayback: update state=" + currMediaData.state);
+ sendMediaUpdate(currMediaData);
+ }
+
+ @VisibleForTesting
+ void injectAudioPlaybacActive(boolean isActive) {
+ mAudioPlaybackIsActive = isActive;
+ updateMediaForAudioPlayback();
+ }
+
+ private final AudioManager.AudioPlaybackCallback mAudioPlaybackCallback =
+ new AudioManager.AudioPlaybackCallback() {
+ @Override
+ public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
+ if (configs == null) {
+ return;
+ }
+ boolean isActive = false;
+ Log.v(TAG, "onPlaybackConfigChanged(): Configs list size=" + configs.size());
+ for (AudioPlaybackConfiguration config : configs) {
+ if (config.isActive() && (config.getAudioAttributes().getUsage()
+ == AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
+ && (config.getAudioAttributes().getContentType()
+ == AudioAttributes.CONTENT_TYPE_SPEECH)) {
+ if (DEBUG) {
+ Log.d(TAG, "onPlaybackConfigChanged(): config="
+ + AudioPlaybackConfiguration.toLogFriendlyString(config));
+ }
+ isActive = true;
+ }
+ }
+ if (isActive != mAudioPlaybackIsActive) {
+ Log.d(TAG, "onPlaybackConfigChanged isActive=" + isActive
+ + ", mAudioPlaybackIsActive=" + mAudioPlaybackIsActive);
+ mAudioPlaybackIsActive = isActive;
+ updateMediaForAudioPlayback();
+ }
+ }
+ };
+
private final MediaPlayerWrapper.Callback mMediaPlayerCallback =
new MediaPlayerWrapper.Callback() {
@Override
@@ -605,6 +715,10 @@
return;
}
+ if (mAudioPlaybackIsActive && (data.state.getState() != PlaybackState.STATE_PLAYING)) {
+ Log.d(TAG, "Some audio playbacks are still active, drop it");
+ return;
+ }
sendMediaUpdate(data);
}
};
diff --git a/src/com/android/bluetooth/avrcp/MediaPlayerWrapper.java b/src/com/android/bluetooth/avrcp/MediaPlayerWrapper.java
index e4176b3..9eba036 100644
--- a/src/com/android/bluetooth/avrcp/MediaPlayerWrapper.java
+++ b/src/com/android/bluetooth/avrcp/MediaPlayerWrapper.java
@@ -54,10 +54,6 @@
private final Object mCallbackLock = new Object();
private Callback mRegisteredCallback = null;
- protected MediaPlayerWrapper() {
- mCurrentData = new MediaData(null, null, null);
- }
-
public interface Callback {
void mediaUpdatedCallback(MediaData data);
}
@@ -80,30 +76,15 @@
return true;
}
- // TODO (apanicke): Implement a factory to make testing and creating interop wrappers easier
- static MediaPlayerWrapper wrap(MediaController controller, Looper looper) {
- if (controller == null || looper == null) {
- e("MediaPlayerWrapper.wrap(): Null parameter - Controller: " + controller
- + " | Looper: " + looper);
- return null;
- }
+ MediaPlayerWrapper(MediaController controller, Looper looper) {
+ mMediaController = controller;
+ mPackageName = controller.getPackageName();
+ mLooper = looper;
- MediaPlayerWrapper newWrapper;
- if (controller.getPackageName().equals("com.google.android.music")) {
- Log.v(TAG, "Creating compatibility wrapper for Google Play Music");
- newWrapper = new GPMWrapper();
- } else {
- newWrapper = new MediaPlayerWrapper();
- }
-
- newWrapper.mMediaController = controller;
- newWrapper.mPackageName = controller.getPackageName();
- newWrapper.mLooper = looper;
-
- newWrapper.mCurrentData.queue = Util.toMetadataList(newWrapper.getQueue());
- newWrapper.mCurrentData.metadata = Util.toMetadata(newWrapper.getMetadata());
- newWrapper.mCurrentData.state = newWrapper.getPlaybackState();
- return newWrapper;
+ mCurrentData = new MediaData(null, null, null);
+ mCurrentData.queue = Util.toMetadataList(getQueue());
+ mCurrentData.metadata = Util.toMetadata(getMetadata());
+ mCurrentData.state = getPlaybackState();
}
void cleanup() {
diff --git a/src/com/android/bluetooth/avrcp/mockable/MediaPlayerWrapperFactory.java b/src/com/android/bluetooth/avrcp/mockable/MediaPlayerWrapperFactory.java
new file mode 100644
index 0000000..d3ef751
--- /dev/null
+++ b/src/com/android/bluetooth/avrcp/mockable/MediaPlayerWrapperFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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.bluetooth.avrcp;
+
+import android.os.Looper;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Provide a method to inject custom MediaControllerWrapper objects for testing. By using the
+ * factory methods instead of calling the wrap method of MediaControllerWrapper directly, we can
+ * inject a custom MediaControllerWrapper that can be used with JUnit and Mockito to set
+ * expectations and validate behaviour in tests.
+ */
+public final class MediaPlayerWrapperFactory {
+ private static MediaPlayerWrapper sInjectedWrapper;
+
+ static MediaPlayerWrapper wrap(MediaController controller, Looper looper) {
+ if (sInjectedWrapper != null) return sInjectedWrapper;
+ if (controller == null || looper == null) {
+ return null;
+ }
+
+ MediaPlayerWrapper newWrapper;
+ if (controller.getPackageName().equals("com.google.android.music")) {
+ newWrapper = new GPMWrapper(controller, looper);
+ } else {
+ newWrapper = new MediaPlayerWrapper(controller, looper);
+ }
+ return newWrapper;
+ }
+
+ @VisibleForTesting
+ static void inject(MediaPlayerWrapper wrapper) {
+ sInjectedWrapper = wrapper;
+ }
+}
+
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 5ef481a..009e42c 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -2314,6 +2314,8 @@
}
boolean setPhonebookAccessPermission(BluetoothDevice device, int value) {
+ enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
+ "Need BLUETOOTH PRIVILEGED permission");
SharedPreferences pref = getSharedPreferences(PHONEBOOK_ACCESS_PERMISSION_PREFERENCE_FILE,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index c5485f9..989043a 100644
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -841,8 +841,6 @@
break;
}
case CALL_STATE_CHANGED: {
- if (mDeviceSilenced) break;
-
HeadsetCallState callState = (HeadsetCallState) message.obj;
if (!mNativeInterface.phoneStateChange(mDevice, callState)) {
stateLogW("processCallState: failed to update call state " + callState);
diff --git a/tests/unit/src/com/android/bluetooth/newavrcp/MediaPlayerListTest.java b/tests/unit/src/com/android/bluetooth/newavrcp/MediaPlayerListTest.java
new file mode 100644
index 0000000..39c8b4c
--- /dev/null
+++ b/tests/unit/src/com/android/bluetooth/newavrcp/MediaPlayerListTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2019 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.bluetooth.avrcp;
+
+import static org.mockito.Mockito.*;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.media.AudioManager;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
+import android.os.Looper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MediaPlayerListTest {
+ private MediaPlayerList mMediaPlayerList;
+
+ private @Captor ArgumentCaptor<AudioManager.AudioPlaybackCallback> mAudioCb;
+ private @Captor ArgumentCaptor<MediaPlayerWrapper.Callback> mPlayerWrapperCb;
+ private @Captor ArgumentCaptor<MediaData> mMediaUpdateData;
+ private @Mock Context mMockContext;
+ private @Mock AvrcpTargetService.ListCallback mAvrcpCallback;
+ private @Mock MediaController mMockController;
+ private @Mock MediaPlayerWrapper mMockPlayerWrapper;
+
+ private final String mFlagDexmarker = System.getProperty("dexmaker.share_classloader", "false");
+ private MediaPlayerWrapper.Callback mActivePlayerCallback;
+
+ @Before
+ public void setUp() throws Exception {
+ if (!mFlagDexmarker.equals("true")) {
+ System.setProperty("dexmaker.share_classloader", "true");
+ }
+
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ Assert.assertNotNull(Looper.myLooper());
+
+ MockitoAnnotations.initMocks(this);
+
+ AudioManager mockAudioManager = mock(AudioManager.class);
+ when(mMockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager);
+
+ MediaSessionManager mMediaSessionManager =
+ (MediaSessionManager) InstrumentationRegistry.getTargetContext()
+ .getSystemService(Context.MEDIA_SESSION_SERVICE);
+ PackageManager mockPackageManager = mock(PackageManager.class);
+ when(mMockContext.getSystemService(Context.MEDIA_SESSION_SERVICE))
+ .thenReturn(mMediaSessionManager);
+
+ mMediaPlayerList =
+ new MediaPlayerList(Looper.myLooper(), InstrumentationRegistry.getTargetContext());
+
+ when(mMockContext.registerReceiver(any(), any())).thenReturn(null);
+ when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
+ when(mMockContext.getPackageManager()).thenReturn(mockPackageManager);
+ List<ResolveInfo> playerList = new ArrayList<ResolveInfo>();
+ when(mockPackageManager.queryIntentServices(any(), anyInt())).thenReturn(null);
+
+ Method method = BrowsablePlayerConnector.class.getDeclaredMethod("setInstanceForTesting",
+ BrowsablePlayerConnector.class);
+ BrowsablePlayerConnector mockConnector = mock(BrowsablePlayerConnector.class);
+ method.setAccessible(true);
+ method.invoke(null, mockConnector);
+ mMediaPlayerList.init(mAvrcpCallback);
+
+ MediaControllerFactory.inject(mMockController);
+ MediaPlayerWrapperFactory.inject(mMockPlayerWrapper);
+
+ doReturn("testPlayer").when(mMockController).getPackageName();
+ when(mMockPlayerWrapper.isMetadataSynced()).thenReturn(false);
+ mMediaPlayerList.setActivePlayer(mMediaPlayerList.addMediaPlayer(mMockController));
+
+ verify(mMockPlayerWrapper).registerCallback(mPlayerWrapperCb.capture());
+ mActivePlayerCallback = mPlayerWrapperCb.getValue();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Method method = BrowsablePlayerConnector.class.getDeclaredMethod("setInstanceForTesting",
+ BrowsablePlayerConnector.class);
+ method.setAccessible(true);
+ method.invoke(null, (BrowsablePlayerConnector) null);
+
+ MediaControllerFactory.inject(null);
+ MediaPlayerWrapperFactory.inject(null);
+ mMediaPlayerList.cleanup();
+ if (!mFlagDexmarker.equals("true")) {
+ System.setProperty("dexmaker.share_classloader", mFlagDexmarker);
+ }
+ }
+
+ private MediaData prepareMediaData(int playbackState) {
+ PlaybackState.Builder builder = new PlaybackState.Builder();
+ builder.setState(playbackState, 0, 1);
+ ArrayList<Metadata> list = new ArrayList<Metadata>();
+ list.add(Util.empty_data());
+ MediaData newData = new MediaData(
+ Util.empty_data(),
+ builder.build(),
+ list);
+
+ return newData;
+ }
+
+ @Test
+ public void testUpdateMeidaDataForAudioPlaybackWhenActivePlayNotPlaying() {
+ // Verify update media data with playing state
+ doReturn(prepareMediaData(PlaybackState.STATE_PAUSED))
+ .when(mMockPlayerWrapper).getCurrentMediaData();
+ mMediaPlayerList.injectAudioPlaybacActive(true);
+ verify(mAvrcpCallback).run(mMediaUpdateData.capture());
+ MediaData data = mMediaUpdateData.getValue();
+ Assert.assertEquals(data.state.getState(), PlaybackState.STATE_PLAYING);
+
+ // verify update media data with current media player media data
+ MediaData currentMediaData = prepareMediaData(PlaybackState.STATE_PAUSED);
+ doReturn(currentMediaData).when(mMockPlayerWrapper).getCurrentMediaData();
+ mMediaPlayerList.injectAudioPlaybacActive(false);
+ verify(mAvrcpCallback, times(2)).run(mMediaUpdateData.capture());
+ data = mMediaUpdateData.getValue();
+ Assert.assertEquals(data.metadata, currentMediaData.metadata);
+ Assert.assertEquals(data.state.toString(), currentMediaData.state.toString());
+ Assert.assertEquals(data.queue, currentMediaData.queue);
+ }
+
+ @Test
+ public void testUpdateMediaDataForActivePlayerWhenAudioPlaybackIsNotActive() {
+ MediaData currMediaData = prepareMediaData(PlaybackState.STATE_PLAYING);
+ mActivePlayerCallback.mediaUpdatedCallback(currMediaData);
+ verify(mAvrcpCallback).run(currMediaData);
+
+ currMediaData = prepareMediaData(PlaybackState.STATE_PAUSED);
+ mActivePlayerCallback.mediaUpdatedCallback(currMediaData);
+ verify(mAvrcpCallback).run(currMediaData);
+ }
+
+ @Test
+ public void testNotUpdateMediaDataForAudioPlaybackWhenActivePlayerIsPlaying() {
+ // Verify not update media data for Audio Playback when active player is playing
+ doReturn(prepareMediaData(PlaybackState.STATE_PLAYING))
+ .when(mMockPlayerWrapper).getCurrentMediaData();
+ mMediaPlayerList.injectAudioPlaybacActive(true);
+ mMediaPlayerList.injectAudioPlaybacActive(false);
+ verify(mAvrcpCallback, never()).run(any());
+ }
+
+ @Test
+ public void testNotUpdateMediaDataForActivePlayerWhenAudioPlaybackIsActive() {
+ doReturn(prepareMediaData(PlaybackState.STATE_PLAYING))
+ .when(mMockPlayerWrapper).getCurrentMediaData();
+ mMediaPlayerList.injectAudioPlaybacActive(true);
+ verify(mAvrcpCallback, never()).run(any());
+
+ // Verify not update active player media data when audio playback is active
+ mActivePlayerCallback.mediaUpdatedCallback(prepareMediaData(PlaybackState.STATE_PAUSED));
+ verify(mAvrcpCallback, never()).run(any());
+ }
+
+}
diff --git a/tests/unit/src/com/android/bluetooth/newavrcp/MediaPlayerWrapperTest.java b/tests/unit/src/com/android/bluetooth/newavrcp/MediaPlayerWrapperTest.java
index ee41320..1e41033 100644
--- a/tests/unit/src/com/android/bluetooth/newavrcp/MediaPlayerWrapperTest.java
+++ b/tests/unit/src/com/android/bluetooth/newavrcp/MediaPlayerWrapperTest.java
@@ -138,10 +138,10 @@
*/
@Test
public void testNullControllerLooper() {
- MediaPlayerWrapper wrapper = MediaPlayerWrapper.wrap(null, mThread.getLooper());
+ MediaPlayerWrapper wrapper = MediaPlayerWrapperFactory.wrap(null, mThread.getLooper());
Assert.assertNull(wrapper);
- wrapper = MediaPlayerWrapper.wrap(mMockController, null);
+ wrapper = MediaPlayerWrapperFactory.wrap(mMockController, null);
Assert.assertNull(wrapper);
}
@@ -151,7 +151,8 @@
*/
@Test
public void testIsReady() {
- MediaPlayerWrapper wrapper = MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapper wrapper =
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
Assert.assertTrue(wrapper.isPlaybackStateReady());
Assert.assertTrue(wrapper.isMetadataReady());
@@ -179,7 +180,8 @@
@Test
public void testControllerUpdate() {
// Create the wrapper object and register the looper with the timeout handler
- MediaPlayerWrapper wrapper = MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapper wrapper =
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
Assert.assertTrue(wrapper.isPlaybackStateReady());
Assert.assertTrue(wrapper.isMetadataReady());
wrapper.registerCallback(mTestCbs);
@@ -213,7 +215,7 @@
// Create the wrapper object and register the looper with the timeout handler
TestLooperManager looperManager = new TestLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Return null when getting the queue
@@ -275,7 +277,7 @@
// Create the wrapper object and register the looper with the timeout handler
TestLooperManager looperManager = new TestLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Return null when getting the queue
@@ -319,7 +321,7 @@
// Create the wrapper object and register the looper with the timeout handler
TestLooperManager looperManager = new TestLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Return null when getting the queue
@@ -348,7 +350,7 @@
// Create the wrapper object and register the looper with the timeout handler
TestLooperManager looperManager = new TestLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Return null when getting the queue
@@ -375,7 +377,7 @@
// Create the wrapper object and register the looper with the timeout handler
TestLooperManager looperManager = new TestLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Call getCurrentQueue() multiple times.
@@ -398,7 +400,7 @@
// Create the wrapper object and register the looper with the timeout handler
TestLooperManager looperManager = new TestLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Return null when getting the queue
@@ -455,7 +457,7 @@
// Create the wrapper object and register the looper with the timeout handler
TestLooperManager looperManager = new TestLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Cleanup the wrapper
@@ -475,7 +477,7 @@
// Create the wrapper object and register the looper with the timeout handler
TestLooperManager looperManager = new TestLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Grab the callbacks the wrapper registered with the controller
@@ -505,7 +507,7 @@
// Create the wrapper object and register the looper with the timeout handler
TestLooperManager looperManager = new TestLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Grab the callbacks the wrapper registered with the controller
@@ -565,7 +567,7 @@
InstrumentationRegistry.getInstrumentation()
.acquireLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Grab the callbacks the wrapper registered with the controller
@@ -615,7 +617,7 @@
InstrumentationRegistry.getInstrumentation()
.acquireLooperManager(mThread.getLooper());
MediaPlayerWrapper wrapper =
- MediaPlayerWrapper.wrap(mMockController, mThread.getLooper());
+ MediaPlayerWrapperFactory.wrap(mMockController, mThread.getLooper());
wrapper.registerCallback(mTestCbs);
// Grab the callbacks the wrapper registered with the controller