Merge "Use new media router2 api to get info media device list"

This commit is contained in:
TreeHugger Robot
2020-01-02 15:18:28 +00:00
committed by Android (Google) Code Review
8 changed files with 239 additions and 115 deletions

View File

@@ -17,9 +17,8 @@ package com.android.settingslib.media;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.widget.Toast;
import androidx.mediarouter.media.MediaRouter;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import com.android.settingslib.R;
import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -31,22 +30,28 @@ public class InfoMediaDevice extends MediaDevice {
private static final String TAG = "InfoMediaDevice";
private MediaRouter.RouteInfo mRouteInfo;
private final MediaRoute2Info mRouteInfo;
private final MediaRouter2Manager mRouterManager;
private final String mPackageName;
InfoMediaDevice(Context context, MediaRouter.RouteInfo info) {
InfoMediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
String packageName) {
super(context, MediaDeviceType.TYPE_CAST_DEVICE);
mRouterManager = routerManager;
mRouteInfo = info;
mPackageName = packageName;
initDeviceRecord();
}
@Override
public String getName() {
return mRouteInfo.getName();
return mRouteInfo.getName().toString();
}
@Override
public String getSummary() {
return null;
return mRouteInfo.getClientPackageName() != null
? mContext.getString(R.string.bluetooth_active_no_battery_level) : null;
}
@Override
@@ -63,15 +68,14 @@ public class InfoMediaDevice extends MediaDevice {
@Override
public boolean connect() {
//TODO(b/121083246): use SystemApi to transfer media
setConnectedRecord();
Toast.makeText(mContext, "This is cast device !", Toast.LENGTH_SHORT).show();
return false;
mRouterManager.selectRoute(mPackageName, mRouteInfo);
return true;
}
@Override
public void disconnect() {
//TODO(b/121083246): disconnected last select device
//TODO(b/144535188): disconnected last select device
}
@Override

View File

@@ -17,13 +17,16 @@ package com.android.settingslib.media;
import android.app.Notification;
import android.content.Context;
import android.util.Log;
import androidx.mediarouter.media.MediaRouteSelector;
import androidx.mediarouter.media.MediaRouter;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* InfoMediaManager provide interface to get InfoMediaDevice list.
*/
@@ -32,62 +35,75 @@ public class InfoMediaManager extends MediaManager {
private static final String TAG = "InfoMediaManager";
@VisibleForTesting
final MediaRouterCallback mMediaRouterCallback = new MediaRouterCallback();
final RouterManagerCallback mMediaRouterCallback = new RouterManagerCallback();
@VisibleForTesting
MediaRouteSelector mSelector;
final Executor mExecutor = Executors.newSingleThreadExecutor();
@VisibleForTesting
MediaRouter mMediaRouter;
MediaRouter2Manager mRouterManager;
private String mPackageName;
private MediaDevice mCurrentConnectedDevice;
InfoMediaManager(Context context, String packageName, Notification notification) {
public InfoMediaManager(Context context, String packageName, Notification notification) {
super(context, notification);
mMediaRouter = MediaRouter.getInstance(context);
mPackageName = packageName;
mSelector = new MediaRouteSelector.Builder()
.addControlCategory(getControlCategoryByPackageName(mPackageName))
.build();
mRouterManager = MediaRouter2Manager.getInstance(context);
if (packageName != null) {
mPackageName = packageName;
}
}
@Override
public void startScan() {
mMediaDevices.clear();
mMediaRouter.addCallback(mSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
mRouterManager.registerCallback(mExecutor, mMediaRouterCallback);
}
@VisibleForTesting
String getControlCategoryByPackageName(String packageName) {
//TODO(b/117129183): Use package name to get ControlCategory.
//Since api not ready, return fixed ControlCategory for prototype.
return "com.google.android.gms.cast.CATEGORY_CAST/4F8B3483";
return "com.google.android.gms.cast.CATEGORY_CAST";
}
@Override
public void stopScan() {
mMediaRouter.removeCallback(mMediaRouterCallback);
mRouterManager.unregisterCallback(mMediaRouterCallback);
}
class MediaRouterCallback extends MediaRouter.Callback {
@Override
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(route));
if (mediaDevice == null) {
mediaDevice = new InfoMediaDevice(mContext, route);
Log.d(TAG, "onRouteAdded() route : " + route.getName());
mMediaDevices.add(mediaDevice);
dispatchDeviceAdded(mediaDevice);
/**
* Get current device that played media.
* @return MediaDevice
*/
public MediaDevice getCurrentConnectedDevice() {
return mCurrentConnectedDevice;
}
class RouterManagerCallback extends MediaRouter2Manager.Callback {
private void refreshDevices() {
mMediaDevices.clear();
mCurrentConnectedDevice = null;
for (MediaRoute2Info route : mRouterManager.getAvailableRoutes(mPackageName)) {
final MediaDevice device = new InfoMediaDevice(mContext, mRouterManager, route,
mPackageName);
if (TextUtils.equals(route.getClientPackageName(), mPackageName)) {
mCurrentConnectedDevice = device;
}
mMediaDevices.add(device);
}
dispatchDeviceListAdded();
}
@Override
public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo route) {
final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(route));
if (mediaDevice != null) {
Log.d(TAG, "onRouteRemoved() route : " + route.getName());
mMediaDevices.remove(mediaDevice);
dispatchDeviceRemoved(mediaDevice);
public void onRoutesAdded(List<MediaRoute2Info> routes) {
refreshDevices();
}
@Override
public void onControlCategoriesChanged(String packageName, List<String> controlCategories) {
if (TextUtils.equals(mPackageName, packageName)) {
refreshDevices();
}
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settingslib.media;
import android.app.Notification;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.IntDef;
@@ -59,6 +60,8 @@ public class LocalMediaManager implements BluetoothCallback {
private Context mContext;
private BluetoothMediaManager mBluetoothMediaManager;
private LocalBluetoothManager mLocalBluetoothManager;
private InfoMediaManager mInfoMediaManager;
private String mPackageName;
@VisibleForTesting
List<MediaDevice> mMediaDevices = new ArrayList<>();
@@ -87,6 +90,7 @@ public class LocalMediaManager implements BluetoothCallback {
public LocalMediaManager(Context context, String packageName, Notification notification) {
mContext = context;
mPackageName = packageName;
mLocalBluetoothManager =
LocalBluetoothManager.getInstance(context, /* onInitCallback= */ null);
if (mLocalBluetoothManager == null) {
@@ -96,6 +100,7 @@ public class LocalMediaManager implements BluetoothCallback {
mBluetoothMediaManager =
new BluetoothMediaManager(context, mLocalBluetoothManager, notification);
mInfoMediaManager = new InfoMediaManager(context, packageName, notification);
}
@VisibleForTesting
@@ -104,6 +109,7 @@ public class LocalMediaManager implements BluetoothCallback {
mContext = context;
mLocalBluetoothManager = localBluetoothManager;
mBluetoothMediaManager = bluetoothMediaManager;
mInfoMediaManager = infoMediaManager;
}
/**
@@ -126,8 +132,7 @@ public class LocalMediaManager implements BluetoothCallback {
return;
}
//TODO(b/121083246): Update it once remote media API is ready.
if (mCurrentConnectedDevice != null && !(connectDevice instanceof InfoMediaDevice)) {
if (mCurrentConnectedDevice != null) {
mCurrentConnectedDevice.disconnect();
}
@@ -157,6 +162,10 @@ public class LocalMediaManager implements BluetoothCallback {
mMediaDevices.clear();
mBluetoothMediaManager.registerCallback(mMediaDeviceCallback);
mBluetoothMediaManager.startScan();
if (!TextUtils.isEmpty(mPackageName)) {
mInfoMediaManager.registerCallback(mMediaDeviceCallback);
mInfoMediaManager.startScan();
}
}
private void addPhoneDeviceIfNecessary() {
@@ -191,6 +200,10 @@ public class LocalMediaManager implements BluetoothCallback {
public void stopScan() {
mBluetoothMediaManager.unregisterCallback(mMediaDeviceCallback);
mBluetoothMediaManager.stopScan();
if (!TextUtils.isEmpty(mPackageName)) {
mInfoMediaManager.unregisterCallback(mMediaDeviceCallback);
mInfoMediaManager.stopScan();
}
}
/**
@@ -253,7 +266,9 @@ public class LocalMediaManager implements BluetoothCallback {
}
}
addPhoneDeviceIfNecessary();
mCurrentConnectedDevice = updateCurrentConnectedDevice();
final MediaDevice infoMediaDevice = mInfoMediaManager.getCurrentConnectedDevice();
mCurrentConnectedDevice = infoMediaDevice != null
? infoMediaDevice : updateCurrentConnectedDevice();
updatePhoneMediaDeviceSummary();
dispatchDeviceListUpdate();
}

View File

@@ -16,8 +16,7 @@
package com.android.settingslib.media;
import android.bluetooth.BluetoothDevice;
import androidx.mediarouter.media.MediaRouter;
import android.media.MediaRoute2Info;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -49,12 +48,12 @@ public class MediaDeviceUtils {
}
/**
* Use RouteInfo id to represent unique id
* Use MediaRoute2Info id to represent unique id
*
* @param route the RouteInfo
* @return RouteInfo id
* @param route the MediaRoute2Info
* @return MediaRoute2Info id
*/
public static String getId(MediaRouter.RouteInfo route) {
public static String getId(MediaRoute2Info route) {
return route.getId();
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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.settingslib.media;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import com.android.settingslib.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class InfoMediaDeviceTest {
private static final String TEST_PACKAGE_NAME = "com.test.packagename";
private static final String TEST_ID = "test_id";
private static final String TEST_NAME = "test_name";
@Mock
private MediaRouter2Manager mRouterManager;
@Mock
private MediaRoute2Info mRouteInfo;
private Context mContext;
private InfoMediaDevice mInfoMediaDevice;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mInfoMediaDevice = new InfoMediaDevice(mContext, mRouterManager, mRouteInfo,
TEST_PACKAGE_NAME);
}
@Test
public void getName_shouldReturnName() {
when(mRouteInfo.getName()).thenReturn(TEST_NAME);
assertThat(mInfoMediaDevice.getName()).isEqualTo(TEST_NAME);
}
@Test
public void getSummary_clientPackageNameIsNull_returnNull() {
when(mRouteInfo.getClientPackageName()).thenReturn(null);
assertThat(mInfoMediaDevice.getSummary()).isEqualTo(null);
}
@Test
public void getSummary_clientPackageNameIsNotNull_returnActive() {
when(mRouteInfo.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
assertThat(mInfoMediaDevice.getSummary())
.isEqualTo(mContext.getString(R.string.bluetooth_active_no_battery_level));
}
@Test
public void getId_shouldReturnId() {
when(mRouteInfo.getId()).thenReturn(TEST_ID);
assertThat(mInfoMediaDevice.getId()).isEqualTo(TEST_ID);
}
@Test
public void connect_shouldSelectRoute() {
mInfoMediaDevice.connect();
verify(mRouterManager).selectRoute(TEST_PACKAGE_NAME, mRouteInfo);
}
}

View File

@@ -23,9 +23,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import androidx.mediarouter.media.MediaRouteSelector;
import androidx.mediarouter.media.MediaRouter;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import org.junit.Before;
import org.junit.Test;
@@ -35,6 +34,9 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class InfoMediaManagerTest {
@@ -42,9 +44,7 @@ public class InfoMediaManagerTest {
private static final String TEST_ID = "test_id";
@Mock
private MediaRouter mMediaRouter;
@Mock
private MediaRouteSelector mSelector;
private MediaRouter2Manager mRouterManager;
private InfoMediaManager mInfoMediaManager;
private Context mContext;
@@ -55,82 +55,70 @@ public class InfoMediaManagerTest {
mContext = RuntimeEnvironment.application;
mInfoMediaManager = new InfoMediaManager(mContext, TEST_PACKAGE_NAME, null);
mInfoMediaManager.mMediaRouter = mMediaRouter;
mInfoMediaManager.mSelector = mSelector;
mInfoMediaManager.mRouterManager = mRouterManager;
}
@Test
public void stopScan_shouldRemoveCallback() {
mInfoMediaManager.stopScan();
verify(mMediaRouter).removeCallback(mInfoMediaManager.mMediaRouterCallback);
verify(mRouterManager).unregisterCallback(mInfoMediaManager.mMediaRouterCallback);
}
@Test
public void startScan_shouldAddCallback() {
mInfoMediaManager.startScan();
verify(mMediaRouter).addCallback(mSelector, mInfoMediaManager.mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
verify(mRouterManager).registerCallback(mInfoMediaManager.mExecutor,
mInfoMediaManager.mMediaRouterCallback);
}
@Test
public void onRouteAdded_mediaDeviceNotExistInList_addMediaDevice() {
final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
public void onRouteAdded_shouldAddMediaDevice() {
final MediaRoute2Info info = mock(MediaRoute2Info.class);
when(info.getId()).thenReturn(TEST_ID);
when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
final List<MediaRoute2Info> routes = new ArrayList<>();
routes.add(info);
when(mRouterManager.getAvailableRoutes(TEST_PACKAGE_NAME)).thenReturn(routes);
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
assertThat(mediaDevice).isNull();
mInfoMediaManager.mMediaRouterCallback.onRouteAdded(mMediaRouter, info);
mInfoMediaManager.mMediaRouterCallback.onRoutesAdded(routes);
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
assertThat(mInfoMediaManager.getCurrentConnectedDevice()).isEqualTo(infoDevice);
assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
}
@Test
public void onRouteAdded_mediaDeviceExistInList_doNothing() {
final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
public void onControlCategoriesChanged_samePackageName_shouldAddMediaDevice() {
final MediaRoute2Info info = mock(MediaRoute2Info.class);
when(info.getId()).thenReturn(TEST_ID);
final InfoMediaDevice infoDevice = new InfoMediaDevice(mContext, info);
mInfoMediaManager.mMediaDevices.add(infoDevice);
when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
final List<MediaRoute2Info> routes = new ArrayList<>();
routes.add(info);
when(mRouterManager.getAvailableRoutes(TEST_PACKAGE_NAME)).thenReturn(routes);
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
final int size = mInfoMediaManager.mMediaDevices.size();
assertThat(mediaDevice).isNotNull();
mInfoMediaManager.mMediaRouterCallback.onRouteAdded(mMediaRouter, info);
assertThat(mInfoMediaManager.mMediaDevices).hasSize(size);
}
@Test
public void onRouteRemoved_mediaDeviceExistInList_removeMediaDevice() {
final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
when(info.getId()).thenReturn(TEST_ID);
final InfoMediaDevice infoDevice = new InfoMediaDevice(mContext, info);
mInfoMediaManager.mMediaDevices.add(infoDevice);
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
assertThat(mediaDevice).isNotNull();
assertThat(mInfoMediaManager.mMediaDevices).hasSize(1);
mInfoMediaManager.mMediaRouterCallback.onRouteRemoved(mMediaRouter, info);
assertThat(mInfoMediaManager.mMediaDevices).isEmpty();
}
@Test
public void onRouteRemoved_mediaDeviceNotExistInList_doNothing() {
final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
when(info.getId()).thenReturn(TEST_ID);
final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
final int size = mInfoMediaManager.mMediaDevices.size();
assertThat(mediaDevice).isNull();
mInfoMediaManager.mMediaRouterCallback.onRouteRemoved(mMediaRouter, info);
mInfoMediaManager.mMediaRouterCallback.onControlCategoriesChanged(TEST_PACKAGE_NAME, null);
assertThat(mInfoMediaManager.mMediaDevices).hasSize(size);
final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
assertThat(mInfoMediaManager.getCurrentConnectedDevice()).isEqualTo(infoDevice);
assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
}
@Test
public void onControlCategoriesChanged_differentPackageName_doNothing() {
mInfoMediaManager.mMediaRouterCallback.onControlCategoriesChanged("com.fake.play", null);
assertThat(mInfoMediaManager.mMediaDevices).hasSize(0);
}
}

View File

@@ -22,8 +22,8 @@ import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import androidx.mediarouter.media.MediaRouter;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -56,6 +56,7 @@ public class MediaDeviceTest {
private static final String ROUTER_ID_1 = "RouterId_1";
private static final String ROUTER_ID_2 = "RouterId_2";
private static final String ROUTER_ID_3 = "RouterId_3";
private static final String TEST_PACKAGE_NAME = "com.test.playmusic";
private final BluetoothClass mHeadreeClass =
new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
private final BluetoothClass mCarkitClass =
@@ -76,11 +77,11 @@ public class MediaDeviceTest {
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
@Mock
private MediaRouter.RouteInfo mRouteInfo1;
private MediaRoute2Info mRouteInfo1;
@Mock
private MediaRouter.RouteInfo mRouteInfo2;
private MediaRoute2Info mRouteInfo2;
@Mock
private MediaRouter.RouteInfo mRouteInfo3;
private MediaRoute2Info mRouteInfo3;
@Mock
private LocalBluetoothProfileManager mProfileManager;
@Mock
@@ -99,6 +100,7 @@ public class MediaDeviceTest {
private InfoMediaDevice mInfoMediaDevice3;
private List<MediaDevice> mMediaDevices = new ArrayList<>();
private PhoneMediaDevice mPhoneMediaDevice;
private MediaRouter2Manager mMediaRouter2Manager;
@Before
public void setUp() {
@@ -134,9 +136,13 @@ public class MediaDeviceTest {
mBluetoothMediaDevice1 = new BluetoothMediaDevice(mContext, mCachedDevice1);
mBluetoothMediaDevice2 = new BluetoothMediaDevice(mContext, mCachedDevice2);
mBluetoothMediaDevice3 = new BluetoothMediaDevice(mContext, mCachedDevice3);
mInfoMediaDevice1 = new InfoMediaDevice(mContext, mRouteInfo1);
mInfoMediaDevice2 = new InfoMediaDevice(mContext, mRouteInfo2);
mInfoMediaDevice3 = new InfoMediaDevice(mContext, mRouteInfo3);
mMediaRouter2Manager = MediaRouter2Manager.getInstance(mContext);
mInfoMediaDevice1 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo1,
TEST_PACKAGE_NAME);
mInfoMediaDevice2 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo2,
TEST_PACKAGE_NAME);
mInfoMediaDevice3 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo3,
TEST_PACKAGE_NAME);
mPhoneMediaDevice = new PhoneMediaDevice(mContext, mLocalBluetoothManager);
}
@@ -364,5 +370,4 @@ public class MediaDeviceTest {
assertThat(mMediaDevices.get(5)).isEqualTo(mBluetoothMediaDevice1);
assertThat(mMediaDevices.get(6)).isEqualTo(mBluetoothMediaDevice2);
}
}

View File

@@ -21,8 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothDevice;
import androidx.mediarouter.media.MediaRouter;
import android.media.MediaRoute2Info;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -44,7 +43,7 @@ public class MediaDeviceUtilsTest {
@Mock
private BluetoothDevice mBluetoothDevice;
@Mock
private MediaRouter.RouteInfo mRouteInfo;
private MediaRoute2Info mRouteInfo;
@Before
public void setUp() {