From bd0dd4941c988be161c83e70c256a5cb6114d1fa Mon Sep 17 00:00:00 2001 From: hughchen Date: Tue, 8 Jan 2019 14:34:10 +0800 Subject: [PATCH 1/3] Add onConnectedDeviceChanged() onServiceConnected() callback - Add onConnectedDeviceChanged() callback to notify MediaDevice to change their connect state. - Add onServiceConnected() to handle profile not ready case. The profile may not ready when calling startScan(). Device status are all disconnected since profiles are not ready to connected. In this case, we observe onServiceConnected() in LocalBluetoothProfileManager. When A2dpProfile or HearingAidProfile is connected will call buildBluetoothDeviceList() again to find the connected devices. Bug: 121083246 Test: make -j50 RunSettingsLibRoboTests Change-Id: I6d8bacb9bbd2221eb8c97bbd0419b4e8c9d8dfea --- .../settingslib/bluetooth/A2dpProfile.java | 1 + .../bluetooth/HearingAidProfile.java | 2 +- .../media/BluetoothMediaDevice.java | 10 +- .../media/BluetoothMediaManager.java | 81 +++++++++++------ .../settingslib/media/InfoMediaDevice.java | 15 +-- .../settingslib/media/InfoMediaManager.java | 26 +++--- .../settingslib/media/LocalMediaManager.java | 91 ++++++++++++++++--- .../settingslib/media/MediaDevice.java | 16 +--- .../settingslib/media/MediaManager.java | 13 ++- .../settingslib/media/PhoneMediaDevice.java | 12 ++- .../settingslib/media/MediaDeviceTest.java | 15 +++ 11 files changed, 195 insertions(+), 87 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java index 24d7011d9a354..c05915685e838 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java @@ -74,6 +74,7 @@ public class A2dpProfile implements LocalBluetoothProfile { device.refresh(); } mIsProfileReady=true; + mProfileManager.callServiceConnectedListeners(); } public void onServiceDisconnected(int profile) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java index 577d98d934052..77dfbe9944888 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java @@ -71,8 +71,8 @@ public class HearingAidProfile implements LocalBluetoothProfile { // Check current list of CachedDevices to see if any are Hearing Aid devices. mDeviceManager.updateHearingAidsDevices(); - mIsProfileReady=true; + mProfileManager.callServiceConnectedListeners(); } public void onServiceDisconnected(int profile) { diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java index 959f9b24133cf..a5c6f0c28e78e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java @@ -54,17 +54,17 @@ public class BluetoothMediaDevice extends MediaDevice { } @Override - public void connect() { + public boolean connect() { //TODO(b/117129183): add callback to notify LocalMediaManager connection state. - mIsConnected = mCachedDevice.setActive(); - super.connect(); - Log.d(TAG, "connect() device : " + getName() + ", is selected : " + mIsConnected); + final boolean isConnected = mCachedDevice.setActive(); + setConnectedRecord(); + Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected); + return isConnected; } @Override public void disconnect() { //TODO(b/117129183): disconnected last select device - mIsConnected = false; } /** diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java index ab1cca0084c45..fa2dd887bd3d1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java @@ -18,6 +18,7 @@ package com.android.settingslib.media; import android.app.Notification; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; import android.content.Context; import android.util.Log; @@ -35,36 +36,48 @@ import java.util.List; /** * BluetoothMediaManager provide interface to get Bluetooth device list. */ -public class BluetoothMediaManager extends MediaManager implements BluetoothCallback { +public class BluetoothMediaManager extends MediaManager implements BluetoothCallback, + LocalBluetoothProfileManager.ServiceListener { private static final String TAG = "BluetoothMediaManager"; - private final DeviceAttributeChangeCallback mCachedDeviceCallback = - new DeviceAttributeChangeCallback(); - private LocalBluetoothManager mLocalBluetoothManager; private LocalBluetoothProfileManager mProfileManager; + private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager; private MediaDevice mLastAddedDevice; private MediaDevice mLastRemovedDevice; + private boolean mIsA2dpProfileReady = false; + private boolean mIsHearingAidProfileReady = false; + BluetoothMediaManager(Context context, LocalBluetoothManager localBluetoothManager, Notification notification) { super(context, notification); mLocalBluetoothManager = localBluetoothManager; mProfileManager = mLocalBluetoothManager.getProfileManager(); + mCachedBluetoothDeviceManager = mLocalBluetoothManager.getCachedDeviceManager(); } @Override public void startScan() { - mMediaDevices.clear(); mLocalBluetoothManager.getEventManager().registerCallback(this); buildBluetoothDeviceList(); dispatchDeviceListAdded(); + + // The profile may not ready when calling startScan(). + // Device status are all disconnected since profiles are not ready to connected. + // In this case, we observe onServiceConnected() in LocalBluetoothProfileManager. + // When A2dpProfile or HearingAidProfile is connected will call buildBluetoothDeviceList() + // again to find the connected devices. + if (!mIsA2dpProfileReady || !mIsHearingAidProfileReady) { + mProfileManager.addServiceListener(this); + } } private void buildBluetoothDeviceList() { + mMediaDevices.clear(); addConnectedA2dpDevices(); addConnectedHearingAidDevices(); } @@ -77,12 +90,10 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall } final List devices = a2dpProfile.getConnectedDevices(); - final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = - mLocalBluetoothManager.getCachedDeviceManager(); for (BluetoothDevice device : devices) { final CachedBluetoothDevice cachedDevice = - cachedBluetoothDeviceManager.findDevice(device); + mCachedBluetoothDeviceManager.findDevice(device); if (cachedDevice == null) { Log.w(TAG, "Can't found CachedBluetoothDevice : " + device.getName()); @@ -96,6 +107,8 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall addMediaDevice(cachedDevice); } } + + mIsA2dpProfileReady = a2dpProfile.isProfileReady(); } private void addConnectedHearingAidDevices() { @@ -107,12 +120,10 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall final List devicesHiSyncIds = new ArrayList<>(); final List devices = hapProfile.getConnectedDevices(); - final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = - mLocalBluetoothManager.getCachedDeviceManager(); for (BluetoothDevice device : devices) { final CachedBluetoothDevice cachedDevice = - cachedBluetoothDeviceManager.findDevice(device); + mCachedBluetoothDeviceManager.findDevice(device); if (cachedDevice == null) { Log.w(TAG, "Can't found CachedBluetoothDevice : " + device.getName()); @@ -130,13 +141,14 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall addMediaDevice(cachedDevice); } } + + mIsHearingAidProfileReady = hapProfile.isProfileReady(); } private void addMediaDevice(CachedBluetoothDevice cachedDevice) { MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice)); if (mediaDevice == null) { mediaDevice = new BluetoothMediaDevice(mContext, cachedDevice); - cachedDevice.registerCallback(mCachedDeviceCallback); mLastAddedDevice = mediaDevice; mMediaDevices.add(mediaDevice); } @@ -145,16 +157,6 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall @Override public void stopScan() { mLocalBluetoothManager.getEventManager().unregisterCallback(this); - unregisterCachedDeviceCallback(); - } - - private void unregisterCachedDeviceCallback() { - for (MediaDevice device : mMediaDevices) { - if (device instanceof BluetoothMediaDevice) { - ((BluetoothMediaDevice) device).getCachedDevice() - .unregisterCallback(mCachedDeviceCallback); - } - } } @Override @@ -166,8 +168,6 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall final List removeDevicesList = new ArrayList<>(); for (MediaDevice device : mMediaDevices) { if (device instanceof BluetoothMediaDevice) { - ((BluetoothMediaDevice) device).getCachedDevice() - .unregisterCallback(mCachedDeviceCallback); removeDevicesList.add(device); } } @@ -212,7 +212,6 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall private void removeMediaDevice(CachedBluetoothDevice cachedDevice) { final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice)); if (mediaDevice != null) { - cachedDevice.unregisterCallback(mCachedDeviceCallback); mLastRemovedDevice = mediaDevice; mMediaDevices.remove(mediaDevice); } @@ -252,10 +251,34 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall dispatchDeviceRemoved(cachedDevice); } } - class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback { - @Override - public void onDeviceAttributesChanged() { - dispatchDeviceAttributesChanged(); + + @Override + public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { + Log.d(TAG, "onActiveDeviceChanged : device : " + + activeDevice + ", profile : " + bluetoothProfile); + if (BluetoothProfile.HEARING_AID == bluetoothProfile + || BluetoothProfile.A2DP == bluetoothProfile) { + final String id = activeDevice == null + ? PhoneMediaDevice.ID : MediaDeviceUtils.getId(activeDevice); + dispatchConnectedDeviceChanged(id); } } + + @Override + public void onServiceConnected() { + if (!mIsA2dpProfileReady || !mIsHearingAidProfileReady) { + buildBluetoothDeviceList(); + dispatchDeviceListAdded(); + } + + //Remove the listener once a2dpProfile and hearingAidProfile are ready. + if (mIsA2dpProfileReady && mIsHearingAidProfileReady) { + mProfileManager.removeServiceListener(this); + } + } + + @Override + public void onServiceDisconnected() { + + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java index 21a81e03037ae..04f70cc676d98 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java @@ -16,6 +16,7 @@ package com.android.settingslib.media; import android.content.Context; +import android.widget.Toast; import androidx.mediarouter.media.MediaRouter; @@ -43,7 +44,7 @@ public class InfoMediaDevice extends MediaDevice { @Override public int getIcon() { - //TODO(b/117129183): This is not final icon for cast device, just for demo. + //TODO(b/121083246): This is not final icon for cast device, just for demo. return R.drawable.ic_settings_print; } @@ -53,15 +54,15 @@ public class InfoMediaDevice extends MediaDevice { } @Override - public void connect() { - //TODO(b/117129183): use MediaController2 to transfer media - mIsConnected = true; - super.connect(); + 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; } @Override public void disconnect() { - //TODO(b/117129183): disconnected last select device - mIsConnected = false; + //TODO(b/121083246): disconnected last select device } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index 6907238082fcd..bc8e2c35291d3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -22,6 +22,8 @@ import android.util.Log; import androidx.mediarouter.media.MediaRouteSelector; import androidx.mediarouter.media.MediaRouter; +import com.android.internal.annotations.VisibleForTesting; + /** * InfoMediaManager provide interface to get InfoMediaDevice list. */ @@ -29,9 +31,13 @@ public class InfoMediaManager extends MediaManager { private static final String TAG = "InfoMediaManager"; - private final MediaRouterCallback mMediaRouterCallback = new MediaRouterCallback(); + @VisibleForTesting + final MediaRouterCallback mMediaRouterCallback = new MediaRouterCallback(); + @VisibleForTesting + MediaRouteSelector mSelector; + @VisibleForTesting + MediaRouter mMediaRouter; - private MediaRouter mMediaRouter; private String mPackageName; InfoMediaManager(Context context, String packageName, Notification notification) { @@ -39,24 +45,20 @@ public class InfoMediaManager extends MediaManager { mMediaRouter = MediaRouter.getInstance(context); mPackageName = packageName; + mSelector = new MediaRouteSelector.Builder() + .addControlCategory(getControlCategoryByPackageName(mPackageName)) + .build(); } @Override public void startScan() { mMediaDevices.clear(); - startScanCastDevice(); - } - - private void startScanCastDevice() { - final MediaRouteSelector selector = new MediaRouteSelector.Builder() - .addControlCategory(getControlCategoryByPackageName(mPackageName)) - .build(); - - mMediaRouter.addCallback(selector, mMediaRouterCallback, + mMediaRouter.addCallback(mSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } - private String getControlCategoryByPackageName(String packageName) { + @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"; diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index c9479d44f7919..44d945a9ee0e2 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -16,12 +16,15 @@ package com.android.settingslib.media; import android.app.Notification; +import android.bluetooth.BluetoothProfile; import android.content.Context; import android.util.Log; import androidx.annotation.IntDef; +import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.bluetooth.BluetoothCallback; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; import java.lang.annotation.Retention; @@ -50,16 +53,20 @@ public class LocalMediaManager implements BluetoothCallback { } private final Collection mCallbacks = new ArrayList<>(); - private final MediaDeviceCallback mMediaDeviceCallback = new MediaDeviceCallback(); + @VisibleForTesting + final MediaDeviceCallback mMediaDeviceCallback = new MediaDeviceCallback(); private Context mContext; - private List mMediaDevices = new ArrayList<>(); private BluetoothMediaManager mBluetoothMediaManager; private InfoMediaManager mInfoMediaManager; - private LocalBluetoothManager mLocalBluetoothManager; - private MediaDevice mLastConnectedDevice; - private MediaDevice mPhoneDevice; + + @VisibleForTesting + List mMediaDevices = new ArrayList<>(); + @VisibleForTesting + MediaDevice mPhoneDevice; + @VisibleForTesting + MediaDevice mCurrentConnectedDevice; /** * Register to start receiving callbacks for MediaDevice events. @@ -93,28 +100,40 @@ public class LocalMediaManager implements BluetoothCallback { mInfoMediaManager = new InfoMediaManager(context, packageName, notification); } + @VisibleForTesting + LocalMediaManager(Context context, LocalBluetoothManager localBluetoothManager, + BluetoothMediaManager bluetoothMediaManager, InfoMediaManager infoMediaManager) { + mContext = context; + mLocalBluetoothManager = localBluetoothManager; + mBluetoothMediaManager = bluetoothMediaManager; + mInfoMediaManager = infoMediaManager; + } + /** * Connect the MediaDevice to transfer media * @param connectDevice the MediaDevice */ public void connectDevice(MediaDevice connectDevice) { - if (connectDevice == mLastConnectedDevice) { + final MediaDevice device = getMediaDeviceById(mMediaDevices, connectDevice.getId()); + if (device == mCurrentConnectedDevice) { + Log.d(TAG, "connectDevice() this device all ready connected! : " + device.getName()); return; } - if (mLastConnectedDevice != null) { - mLastConnectedDevice.disconnect(); + //TODO(b/121083246): Update it once remote media API is ready. + if (mCurrentConnectedDevice != null && !(connectDevice instanceof InfoMediaDevice)) { + mCurrentConnectedDevice.disconnect(); } - connectDevice.connect(); - if (connectDevice.isConnected()) { - mLastConnectedDevice = connectDevice; + final boolean isConnected = device.connect(); + if (isConnected) { + mCurrentConnectedDevice = device; } - final int state = connectDevice.isConnected() + final int state = isConnected ? MediaDeviceState.STATE_CONNECTED : MediaDeviceState.STATE_DISCONNECTED; - dispatchSelectedDeviceStateChanged(connectDevice, state); + dispatchSelectedDeviceStateChanged(device, state); } void dispatchSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state) { @@ -189,6 +208,31 @@ public class LocalMediaManager implements BluetoothCallback { return null; } + /** + * Find the current connected MediaDevice. + * + * @return MediaDevice + */ + public MediaDevice getCurrentConnectedDevice() { + return mCurrentConnectedDevice; + } + + private MediaDevice updateCurrentConnectedDevice() { + for (MediaDevice device : mMediaDevices) { + if (device instanceof BluetoothMediaDevice) { + if (isConnected(((BluetoothMediaDevice) device).getCachedDevice())) { + return device; + } + } + } + return mMediaDevices.contains(mPhoneDevice) ? mPhoneDevice : null; + } + + private boolean isConnected(CachedBluetoothDevice device) { + return device.isActiveDevice(BluetoothProfile.A2DP) + || device.isActiveDevice(BluetoothProfile.HEARING_AID); + } + class MediaDeviceCallback implements MediaManager.MediaDeviceCallback { @Override public void onDeviceAdded(MediaDevice device) { @@ -201,8 +245,13 @@ public class LocalMediaManager implements BluetoothCallback { @Override public void onDeviceListAdded(List devices) { - mMediaDevices.addAll(devices); + for (MediaDevice device : devices) { + if (getMediaDeviceById(mMediaDevices, device.getId()) == null) { + mMediaDevices.add(device); + } + } addPhoneDeviceIfNecessary(); + mCurrentConnectedDevice = updateCurrentConnectedDevice(); dispatchDeviceListUpdate(); } @@ -226,6 +275,20 @@ public class LocalMediaManager implements BluetoothCallback { public void onDeviceAttributesChanged() { dispatchDeviceListUpdate(); } + + @Override + public void onConnectedDeviceChanged(String id) { + final MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id); + + if (connectDevice == mCurrentConnectedDevice) { + Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected! : " + + connectDevice.getName()); + return; + } + mCurrentConnectedDevice = connectDevice; + + dispatchDeviceListUpdate(); + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java index 33b621cb28da0..f35c30edd16af 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java @@ -41,7 +41,6 @@ public abstract class MediaDevice implements Comparable { private int mConnectedRecord; - protected boolean mIsConnected = false; protected Context mContext; protected int mType; @@ -56,15 +55,6 @@ public abstract class MediaDevice implements Comparable { getId()); } - /** - * Check the MediaDevice is be connected to transfer. - * - * @return true if the MediaDevice is be connected to transfer, false otherwise. - */ - public boolean isConnected() { - return mIsConnected; - } - /** * Get name from MediaDevice. * @@ -87,8 +77,12 @@ public abstract class MediaDevice implements Comparable { /** * Transfer MediaDevice for media + * + * @return result of transfer media */ - public void connect() { + public abstract boolean connect(); + + void setConnectedRecord() { mConnectedRecord++; ConnectionRecordManager.getInstance().setConnectionRecord(mContext, getId(), mConnectedRecord); diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java index 72b6b09d637ea..2c3a96cafa562 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java @@ -96,7 +96,7 @@ public abstract class MediaManager { protected void dispatchDeviceListAdded() { synchronized (mCallbacks) { for (MediaDeviceCallback callback : mCallbacks) { - callback.onDeviceListAdded(mMediaDevices); + callback.onDeviceListAdded(new ArrayList<>(mMediaDevices)); } } } @@ -109,10 +109,10 @@ public abstract class MediaManager { } } - protected void dispatchDeviceAttributesChanged() { + protected void dispatchConnectedDeviceChanged(String id) { synchronized (mCallbacks) { for (MediaDeviceCallback callback : mCallbacks) { - callback.onDeviceAttributesChanged(); + callback.onConnectedDeviceChanged(id); } } } @@ -153,5 +153,12 @@ public abstract class MediaManager { * Callback for notifying MediaDevice attributes is changed. */ void onDeviceAttributesChanged(); + + /** + * Callback for notifying connected MediaDevice is changed. + * + * @param id the id of MediaDevice + */ + void onConnectedDeviceChanged(String id); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java index e0f3c2ff76923..c808214dbcf4f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java @@ -62,20 +62,22 @@ public class PhoneMediaDevice extends MediaDevice { } @Override - public void connect() { + public boolean connect() { final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile(); final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile(); + boolean isConnected = false; + if (hapProfile != null && a2dpProfile != null) { - mIsConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null); - super.connect(); + isConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null); + setConnectedRecord(); } - Log.d(TAG, "connect() device : " + getName() + ", is selected : " + mIsConnected); + Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected); + return isConnected; } @Override public void disconnect() { //TODO(b/117129183): disconnected last select device - mIsConnected = false; } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java index 9bbdd0102fad6..fc514f0ac25cb 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java @@ -25,8 +25,11 @@ import android.content.Context; import androidx.mediarouter.media.MediaRouter; +import com.android.settingslib.bluetooth.A2dpProfile; import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.HearingAidProfile; import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import org.junit.Before; import org.junit.Test; @@ -78,6 +81,14 @@ public class MediaDeviceTest { private MediaRouter.RouteInfo mRouteInfo2; @Mock private MediaRouter.RouteInfo mRouteInfo3; + @Mock + private LocalBluetoothProfileManager mProfileManager; + @Mock + private HearingAidProfile mHapProfile; + @Mock + private A2dpProfile mA2dpProfile; + @Mock + private BluetoothDevice mDevice; private BluetoothMediaDevice mBluetoothMediaDevice1; private BluetoothMediaDevice mBluetoothMediaDevice2; @@ -109,6 +120,10 @@ public class MediaDeviceTest { when(mRouteInfo1.getName()).thenReturn(DEVICE_NAME_1); when(mRouteInfo2.getName()).thenReturn(DEVICE_NAME_2); when(mRouteInfo3.getName()).thenReturn(DEVICE_NAME_3); + when(mLocalBluetoothManager.getProfileManager()).thenReturn(mProfileManager); + when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); + when(mProfileManager.getHearingAidProfile()).thenReturn(mHapProfile); + when(mA2dpProfile.getActiveDevice()).thenReturn(mDevice); mBluetoothMediaDevice1 = new BluetoothMediaDevice(mContext, mCachedDevice1); mBluetoothMediaDevice2 = new BluetoothMediaDevice(mContext, mCachedDevice2); From f4caa42830683dec86f4bc5864631afc61fd374b Mon Sep 17 00:00:00 2001 From: hughchen Date: Tue, 15 Jan 2019 17:58:23 +0800 Subject: [PATCH 2/3] Add constants for launch MediaOutput slice Bug: 121083246 Test: Build pass Change-Id: I5695fdca1d2fb0886cafe3d067c1ec65c6777106 --- .../media/MediaOutputSliceConstants.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java new file mode 100644 index 0000000000000..e600cb892c44c --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java @@ -0,0 +1,40 @@ +/* + * 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; + +/** + * Class to access MediaOutput constants. + */ +public class MediaOutputSliceConstants { + + /** + * Key for the Media output setting. + */ + public static final String KEY_MEDIA_OUTPUT = "media_output"; + + /** + * Activity Action: Show a settings dialog containing {@link MediaDevice} to transfer media. + */ + public static final String ACTION_MEDIA_OUTPUT = + "com.android.settings.panel.action.MEDIA_OUTPUT"; + + /** + * An string extra specifying a media package name. + */ + public static final String EXTRA_PACKAGE_NAME = + "com.android.settings.panel.extra.PACKAGE_NAME"; +} From 61c1c9f059a52f931b0b2aea99468a82f1a5469a Mon Sep 17 00:00:00 2001 From: hughchen Date: Thu, 17 Jan 2019 14:34:51 +0800 Subject: [PATCH 3/3] Add test case for media manager Bug: 121083246 Test: make -j50 RunSettingsLibRoboTests Change-Id: I60b11ddef57a303c154e5e04e6425cf632842d7a --- .../media/BluetoothMediaDeviceTest.java | 69 +++ .../media/BluetoothMediaManagerTest.java | 416 ++++++++++++++++++ .../media/InfoMediaManagerTest.java | 136 ++++++ .../media/LocalMediaManagerTest.java | 369 ++++++++++++++++ .../media/MediaDeviceUtilsTest.java | 67 +++ .../settingslib/media/MediaManagerTest.java | 130 ++++++ .../media/PhoneMediaDeviceTest.java | 100 +++++ 7 files changed, 1287 insertions(+) create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java new file mode 100644 index 0000000000000..e5d1b18177263 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java @@ -0,0 +1,69 @@ +/* + * 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.when; + +import android.bluetooth.BluetoothProfile; +import android.content.Context; + +import com.android.settingslib.bluetooth.CachedBluetoothDevice; + +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 BluetoothMediaDeviceTest { + + @Mock + private CachedBluetoothDevice mDevice; + + private Context mContext; + private BluetoothMediaDevice mBluetoothMediaDevice; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + when(mDevice.isActiveDevice(BluetoothProfile.A2DP)).thenReturn(true); + when(mDevice.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true); + + mBluetoothMediaDevice = new BluetoothMediaDevice(mContext, mDevice); + } + + @Test + public void connect_setActiveSuccess_isConnectedReturnTrue() { + when(mDevice.setActive()).thenReturn(true); + + assertThat(mBluetoothMediaDevice.connect()).isTrue(); + } + + @Test + public void connect_setActiveFail_isConnectedReturnFalse() { + when(mDevice.setActive()).thenReturn(false); + + assertThat(mBluetoothMediaDevice.connect()).isFalse(); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java new file mode 100644 index 0000000000000..a20e22bb4f26a --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java @@ -0,0 +1,416 @@ +/* + * 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.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.content.Context; + +import com.android.settingslib.bluetooth.A2dpProfile; +import com.android.settingslib.bluetooth.BluetoothEventManager; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.HearingAidProfile; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; + +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; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class BluetoothMediaManagerTest { + + private static final String TEST_ADDRESS = "11:22:33:44:55:66"; + + @Mock + private LocalBluetoothManager mLocalBluetoothManager; + @Mock + private LocalBluetoothProfileManager mProfileManager; + @Mock + private A2dpProfile mA2dpProfile; + @Mock + private HearingAidProfile mHapProfile; + @Mock + private CachedBluetoothDeviceManager mCachedDeviceManager; + @Mock + private BluetoothEventManager mEventManager; + @Mock + private MediaManager.MediaDeviceCallback mCallback; + + private BluetoothMediaManager mMediaManager; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + when(mLocalBluetoothManager.getProfileManager()).thenReturn(mProfileManager); + when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); + when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); + when(mProfileManager.getHearingAidProfile()).thenReturn(mHapProfile); + when(mLocalBluetoothManager.getEventManager()).thenReturn(mEventManager); + + mMediaManager = new BluetoothMediaManager(mContext, mLocalBluetoothManager, null); + } + + @Test + public void startScan_haveA2dpProfileConnectedBluetoothDevice_shouldAddDevice() { + final List devices = new ArrayList<>(); + final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class); + devices.add(bluetoothDevice); + + when(mA2dpProfile.getConnectedDevices()).thenReturn(devices); + when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice); + when(cachedDevice.isConnected()).thenReturn(true); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + mMediaManager.startScan(); + assertThat(mMediaManager.mMediaDevices).hasSize(devices.size()); + } + + @Test + public void startScan_haveA2dpProfileDisconnectedBluetoothDevice_shouldNotAddDevice() { + final List devices = new ArrayList<>(); + final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class); + devices.add(bluetoothDevice); + + when(mA2dpProfile.getConnectedDevices()).thenReturn(devices); + when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice); + when(cachedDevice.isConnected()).thenReturn(false); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + mMediaManager.startScan(); + assertThat(mMediaManager.mMediaDevices).isEmpty(); + } + + @Test + public void startScan_noA2dpProfileBluetoothDevice_shouldNotAddDevice() { + final List devices = new ArrayList<>(); + + when(mA2dpProfile.getConnectedDevices()).thenReturn(devices); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + mMediaManager.startScan(); + assertThat(mMediaManager.mMediaDevices).isEmpty(); + } + + @Test + public void startScan_haveHapProfileConnectedBluetoothDevice_shouldAddDevice() { + final List devices = new ArrayList<>(); + final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class); + devices.add(bluetoothDevice); + + when(mHapProfile.getConnectedDevices()).thenReturn(devices); + when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice); + when(cachedDevice.isConnected()).thenReturn(true); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + mMediaManager.startScan(); + assertThat(mMediaManager.mMediaDevices).hasSize(devices.size()); + } + + @Test + public void startScan_noHapProfileBluetoothDevice_shouldNotAddDevice() { + final List devices = new ArrayList<>(); + + when(mHapProfile.getConnectedDevices()).thenReturn(devices); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + mMediaManager.startScan(); + assertThat(mMediaManager.mMediaDevices).isEmpty(); + } + + @Test + public void starScan_a2dpAndHapProfileNotReady_shouldRegisterCallback() { + final Collection mDevices = new ArrayList<>(); + final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + mDevices.add(cachedDevice); + + when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices); + when(mA2dpProfile.isProfileReady()).thenReturn(false); + when(mHapProfile.isProfileReady()).thenReturn(false); + + mMediaManager.startScan(); + + verify(mProfileManager).addServiceListener(mMediaManager); + } + + @Test + public void starScan_a2dpAndHapProfileReady_shouldNotRegisterCallback() { + final Collection mDevices = new ArrayList<>(); + final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + mDevices.add(cachedDevice); + + when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices); + when(mA2dpProfile.isProfileReady()).thenReturn(true); + when(mHapProfile.isProfileReady()).thenReturn(true); + + mMediaManager.startScan(); + + verify(mProfileManager, never()).addServiceListener(mMediaManager); + } + + @Test + public void onServiceConnected_a2dpAndHapProfileNotReady_doNothing() { + final Collection mDevices = new ArrayList<>(); + final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + mDevices.add(cachedDevice); + + when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices); + when(mA2dpProfile.isProfileReady()).thenReturn(false); + when(mHapProfile.isProfileReady()).thenReturn(false); + + mMediaManager.startScan(); + mMediaManager.onServiceConnected(); + + verify(mProfileManager, never()).removeServiceListener(mMediaManager); + } + + @Test + public void onDeviceAttributesChanged_a2dpAndHapProfileReady_shouldUnregisterCallback() { + final Collection mDevices = new ArrayList<>(); + final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + mDevices.add(cachedDevice); + + when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices); + when(mA2dpProfile.isProfileReady()).thenReturn(true); + when(mHapProfile.isProfileReady()).thenReturn(true); + + mMediaManager.startScan(); + mMediaManager.onServiceConnected(); + + verify(mProfileManager).removeServiceListener(mMediaManager); + } + + @Test + public void onBluetoothStateChanged_bluetoothStateIsOn_callOnDeviceListAdded() { + mMediaManager.registerCallback(mCallback); + mMediaManager.onBluetoothStateChanged(BluetoothAdapter.STATE_ON); + + verify(mCallback).onDeviceListAdded(any()); + } + + @Test + public void onBluetoothStateChanged_bluetoothStateIsOff_callOnDeviceListRemoved() { + final BluetoothMediaDevice device1 = mock(BluetoothMediaDevice.class); + final BluetoothMediaDevice device2 = mock(BluetoothMediaDevice.class); + mMediaManager.mMediaDevices.add(device1); + mMediaManager.mMediaDevices.add(device2); + + mMediaManager.registerCallback(mCallback); + mMediaManager.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + verify(mCallback).onDeviceListRemoved(any()); + } + + @Test + public void onDeviceAdded_cachedDeviceIsConnected_callOnDeviceAdded() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + + when(device.isConnectedHearingAidDevice()).thenReturn(true); + when(device.isConnectedA2dpDevice()).thenReturn(true); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + mMediaManager.registerCallback(mCallback); + mMediaManager.onDeviceAdded(device); + + assertThat(mMediaManager.mMediaDevices).hasSize(1); + verify(mCallback).onDeviceAdded(any()); + + } + + @Test + public void onDeviceAdded_cachedDeviceIsDisconnected_doNothing() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + + when(device.isConnectedHearingAidDevice()).thenReturn(false); + when(device.isConnectedA2dpDevice()).thenReturn(false); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + mMediaManager.registerCallback(mCallback); + mMediaManager.onDeviceAdded(device); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + verify(mCallback, never()).onDeviceAdded(any()); + + } + + @Test + public void onDeviceDeleted_cachedDeviceIsConnected_doNothing() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class); + mMediaManager.mMediaDevices.add(bluetoothMediaDevice); + + when(device.isConnectedHearingAidDevice()).thenReturn(true); + when(device.isConnectedA2dpDevice()).thenReturn(true); + when(device.getAddress()).thenReturn(TEST_ADDRESS); + when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS); + + assertThat(mMediaManager.mMediaDevices).hasSize(1); + mMediaManager.registerCallback(mCallback); + mMediaManager.onDeviceDeleted(device); + + assertThat(mMediaManager.mMediaDevices).hasSize(1); + verify(mCallback, never()).onDeviceRemoved(any()); + } + + @Test + public void onDeviceDeleted_cachedDeviceIsDisconnected_callOnDeviceRemoved() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class); + mMediaManager.mMediaDevices.add(bluetoothMediaDevice); + + when(device.isConnectedHearingAidDevice()).thenReturn(false); + when(device.isConnectedA2dpDevice()).thenReturn(false); + when(device.getAddress()).thenReturn(TEST_ADDRESS); + when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS); + + assertThat(mMediaManager.mMediaDevices).hasSize(1); + mMediaManager.registerCallback(mCallback); + mMediaManager.onDeviceDeleted(device); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + verify(mCallback).onDeviceRemoved(any()); + } + + @Test + public void onProfileConnectionStateChanged_cachedDeviceIsConnect_callOnDeviceAdded() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + + when(device.isConnectedHearingAidDevice()).thenReturn(true); + when(device.isConnectedA2dpDevice()).thenReturn(true); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + mMediaManager.registerCallback(mCallback); + mMediaManager.onProfileConnectionStateChanged(device, 0, 0); + + assertThat(mMediaManager.mMediaDevices).hasSize(1); + verify(mCallback).onDeviceAdded(any()); + } + + @Test + public void onProfileConnectionStateChanged_cachedDeviceIsDisconnect_callOnDeviceRemoved() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class); + mMediaManager.mMediaDevices.add(bluetoothMediaDevice); + + when(device.isConnectedHearingAidDevice()).thenReturn(false); + when(device.isConnectedA2dpDevice()).thenReturn(false); + when(device.getAddress()).thenReturn(TEST_ADDRESS); + when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS); + + assertThat(mMediaManager.mMediaDevices).hasSize(1); + mMediaManager.registerCallback(mCallback); + mMediaManager.onProfileConnectionStateChanged(device, 0, 0); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + verify(mCallback).onDeviceRemoved(any()); + } + + @Test + public void onAclConnectionStateChanged_cachedDeviceIsConnect_callOnDeviceAdded() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + + when(device.isConnectedHearingAidDevice()).thenReturn(true); + when(device.isConnectedA2dpDevice()).thenReturn(true); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + mMediaManager.registerCallback(mCallback); + mMediaManager.onAclConnectionStateChanged(device, 0); + + assertThat(mMediaManager.mMediaDevices).hasSize(1); + verify(mCallback).onDeviceAdded(any()); + } + + @Test + public void onAclConnectionStateChanged_cachedDeviceIsDisconnect_callOnDeviceRemoved() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class); + mMediaManager.mMediaDevices.add(bluetoothMediaDevice); + + when(device.isConnectedHearingAidDevice()).thenReturn(false); + when(device.isConnectedA2dpDevice()).thenReturn(false); + when(device.getAddress()).thenReturn(TEST_ADDRESS); + when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS); + + assertThat(mMediaManager.mMediaDevices).hasSize(1); + mMediaManager.registerCallback(mCallback); + mMediaManager.onAclConnectionStateChanged(device, 0); + + assertThat(mMediaManager.mMediaDevices).isEmpty(); + verify(mCallback).onDeviceRemoved(any()); + } + + @Test + public void onActiveDeviceChanged_isHapProfile_callOnActiveDeviceChanged() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + + when(device.getAddress()).thenReturn(TEST_ADDRESS); + + mMediaManager.registerCallback(mCallback); + mMediaManager.onActiveDeviceChanged(device, BluetoothProfile.HEARING_AID); + + verify(mCallback).onConnectedDeviceChanged(any()); + } + + @Test + public void onActiveDeviceChanged_isA2dpProfile_callOnActiveDeviceChanged() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + + when(device.getAddress()).thenReturn(TEST_ADDRESS); + + mMediaManager.registerCallback(mCallback); + mMediaManager.onActiveDeviceChanged(device, BluetoothProfile.A2DP); + + verify(mCallback).onConnectedDeviceChanged(any()); + } + + @Test + public void onActiveDeviceChanged_isNotA2dpAndHapProfile_doNothing() { + final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + + when(device.getAddress()).thenReturn(TEST_ADDRESS); + + mMediaManager.registerCallback(mCallback); + mMediaManager.onActiveDeviceChanged(device, BluetoothProfile.HEALTH); + + verify(mCallback, never()).onConnectedDeviceChanged(any()); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java new file mode 100644 index 0000000000000..b11cf69b04f46 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java @@ -0,0 +1,136 @@ +/* + * 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.mock; +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 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 InfoMediaManagerTest { + + private static final String TEST_PACKAGE_NAME = "com.test.packagename"; + private static final String TEST_ID = "test_id"; + + @Mock + private MediaRouter mMediaRouter; + @Mock + private MediaRouteSelector mSelector; + + private InfoMediaManager mInfoMediaManager; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + mInfoMediaManager = new InfoMediaManager(mContext, TEST_PACKAGE_NAME, null); + mInfoMediaManager.mMediaRouter = mMediaRouter; + mInfoMediaManager.mSelector = mSelector; + } + + @Test + public void stopScan_shouldRemoveCallback() { + mInfoMediaManager.stopScan(); + + verify(mMediaRouter).removeCallback(mInfoMediaManager.mMediaRouterCallback); + } + + @Test + public void startScan_shouldAddCallback() { + mInfoMediaManager.startScan(); + + verify(mMediaRouter).addCallback(mSelector, mInfoMediaManager.mMediaRouterCallback, + MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); + } + + @Test + public void onRouteAdded_mediaDeviceNotExistInList_addMediaDevice() { + final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class); + when(info.getId()).thenReturn(TEST_ID); + + final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID); + assertThat(mediaDevice).isNull(); + + mInfoMediaManager.mMediaRouterCallback.onRouteAdded(mMediaRouter, info); + + final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0); + assertThat(infoDevice.getId()).isEqualTo(TEST_ID); + } + + @Test + public void onRouteAdded_mediaDeviceExistInList_doNothing() { + 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); + 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); + + assertThat(mInfoMediaManager.mMediaDevices).hasSize(size); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java new file mode 100644 index 0000000000000..355681401b9a8 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java @@ -0,0 +1,369 @@ +/* + * 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.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; + +import com.android.settingslib.bluetooth.A2dpProfile; +import com.android.settingslib.bluetooth.HearingAidProfile; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; + +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; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class LocalMediaManagerTest { + + private static final String TEST_DEVICE_ID_1 = "device_id_1"; + private static final String TEST_DEVICE_ID_2 = "device_id_2"; + private static final String TEST_DEVICE_ID_3 = "device_id_3"; + private static final String TEST_CURRENT_DEVICE_ID = "currentDevice_id"; + + @Mock + private BluetoothMediaManager mBluetoothMediaManager; + @Mock + private InfoMediaManager mInfoMediaManager; + @Mock + private LocalBluetoothManager mLocalBluetoothManager; + @Mock + private LocalMediaManager.DeviceCallback mCallback; + @Mock + private HearingAidProfile mHapProfile; + @Mock + private A2dpProfile mA2dpProfile; + @Mock + private LocalBluetoothProfileManager mLocalProfileManager; + + private Context mContext; + private LocalMediaManager mLocalMediaManager; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalProfileManager); + when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); + when(mLocalProfileManager.getHearingAidProfile()).thenReturn(mHapProfile); + + mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, + mBluetoothMediaManager, mInfoMediaManager); + } + + @Test + public void startScan_mediaDevicesListShouldBeClear() { + final MediaDevice device = mock(MediaDevice.class); + mLocalMediaManager.mMediaDevices.add(device); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(1); + mLocalMediaManager.startScan(); + assertThat(mLocalMediaManager.mMediaDevices).isEmpty(); + } + + @Test + public void connectDevice_deviceNotEqualCurrentConnectedDevice_connectDevice() { + final MediaDevice currentDevice = mock(MediaDevice.class); + final MediaDevice device = mock(MediaDevice.class); + mLocalMediaManager.mMediaDevices.add(currentDevice); + mLocalMediaManager.mMediaDevices.add(device); + mLocalMediaManager.mCurrentConnectedDevice = currentDevice; + + when(device.getId()).thenReturn(TEST_DEVICE_ID_1); + when(currentDevice.getId()).thenReturn(TEST_CURRENT_DEVICE_ID); + + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.connectDevice(device); + + verify(currentDevice).disconnect(); + verify(device).connect(); + verify(mCallback).onSelectedDeviceStateChanged(any(), + eq(LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED)); + } + + @Test + public void getMediaDeviceById_idExist_shouldReturnMediaDevice() { + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(device2); + + when(device1.getId()).thenReturn(TEST_DEVICE_ID_1); + when(device2.getId()).thenReturn(TEST_DEVICE_ID_2); + + final MediaDevice device = mLocalMediaManager + .getMediaDeviceById(mLocalMediaManager.mMediaDevices, TEST_DEVICE_ID_2); + + assertThat(device.getId()).isEqualTo(TEST_DEVICE_ID_2); + } + + @Test + public void getMediaDeviceById_idNotExist_shouldReturnNull() { + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(device2); + + when(device1.getId()).thenReturn(TEST_DEVICE_ID_1); + when(device2.getId()).thenReturn(TEST_DEVICE_ID_2); + + final MediaDevice device = mLocalMediaManager + .getMediaDeviceById(mLocalMediaManager.mMediaDevices, TEST_CURRENT_DEVICE_ID); + + assertThat(device).isNull(); + } + + @Test + public void onDeviceAdded_mediaDeviceAndPhoneDeviceNotExistInList_addBothDevice() { + final MediaDevice device = mock(MediaDevice.class); + + assertThat(mLocalMediaManager.mMediaDevices).isEmpty(); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceAdded(device); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + verify(mCallback).onDeviceListUpdate(any()); + } + + @Test + public void onDeviceAdded_mediaDeviceNotExistAndPhoneDeviceExistInList_addMediaDevice() { + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class); + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceAdded(device2); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(3); + verify(mCallback).onDeviceListUpdate(any()); + } + + @Test + public void onDeviceAdded_mediaDeviceAndPhoneDeviceExistInList_doNothing() { + final MediaDevice device1 = mock(MediaDevice.class); + mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class); + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceAdded(device1); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + verify(mCallback, never()).onDeviceListUpdate(any()); + } + + @Test + public void onDeviceListAdded_phoneDeviceNotExistInList_addPhoneDeviceAndDevicesList() { + final List devices = new ArrayList<>(); + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + devices.add(device1); + devices.add(device2); + + when(device1.getId()).thenReturn(TEST_DEVICE_ID_1); + when(device2.getId()).thenReturn(TEST_DEVICE_ID_2); + + assertThat(mLocalMediaManager.mMediaDevices).isEmpty(); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(3); + verify(mCallback).onDeviceListUpdate(any()); + } + + @Test + public void onDeviceListAdded_phoneDeviceExistInList_addDeviceList() { + final List devices = new ArrayList<>(); + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + final MediaDevice device3 = mock(MediaDevice.class); + mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class); + devices.add(device1); + devices.add(device2); + mLocalMediaManager.mMediaDevices.add(device3); + mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice); + + when(device1.getId()).thenReturn(TEST_DEVICE_ID_1); + when(device2.getId()).thenReturn(TEST_DEVICE_ID_2); + when(device3.getId()).thenReturn(TEST_DEVICE_ID_3); + when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id"); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(4); + verify(mCallback).onDeviceListUpdate(any()); + } + + @Test + public void onDeviceRemoved_phoneDeviceIsLastDeviceAfterRemoveMediaDevice_removeBothDevice() { + final MediaDevice device1 = mock(MediaDevice.class); + mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class); + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceRemoved(device1); + + assertThat(mLocalMediaManager.mMediaDevices).isEmpty(); + verify(mCallback).onDeviceListUpdate(any()); + } + + @Test + public void onDeviceRemoved_phoneDeviceNotLastDeviceAfterRemoveMediaDevice_removeMediaDevice() { + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class); + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(device2); + mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(3); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceRemoved(device2); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + verify(mCallback).onDeviceListUpdate(any()); + } + + @Test + public void onDeviceRemoved_removeMediaDeviceNotInList_doNothing() { + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class); + mLocalMediaManager.mMediaDevices.add(device2); + mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceRemoved(device1); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + verify(mCallback, never()).onDeviceListUpdate(any()); + } + + @Test + public void onDeviceListRemoved_phoneDeviceIsLastDeviceAfterRemoveDeviceList_removeAll() { + final List devices = new ArrayList<>(); + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class); + devices.add(device1); + devices.add(device2); + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(device2); + mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(3); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceListRemoved(devices); + + assertThat(mLocalMediaManager.mMediaDevices).isEmpty(); + verify(mCallback).onDeviceListUpdate(any()); + } + + @Test + public void onDeviceListRemoved_phoneDeviceNotLastDeviceAfterRemoveDeviceList_removeList() { + final List devices = new ArrayList<>(); + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + final MediaDevice device3 = mock(MediaDevice.class); + mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class); + devices.add(device1); + devices.add(device3); + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(device2); + mLocalMediaManager.mMediaDevices.add(device3); + mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(4); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceListRemoved(devices); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + verify(mCallback).onDeviceListUpdate(any()); + } + + @Test + public void onDeviceAttributesChanged_shouldDispatchDeviceListUpdate() { + mLocalMediaManager.registerCallback(mCallback); + + mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged(); + + verify(mCallback).onDeviceListUpdate(any()); + } + + @Test + public void onConnectedDeviceChanged_connectedAndCurrentDeviceAreDifferent_notifyThemChanged() { + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(device2); + mLocalMediaManager.mCurrentConnectedDevice = device1; + + when(device1.getId()).thenReturn(TEST_DEVICE_ID_1); + when(device2.getId()).thenReturn(TEST_DEVICE_ID_2); + + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_2); + + assertThat(mLocalMediaManager.getCurrentConnectedDevice()).isEqualTo(device2); + verify(mCallback).onDeviceListUpdate(any()); + } + + @Test + public void onConnectedDeviceChanged_connectedAndCurrentDeviceAreSame_doNothing() { + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(device2); + mLocalMediaManager.mCurrentConnectedDevice = device1; + + when(device1.getId()).thenReturn(TEST_DEVICE_ID_1); + when(device2.getId()).thenReturn(TEST_DEVICE_ID_2); + + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_1); + + verify(mCallback, never()).onDeviceListUpdate(any()); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java new file mode 100644 index 0000000000000..6e29e137c9f23 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java @@ -0,0 +1,67 @@ +/* + * 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.when; + +import androidx.mediarouter.media.MediaRouter; + +import com.android.settingslib.bluetooth.CachedBluetoothDevice; + +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; + +@RunWith(RobolectricTestRunner.class) +public class MediaDeviceUtilsTest { + + private static final String TEST_ADDRESS = "11:22:33:44:55:66"; + private static final String TEST_ROUTE_ID = "test_route_id"; + + @Mock + private CachedBluetoothDevice mDevice; + @Mock + private MediaRouter.RouteInfo mRouteInfo; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void getId_returnBluetoothDeviceAddress() { + when(mDevice.getAddress()).thenReturn(TEST_ADDRESS); + + final String id = MediaDeviceUtils.getId(mDevice); + + assertThat(id).isEqualTo(TEST_ADDRESS); + } + + @Test + public void getId_returnRouteInfoId() { + when(mRouteInfo.getId()).thenReturn(TEST_ROUTE_ID); + + final String id = MediaDeviceUtils.getId(mRouteInfo); + + assertThat(id).isEqualTo(TEST_ROUTE_ID); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java new file mode 100644 index 0000000000000..98eccb506f63e --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java @@ -0,0 +1,130 @@ +/* + * 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.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; + +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 MediaManagerTest { + + private static final String TEST_ID = "test_id"; + + @Mock + private MediaManager.MediaDeviceCallback mCallback; + @Mock + private MediaDevice mDevice; + + private MediaManager mMediaManager; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + when(mDevice.getId()).thenReturn(TEST_ID); + + mMediaManager = new MediaManager(mContext, null) { + @Override + public void startScan() { + + } + + @Override + public void stopScan() { + + } + }; + } + + @Test + public void dispatchDeviceAdded_registerCallback_shouldDispatchCallback() { + mMediaManager.registerCallback(mCallback); + + mMediaManager.dispatchDeviceAdded(mDevice); + + verify(mCallback).onDeviceAdded(mDevice); + } + + @Test + public void dispatchDeviceRemoved_registerCallback_shouldDispatchCallback() { + mMediaManager.registerCallback(mCallback); + + mMediaManager.dispatchDeviceRemoved(mDevice); + + verify(mCallback).onDeviceRemoved(mDevice); + } + + @Test + public void dispatchDeviceListAdded_registerCallback_shouldDispatchCallback() { + mMediaManager.registerCallback(mCallback); + + mMediaManager.dispatchDeviceListAdded(); + + verify(mCallback).onDeviceListAdded(any()); + } + + @Test + public void dispatchDeviceListRemoved_registerCallback_shouldDispatchCallback() { + mMediaManager.registerCallback(mCallback); + + mMediaManager.dispatchDeviceListRemoved(mMediaManager.mMediaDevices); + + verify(mCallback).onDeviceListRemoved(mMediaManager.mMediaDevices); + } + + @Test + public void dispatchActiveDeviceChanged_registerCallback_shouldDispatchCallback() { + mMediaManager.registerCallback(mCallback); + + mMediaManager.dispatchConnectedDeviceChanged(TEST_ID); + + verify(mCallback).onConnectedDeviceChanged(TEST_ID); + } + + @Test + public void findMediaDevice_idExist_shouldReturnMediaDevice() { + mMediaManager.mMediaDevices.add(mDevice); + + final MediaDevice device = mMediaManager.findMediaDevice(TEST_ID); + + assertThat(device.getId()).isEqualTo(mDevice.getId()); + } + + @Test + public void findMediaDevice_idNotExist_shouldReturnNull() { + mMediaManager.mMediaDevices.add(mDevice); + + final MediaDevice device = mMediaManager.findMediaDevice("123"); + + assertThat(device).isNull(); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java new file mode 100644 index 0000000000000..5ba33f569e441 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java @@ -0,0 +1,100 @@ +/* + * 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.when; + +import android.bluetooth.BluetoothDevice; +import android.content.Context; + +import com.android.settingslib.bluetooth.A2dpProfile; +import com.android.settingslib.bluetooth.HearingAidProfile; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; + +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 PhoneMediaDeviceTest { + + @Mock + private LocalBluetoothProfileManager mLocalProfileManager; + @Mock + private LocalBluetoothManager mLocalBluetoothManager; + @Mock + private HearingAidProfile mHapProfile; + @Mock + private A2dpProfile mA2dpProfile; + @Mock + private BluetoothDevice mDevice; + + private Context mContext; + private PhoneMediaDevice mPhoneMediaDevice; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalProfileManager); + when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); + when(mLocalProfileManager.getHearingAidProfile()).thenReturn(mHapProfile); + when(mA2dpProfile.getActiveDevice()).thenReturn(mDevice); + + mPhoneMediaDevice = new PhoneMediaDevice(mContext, mLocalBluetoothManager); + } + + @Test + public void connect_phoneDeviceSetActiveSuccess_isConnectedReturnTrue() { + when(mA2dpProfile.setActiveDevice(null)).thenReturn(true); + when(mHapProfile.setActiveDevice(null)).thenReturn(true); + + assertThat(mPhoneMediaDevice.connect()).isTrue(); + } + + @Test + public void connect_a2dpProfileSetActiveFail_isConnectedReturnFalse() { + when(mA2dpProfile.setActiveDevice(null)).thenReturn(false); + when(mHapProfile.setActiveDevice(null)).thenReturn(true); + + assertThat(mPhoneMediaDevice.connect()).isFalse(); + } + + @Test + public void connect_hearingAidProfileSetActiveFail_isConnectedReturnFalse() { + when(mA2dpProfile.setActiveDevice(null)).thenReturn(true); + when(mHapProfile.setActiveDevice(null)).thenReturn(false); + + assertThat(mPhoneMediaDevice.connect()).isFalse(); + } + + @Test + public void connect_hearingAidAndA2dpProfileSetActiveFail_isConnectedReturnFalse() { + when(mA2dpProfile.setActiveDevice(null)).thenReturn(false); + when(mHapProfile.setActiveDevice(null)).thenReturn(false); + + assertThat(mPhoneMediaDevice.connect()).isFalse(); + } +}