OSDN Git Service

Add AVRCP unit tests and switch to using mockable interfaces
authorAjay Panicker <apanicke@google.com>
Fri, 21 Oct 2016 19:07:39 +0000 (12:07 -0700)
committerAndre Eisenbach <eisenbach@google.com>
Wed, 26 Oct 2016 17:47:14 +0000 (17:47 +0000)
Add a mockable interface for MediaController in order to add unit
tests for AddressedMediaPlayer.

Bug: 32416674
Test: Tested manually
Change-Id: I081c37915fc15e58f3de37c3a16e03747503860c

src/com/android/bluetooth/avrcp/AddressedMediaPlayer.java
src/com/android/bluetooth/avrcp/Avrcp.java
src/com/android/bluetooth/avrcp/AvrcpHelperClasses.java
src/com/android/bluetooth/avrcp/BrowsedMediaPlayer.java
src/com/android/bluetooth/avrcp/mockable/MediaController.java [new file with mode: 0644]
tests/Android.mk
tests/AndroidManifest.xml
tests/src/com/android/bluetooth/tests/avrcp/AddressedMediaPlayerTest.java [new file with mode: 0644]
tests/src/com/android/bluetooth/tests/gatt/GattServiceTest.java [moved from tests/src/com/android/bluetooth/gatt/GattServiceTest.java with 100% similarity]

index bb3136a..d66c496 100644 (file)
@@ -19,7 +19,6 @@ package com.android.bluetooth.avrcp;
 import android.bluetooth.BluetoothAvrcp;
 import android.media.session.MediaSession;
 import android.media.session.MediaSession.QueueItem;
-import android.media.session.MediaController;
 import android.media.MediaDescription;
 import android.media.MediaMetadata;
 import android.os.Bundle;
index f135cb8..130ed69 100644 (file)
@@ -33,7 +33,6 @@ import android.content.SharedPreferences;
 import android.media.AudioManager;
 import android.media.MediaDescription;
 import android.media.MediaMetadata;
-import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.MediaSession.QueueItem;
 import android.media.session.MediaSessionManager;
