Loading android/app/src/com/android/bluetooth/avrcp/Avrcp.java +2 −2 Original line number Diff line number Diff line Loading @@ -1800,7 +1800,7 @@ public final class Avrcp { for (android.media.session.MediaController controller : newControllers) { String packageName = controller.getPackageName(); if (DEBUG) { Log.v(TAG, "ActiveSession: " + MediaController.wrap(controller)); Log.v(TAG, "ActiveSession: " + MediaControllerFactory.wrap(controller)); } // Only use the first (highest priority) controller from each package if (updatedPackages.contains(packageName)) { Loading Loading @@ -2000,7 +2000,7 @@ public final class Avrcp { /** Add (or update) a player to the media player list given an active controller */ private boolean addMediaPlayerController(android.media.session.MediaController controller) { String packageName = controller.getPackageName(); MediaPlayerInfo info = new MediaPlayerInfo(MediaController.wrap(controller), MediaPlayerInfo info = new MediaPlayerInfo(MediaControllerFactory.wrap(controller), AvrcpConstants.PLAYER_TYPE_AUDIO, AvrcpConstants.PLAYER_SUBTYPE_NONE, getBluetoothPlayState(controller.getPlaybackState()), getFeatureBitMask(packageName), controller.getPackageName(), Loading android/app/src/com/android/bluetooth/avrcp/BrowsedMediaPlayer.java +1 −2 Original line number Diff line number Diff line Loading @@ -318,8 +318,7 @@ class BrowsedMediaPlayer { mPathStack.push(mMediaId); } mMediaController = MediaController.wrap( new android.media.session.MediaController(mContext, token)); mMediaController = MediaControllerFactory.make(mContext, token); /* get root folder items */ mMediaBrowser.subscribe(mRootFolderUid, mFolderItemsCb); return; Loading android/app/src/com/android/bluetooth/avrcp/mockable/MediaBrowser.java 0 → 100644 +165 −0 Original line number Diff line number Diff line /* * Copyright 2018 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.content.ComponentName; import android.content.Context; import android.media.session.MediaSession; import android.os.Bundle; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; /** * Provide a mockable interface in order to test classes that use MediaBrowser. * We need this class due to the fact that the MediaController class is marked as final and * there is no way to currently mock final classes in Android. Once this is possible this class * can be deleted. */ public class MediaBrowser { android.media.browse.MediaBrowser mDelegate; /** * Wrap a real MediaBrowser object */ public MediaBrowser(android.media.browse.MediaBrowser delegate) { mDelegate = delegate; } /** * Create a real MediaBrowser object and wrap it */ public MediaBrowser(Context context, ComponentName serviceComponent, ConnectionCallback callback, Bundle rootHints) { mDelegate = new android.media.browse.MediaBrowser(context, serviceComponent, callback, rootHints); } /** * Wrapper for MediaBrowser.ConnectionCallback */ public abstract static class ConnectionCallback extends android.media.browse.MediaBrowser.ConnectionCallback {} /** * Wrapper for MediaBrowser.ItemCallback */ public abstract static class ItemCallback extends android.media.browse.MediaBrowser.ItemCallback {} /** * Wrapper for MediaBrowser.SubscriptionCallback */ public abstract static class SubscriptionCallback extends android.media.browse.MediaBrowser.SubscriptionCallback {} /** * Wrapper for MediaBrowser.connect() */ public void connect() { mDelegate.connect(); } /** * Wrapper for MediaBrowser.disconnect() */ public void disconnect() { mDelegate.disconnect(); } /** * Wrapper for MediaBrowser.getExtras() */ public Bundle getExtras() { return mDelegate.getExtras(); } /** * Wrapper for MediaBrowser.getItem(String mediaId, ItemCallback callback) */ public void getItem(String mediaId, ItemCallback callback) { mDelegate.getItem(mediaId, callback); } /** * Wrapper for MediaBrowser.getRoot() */ public String getRoot() { return mDelegate.getRoot(); } /** * Wrapper for MediaBrowser.getServiceComponent() */ public ComponentName getServiceComponent() { return mDelegate.getServiceComponent(); } /** * Wrapper for MediaBrowser.getSessionToken() */ public MediaSession.Token getSessionToken() { return mDelegate.getSessionToken(); } /** * Wrapper for MediaBrowser.isConnected() */ public boolean isConnected() { return mDelegate.isConnected(); } /** * Wrapper for MediaBrowser.subscribe(String parentId, Bundle options, * SubscriptionCallback callback) */ public void subscribe(String parentId, Bundle options, SubscriptionCallback callback) { mDelegate.subscribe(parentId, options, callback); } /** * Wrapper for MediaBrowser.subscribe(String parentId, SubscriptionCallback callback) */ public void subscribe(String parentId, SubscriptionCallback callback) { mDelegate.subscribe(parentId, callback); } /** * Wrapper for MediaBrowser.unsubscribe(String parentId) */ public void unsubscribe(String parentId) { mDelegate.unsubscribe(parentId); } /** * Wrapper for MediaBrowser.unsubscribe(String parentId, SubscriptionCallback callback) */ public void unsubscribe(String parentId, SubscriptionCallback callback) { mDelegate.unsubscribe(parentId, callback); } /** * A function that allows Mockito to capture the constructor arguments when using * MediaBrowserFactory.make() */ @VisibleForTesting public void testInit(Context context, ComponentName serviceComponent, ConnectionCallback callback, Bundle rootHints) { // This is only used by Mockito to capture the constructor arguments on creation Log.wtfStack("AvrcpMockMediaBrowser", "This function should never be called"); } } android/app/src/com/android/bluetooth/avrcp/mockable/MediaBrowserFactory.java 0 → 100644 +52 −0 Original line number Diff line number Diff line /* * Copyright 2018 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.content.ComponentName; import android.content.Context; import android.os.Bundle; import com.android.internal.annotations.VisibleForTesting; /** * Provide a method to inject custom MediaBrowser objects for testing. By using the factory * methods instead of calling the constructor of MediaBrowser directly, we can inject a custom * MediaBrowser that can be used with JUnit and Mockito to set expectations and validate * behaviour in tests. */ public final class MediaBrowserFactory { private static MediaBrowser sInjectedBrowser; static MediaBrowser wrap(android.media.browse.MediaBrowser delegate) { if (sInjectedBrowser != null) return sInjectedBrowser; return (delegate != null) ? new MediaBrowser(delegate) : null; } static MediaBrowser make(Context context, ComponentName serviceComponent, MediaBrowser.ConnectionCallback callback, Bundle rootHints) { if (sInjectedBrowser != null) { sInjectedBrowser.testInit(context, serviceComponent, callback, rootHints); return sInjectedBrowser; } return new MediaBrowser(context, serviceComponent, callback, rootHints); } @VisibleForTesting static void inject(MediaBrowser browser) { sInjectedBrowser = browser; } } android/app/src/com/android/bluetooth/avrcp/mockable/MediaController.java +29 −5 Original line number Diff line number Diff line /* * Copyright 2018 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.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; import android.content.Context; import android.media.MediaDescription; import android.media.MediaMetadata; import android.media.Rating; Loading @@ -16,22 +33,29 @@ import android.view.KeyEvent; import java.util.List; /** * Provide a mockable interface in order to test classes that use MediaController. * We need this class due to the fact that the MediaController class is marked as final and * there is no way to currently mock final classes in Android. Once this is possible this class * can be deleted. */ public class MediaController { @NonNull 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 MediaController(Context context, MediaSession.Token token) { mDelegate = new android.media.session.MediaController(context, token); mTransportDelegate = mDelegate.getTransportControls(); mTransportControls = new TransportControls(); } public android.media.session.MediaController getWrappedInstance() { return mDelegate; } Loading Loading
android/app/src/com/android/bluetooth/avrcp/Avrcp.java +2 −2 Original line number Diff line number Diff line Loading @@ -1800,7 +1800,7 @@ public final class Avrcp { for (android.media.session.MediaController controller : newControllers) { String packageName = controller.getPackageName(); if (DEBUG) { Log.v(TAG, "ActiveSession: " + MediaController.wrap(controller)); Log.v(TAG, "ActiveSession: " + MediaControllerFactory.wrap(controller)); } // Only use the first (highest priority) controller from each package if (updatedPackages.contains(packageName)) { Loading Loading @@ -2000,7 +2000,7 @@ public final class Avrcp { /** Add (or update) a player to the media player list given an active controller */ private boolean addMediaPlayerController(android.media.session.MediaController controller) { String packageName = controller.getPackageName(); MediaPlayerInfo info = new MediaPlayerInfo(MediaController.wrap(controller), MediaPlayerInfo info = new MediaPlayerInfo(MediaControllerFactory.wrap(controller), AvrcpConstants.PLAYER_TYPE_AUDIO, AvrcpConstants.PLAYER_SUBTYPE_NONE, getBluetoothPlayState(controller.getPlaybackState()), getFeatureBitMask(packageName), controller.getPackageName(), Loading
android/app/src/com/android/bluetooth/avrcp/BrowsedMediaPlayer.java +1 −2 Original line number Diff line number Diff line Loading @@ -318,8 +318,7 @@ class BrowsedMediaPlayer { mPathStack.push(mMediaId); } mMediaController = MediaController.wrap( new android.media.session.MediaController(mContext, token)); mMediaController = MediaControllerFactory.make(mContext, token); /* get root folder items */ mMediaBrowser.subscribe(mRootFolderUid, mFolderItemsCb); return; Loading
android/app/src/com/android/bluetooth/avrcp/mockable/MediaBrowser.java 0 → 100644 +165 −0 Original line number Diff line number Diff line /* * Copyright 2018 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.content.ComponentName; import android.content.Context; import android.media.session.MediaSession; import android.os.Bundle; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; /** * Provide a mockable interface in order to test classes that use MediaBrowser. * We need this class due to the fact that the MediaController class is marked as final and * there is no way to currently mock final classes in Android. Once this is possible this class * can be deleted. */ public class MediaBrowser { android.media.browse.MediaBrowser mDelegate; /** * Wrap a real MediaBrowser object */ public MediaBrowser(android.media.browse.MediaBrowser delegate) { mDelegate = delegate; } /** * Create a real MediaBrowser object and wrap it */ public MediaBrowser(Context context, ComponentName serviceComponent, ConnectionCallback callback, Bundle rootHints) { mDelegate = new android.media.browse.MediaBrowser(context, serviceComponent, callback, rootHints); } /** * Wrapper for MediaBrowser.ConnectionCallback */ public abstract static class ConnectionCallback extends android.media.browse.MediaBrowser.ConnectionCallback {} /** * Wrapper for MediaBrowser.ItemCallback */ public abstract static class ItemCallback extends android.media.browse.MediaBrowser.ItemCallback {} /** * Wrapper for MediaBrowser.SubscriptionCallback */ public abstract static class SubscriptionCallback extends android.media.browse.MediaBrowser.SubscriptionCallback {} /** * Wrapper for MediaBrowser.connect() */ public void connect() { mDelegate.connect(); } /** * Wrapper for MediaBrowser.disconnect() */ public void disconnect() { mDelegate.disconnect(); } /** * Wrapper for MediaBrowser.getExtras() */ public Bundle getExtras() { return mDelegate.getExtras(); } /** * Wrapper for MediaBrowser.getItem(String mediaId, ItemCallback callback) */ public void getItem(String mediaId, ItemCallback callback) { mDelegate.getItem(mediaId, callback); } /** * Wrapper for MediaBrowser.getRoot() */ public String getRoot() { return mDelegate.getRoot(); } /** * Wrapper for MediaBrowser.getServiceComponent() */ public ComponentName getServiceComponent() { return mDelegate.getServiceComponent(); } /** * Wrapper for MediaBrowser.getSessionToken() */ public MediaSession.Token getSessionToken() { return mDelegate.getSessionToken(); } /** * Wrapper for MediaBrowser.isConnected() */ public boolean isConnected() { return mDelegate.isConnected(); } /** * Wrapper for MediaBrowser.subscribe(String parentId, Bundle options, * SubscriptionCallback callback) */ public void subscribe(String parentId, Bundle options, SubscriptionCallback callback) { mDelegate.subscribe(parentId, options, callback); } /** * Wrapper for MediaBrowser.subscribe(String parentId, SubscriptionCallback callback) */ public void subscribe(String parentId, SubscriptionCallback callback) { mDelegate.subscribe(parentId, callback); } /** * Wrapper for MediaBrowser.unsubscribe(String parentId) */ public void unsubscribe(String parentId) { mDelegate.unsubscribe(parentId); } /** * Wrapper for MediaBrowser.unsubscribe(String parentId, SubscriptionCallback callback) */ public void unsubscribe(String parentId, SubscriptionCallback callback) { mDelegate.unsubscribe(parentId, callback); } /** * A function that allows Mockito to capture the constructor arguments when using * MediaBrowserFactory.make() */ @VisibleForTesting public void testInit(Context context, ComponentName serviceComponent, ConnectionCallback callback, Bundle rootHints) { // This is only used by Mockito to capture the constructor arguments on creation Log.wtfStack("AvrcpMockMediaBrowser", "This function should never be called"); } }
android/app/src/com/android/bluetooth/avrcp/mockable/MediaBrowserFactory.java 0 → 100644 +52 −0 Original line number Diff line number Diff line /* * Copyright 2018 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.content.ComponentName; import android.content.Context; import android.os.Bundle; import com.android.internal.annotations.VisibleForTesting; /** * Provide a method to inject custom MediaBrowser objects for testing. By using the factory * methods instead of calling the constructor of MediaBrowser directly, we can inject a custom * MediaBrowser that can be used with JUnit and Mockito to set expectations and validate * behaviour in tests. */ public final class MediaBrowserFactory { private static MediaBrowser sInjectedBrowser; static MediaBrowser wrap(android.media.browse.MediaBrowser delegate) { if (sInjectedBrowser != null) return sInjectedBrowser; return (delegate != null) ? new MediaBrowser(delegate) : null; } static MediaBrowser make(Context context, ComponentName serviceComponent, MediaBrowser.ConnectionCallback callback, Bundle rootHints) { if (sInjectedBrowser != null) { sInjectedBrowser.testInit(context, serviceComponent, callback, rootHints); return sInjectedBrowser; } return new MediaBrowser(context, serviceComponent, callback, rootHints); } @VisibleForTesting static void inject(MediaBrowser browser) { sInjectedBrowser = browser; } }
android/app/src/com/android/bluetooth/avrcp/mockable/MediaController.java +29 −5 Original line number Diff line number Diff line /* * Copyright 2018 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.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; import android.content.Context; import android.media.MediaDescription; import android.media.MediaMetadata; import android.media.Rating; Loading @@ -16,22 +33,29 @@ import android.view.KeyEvent; import java.util.List; /** * Provide a mockable interface in order to test classes that use MediaController. * We need this class due to the fact that the MediaController class is marked as final and * there is no way to currently mock final classes in Android. Once this is possible this class * can be deleted. */ public class MediaController { @NonNull 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 MediaController(Context context, MediaSession.Token token) { mDelegate = new android.media.session.MediaController(context, token); mTransportDelegate = mDelegate.getTransportControls(); mTransportControls = new TransportControls(); } public android.media.session.MediaController getWrappedInstance() { return mDelegate; } Loading