@@ -1592,17 +1591,22 @@ public final class Avrcp {
             new MediaSessionManager.OnActiveSessionsChangedListener() {
 
         @Override
-        public void onActiveSessionsChanged(List<MediaController> mediaControllerList) {
+        public void onActiveSessionsChanged(List<android.media.session.MediaController> mediaControllerList) {
             if (DEBUG) Log.v(TAG, "received onActiveSessionsChanged");
 
-            if (isAvailablePlayersChanged(mediaControllerList)) {
+            List<MediaController> mediaControllerListTemp = new ArrayList<MediaController>();
+            for (android.media.session.MediaController temp : mediaControllerList) {
+                mediaControllerListTemp.add(MediaController.wrap(temp));
+            }
+
+            if (isAvailablePlayersChanged(mediaControllerListTemp)) {
                 // rebuild the list cached locally in this file
                 buildMediaPlayersList();
 
                 // inform the remote device that the player list has changed
                 sendAvailablePlayersChanged();
-            } else if (isAddressedPlayerChanged(mediaControllerList)) {
-                int newAddrPlayerID = getNewAddrPlayerID(mediaControllerList.get(0)
+            } else if (isAddressedPlayerChanged(mediaControllerListTemp)) {
+                int newAddrPlayerID = getNewAddrPlayerID(mediaControllerListTemp.get(0)
                         .getPackageName());
                 // inform the remote device that the addressed player has changed
                 sendAddressedPlayerChanged(newAddrPlayerID);
@@ -1819,14 +1823,15 @@ public final class Avrcp {
         mMediaPlayerInfoList.clear();
 
         /* Initializing all media players */
-        for (MediaController mediaController : getActiveControllersList()) {
-            initMediaPlayer(mediaController);
+        for (android.media.session.MediaController mediaController : getActiveControllersList()) {
+            initMediaPlayer(MediaController.wrap(mediaController));
         }
     }
 
     /* Using session manager apis, getting the list of active media controllers */
-    private List<MediaController> getActiveControllersList() {
-        List<MediaController> controllersList = new ArrayList<MediaController>();
+    private List<android.media.session.MediaController> getActiveControllersList() {
+        List<android.media.session.MediaController> controllersList =
+            new ArrayList<android.media.session.MediaController>();
         controllersList = mMediaSessionManager.getActiveSessions(null);
         Log.i(TAG, "getActiveControllersList: " + controllersList.size() + " controllers");
         return controllersList;
index 9855a27..6a50238 100644 (file)
@@ -16,7 +16,6 @@
 
 package com.android.bluetooth.avrcp;
 
-import android.media.session.MediaController;
 import android.media.session.MediaSession;
 
 import java.util.List;
index 3e3c33c..8c45468 100644 (file)
@@ -22,7 +22,6 @@ import android.media.MediaDescription;
 import android.media.MediaMetadata;
 import android.media.browse.MediaBrowser;
 import android.media.browse.MediaBrowser.MediaItem;
-import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.MediaSession.QueueItem;
 import android.util.Log;
@@ -223,7 +222,8 @@ class BrowsedMediaPlayer {
             }
 
             if (isError == false) {
-                mMediaController = new MediaController(mContext, token);
+                mMediaController = MediaController.wrap(
+                    new android.media.session.MediaController(mContext, token));
                 /* get root folder items */
                 mMediaBrowser.subscribe(mRootFolderUid, folderItemsCb);
             }
diff --git a/src/com/android/bluetooth/avrcp/mockable/MediaController.java b/src/com/android/bluetooth/avrcp/mockable/MediaController.java
new file mode 100644 (file)
index 0000000..032bf2b
--- /dev/null
@@ -0,0 +1,224 @@
+package com.android.bluetooth.avrcp;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.MediaMetadata;
+import android.media.Rating;
+import android.media.VolumeProvider;
+import android.media.session.PlaybackState;
+import android.media.session.MediaSession;
+import android.media.session.MediaSession.QueueItem;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MediaController {
+    public android.media.session.MediaController mDelegate;
+    public android.media.session.MediaController.TransportControls mTransportDelegate;
+    public TransportControls mTransportControls;
+
+    @Nullable
+    public static MediaController wrap(@Nullable android.media.session.MediaController delegate) {
+      return (delegate != null) ? new MediaController(delegate) : null;
+    }
+
+    public MediaController(@NonNull android.media.session.MediaController delegate) {
+        mDelegate = delegate;
+        mTransportDelegate = delegate.getTransportControls();
+        mTransportControls = new TransportControls();
+    }
+
+    public android.media.session.MediaController getWrappedInstance() {
+        return mDelegate;
+    }
+
+    public @NonNull TransportControls getTransportControls() {
+        return mTransportControls;
+    }
+
+    public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) {
+        return mDelegate.dispatchMediaButtonEvent(keyEvent);
+    }
+
+    public @Nullable PlaybackState getPlaybackState() {
+        return mDelegate.getPlaybackState();
+    }
+
+    public @Nullable MediaMetadata getMetadata() {
+        return mDelegate.getMetadata();
+    }
+
+    public @Nullable List<MediaSession.QueueItem> getQueue() {
+        return mDelegate.getQueue();
+    }
+
+    public @Nullable CharSequence getQueueTitle() {
+        return mDelegate.getQueueTitle();
+    }
+
+    public @Nullable Bundle getExtras() {
+        return mDelegate.getExtras();
+    }
+
+    public int getRatingType() {
+        return mDelegate.getRatingType();
+    }
+
+    public long getFlags() {
+        return mDelegate.getFlags();
+    }
+
+    public @Nullable android.media.session.MediaController.PlaybackInfo getPlaybackInfo() {
+        return mDelegate.getPlaybackInfo();
+    }
+
+    public @Nullable PendingIntent getSessionActivity() {
+        return mDelegate.getSessionActivity();
+    }
+
+    public @NonNull MediaSession.Token getSessionToken() {
+        return mDelegate.getSessionToken();
+    }
+
+    public void setVolumeTo(int value, int flags) {
+        mDelegate.setVolumeTo(value, flags);
+    }
+
+    public void adjustVolume(int direction, int flags) {
+        mDelegate.adjustVolume(direction, flags);
+    }
+
+    public void registerCallback(@NonNull Callback callback) {
+        //TODO(apanicke): Add custom callback struct to be able to analyze and
+        // delegate callbacks
+        mDelegate.registerCallback(callback);
+    }
+
+    public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
+        mDelegate.registerCallback(callback, handler);
+    }
+
+    public void unregisterCallback(@NonNull Callback callback) {
+        mDelegate.unregisterCallback(callback);
+    }
+
+    public void sendCommand(@NonNull String command, @Nullable Bundle args,
+            @Nullable ResultReceiver cb) {
+        mDelegate.sendCommand(command, args, cb);
+    }
+
+    public String getPackageName() {
+        return mDelegate.getPackageName();
+    }
+
+    public String getTag() {
+        return mDelegate.getTag();
+    }
+
+    public boolean controlsSameSession(MediaController other) {
+        return mDelegate.controlsSameSession(other.getWrappedInstance());
+    }
+
+    public boolean controlsSameSession(android.media.session.MediaController other) {
+        return mDelegate.controlsSameSession(other);
+    }
+
+    public static abstract class Callback extends android.media.session.MediaController.Callback { }
+
+    public class TransportControls {
+
+        public void prepare() {
+            mTransportDelegate.prepare();
+        }
+
+        public void prepareFromMediaId(String mediaId, Bundle extras) {
+            mTransportDelegate.prepareFromMediaId(mediaId, extras);
+        }
+
+        public void prepareFromSearch(String query, Bundle extras) {
+            mTransportDelegate.prepareFromSearch(query, extras);
+        }
+
+        public void prepareFromUri(Uri uri, Bundle extras) {
+            mTransportDelegate.prepareFromUri(uri, extras);
+        }
+
+        public void play() {
+            mTransportDelegate.play();
+        }
+
+        public void playFromMediaId(String mediaId, Bundle extras) {
+            mTransportDelegate.playFromMediaId(mediaId, extras);
+        }
+
+        public void playFromSearch(String query, Bundle extras) {
+            mTransportDelegate.playFromSearch(query, extras);
+        }
+
+        public void playFromUri(Uri uri, Bundle extras) {
+            mTransportDelegate.playFromUri(uri, extras);
+        }
+
+        public void skipToQueueItem(long id) {
+            mTransportDelegate.skipToQueueItem(id);
+        }
+
+        public void pause() {
+            mTransportDelegate.pause();
+        }
+
+        public void stop() {
+            mTransportDelegate.stop();
+        }
+
+        public void seekTo(long pos) {
+            mTransportDelegate.seekTo(pos);
+        }
+
+        public void fastForward() {
+            mTransportDelegate.fastForward();
+        }
+
+        public void skipToNext() {
+            mTransportDelegate.skipToNext();
+        }
+
+        public void rewind() {
+            mTransportDelegate.rewind();
+        }
+
+        public void skipToPrevious() {
+            mTransportDelegate.skipToPrevious();
+        }
+
+        public void setRating(Rating rating) {
+            mTransportDelegate.setRating(rating);
+        }
+
+        public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
+                @Nullable Bundle args) {
+            mTransportDelegate.sendCustomAction(customAction, args);
+        }
+
+        public void sendCustomAction(@NonNull String action, @Nullable Bundle args) {
+            mTransportDelegate.sendCustomAction(action, args);
+        }
+    }
+}
+
index 32f0111..e2a2e82 100755 (executable)
@@ -5,8 +5,15 @@ include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := tests
 LOCAL_CERTIFICATE := platform
 
-LOCAL_JAVA_LIBRARIES := javax.obex android.test.runner telephony-common libprotobuf-java-micro
-LOCAL_STATIC_JAVA_LIBRARIES := com.android.emailcommon littlemock dexmaker
+LOCAL_JAVA_LIBRARIES := \
+    javax.obex android.test.runner \
+    telephony-common \
+    libprotobuf-java-micro
+
+LOCAL_STATIC_JAVA_LIBRARIES :=  \
+    com.android.emailcommon \
+    android-support-test \
+    mockito-target
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
index cf128db..b4358c8 100755 (executable)
@@ -64,7 +64,7 @@
     the package of com.android.bluetooth.  To run the tests use the command:
     "adb shell am instrument -w com.android.bluetooth.tests/android.test.InstrumentationTestRunner"
     -->
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.bluetooth"
                      android:label="Tests for com.android.bluetooth"/>
 </manifest>
diff --git a/tests/src/com/android/bluetooth/tests/avrcp/AddressedMediaPlayerTest.java b/tests/src/com/android/bluetooth/tests/avrcp/AddressedMediaPlayerTest.java
new file mode 100644 (file)
index 0000000..81773a4
--- /dev/null
@@ -0,0 +1,93 @@
+package com.android.bluetooth.avrcp;
+
+import android.bluetooth.BluetoothAvrcp;
+import android.media.session.MediaSession;
+import android.media.session.MediaSession.QueueItem;
+import android.media.MediaDescription;
+import android.media.MediaMetadata;
+import android.os.Bundle;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+
+import static org.mockito.Mockito.*;
+
+public class AddressedMediaPlayerTest extends AndroidTestCase {
+
+    public void testHandlePassthroughCmd() {
+        MediaController mockController = mock(com.android.bluetooth.avrcp.MediaController.class);
+        MediaController.TransportControls mockTransport = mock(MediaController.TransportControls.class);
+        AvrcpMediaRspInterface mockRspInterface = mock(AvrcpMediaRspInterface.class);
+
+        when(mockController.getTransportControls()).thenReturn(mockTransport);
+        AddressedMediaPlayer myMediaPlayer = new AddressedMediaPlayer(mockRspInterface);
+
+
+        // Test rewind
+        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_REWIND,
+                                           AvrcpConstants.KEY_STATE_PRESS,
+                                           null,
+                                           mockController);
+        verify(mockTransport).rewind();
+
+        // Test fast forward
+        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR,
+                                           AvrcpConstants.KEY_STATE_PRESS,
+                                           null,
+                                           mockController);
+        verify(mockTransport).fastForward();
+
+        // Test play
+        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_PLAY,
+                                           AvrcpConstants.KEY_STATE_PRESS,
+                                           null,
+                                           mockController);
+        verify(mockTransport).play();
+
+        // Test pause
+        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_PAUSE,
+                                           AvrcpConstants.KEY_STATE_PRESS,
+                                           null,
+                                           mockController);
+        verify(mockTransport).pause();
+
+        // Test stop
+        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_STOP,
+                                           AvrcpConstants.KEY_STATE_PRESS,
+                                           null,
+                                           mockController);
+        verify(mockTransport).stop();
+
+        // Test skip to next
+        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_FORWARD,
+                                           AvrcpConstants.KEY_STATE_PRESS,
+                                           null,
+                                           mockController);
+        verify(mockTransport).skipToNext();
+
+        // Test skip backwards
+        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_BACKWARD,
+                                           AvrcpConstants.KEY_STATE_PRESS,
+                                           null,
+                                           mockController);
+        verify(mockTransport).skipToPrevious();
+
+        // Test invalid key
+        myMediaPlayer.handlePassthroughCmd(0xFF,
+                                           AvrcpConstants.KEY_STATE_PRESS,
+                                           null,
+                                           mockController);
+        verifyNoMoreInteractions(mockTransport);
+
+        // Test key release
+        myMediaPlayer.handlePassthroughCmd(BluetoothAvrcp.PASSTHROUGH_ID_PLAY,
+                                           AvrcpConstants.KEY_STATE_RELEASE,
+                                           null,
+                                           mockController);
+        verifyNoMoreInteractions(mockTransport);
+    }
+}