Loading packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java +29 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package com.android.settingslib.media; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.util.Log; Loading @@ -33,6 +35,13 @@ public class BluetoothMediaDevice extends MediaDevice { BluetoothMediaDevice(Context context, CachedBluetoothDevice device) { super(context, MediaDeviceType.TYPE_BLUETOOTH_DEVICE); mCachedDevice = device; initDeviceRecord(); buildConnectedState(device); } private void buildConnectedState(CachedBluetoothDevice device) { mIsConnected = device.isActiveDevice(BluetoothProfile.A2DP) || device.isActiveDevice(BluetoothProfile.HEARING_AID); } @Override Loading @@ -51,10 +60,16 @@ public class BluetoothMediaDevice extends MediaDevice { return MediaDeviceUtils.getId(mCachedDevice); } @Override public void notifyConnectedChanged() { buildConnectedState(mCachedDevice); } @Override public void 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); } Loading @@ -70,4 +85,18 @@ public class BluetoothMediaDevice extends MediaDevice { public CachedBluetoothDevice getCachedDevice() { return mCachedDevice; } @Override protected boolean isCarKitDevice() { final BluetoothClass bluetoothClass = mCachedDevice.getDevice().getBluetoothClass(); if (bluetoothClass != null) { switch (bluetoothClass.getDeviceClass()) { // Both are common CarKit class case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: return true; } } return false; } } packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java +50 −22 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -30,6 +31,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** Loading @@ -39,8 +41,8 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall private static final String TAG = "BluetoothMediaManager"; private final DeviceAttributeChangeCallback mCachedDeviceCallback = new DeviceAttributeChangeCallback(); private final DeviceProfileNotReadyObserverCallback mObserverCallback = new DeviceProfileNotReadyObserverCallback(); private LocalBluetoothManager mLocalBluetoothManager; private LocalBluetoothProfileManager mProfileManager; Loading @@ -48,6 +50,10 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall private MediaDevice mLastAddedDevice; private MediaDevice mLastRemovedDevice; private boolean mIsA2dpProfileReady = false; private boolean mIsHearingAidProfileReady = false; private Collection<CachedBluetoothDevice> mCachedDevices; BluetoothMediaManager(Context context, LocalBluetoothManager localBluetoothManager, Notification notification) { super(context, notification); Loading @@ -62,6 +68,18 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall 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 all devices in CachedDeviceManager. // When one of these device is connected to profile, will call buildBluetoothDeviceList() // again to find the connected devices. if (!mIsA2dpProfileReady && !mIsHearingAidProfileReady) { mCachedDevices = mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy(); for (CachedBluetoothDevice device : mCachedDevices) { device.registerCallback(mObserverCallback); } } } private void buildBluetoothDeviceList() { Loading @@ -75,6 +93,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall Log.w(TAG, "addConnectedA2dpDevices() a2dp profile is null!"); return; } final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices(); final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = mLocalBluetoothManager.getCachedDeviceManager(); Loading @@ -95,6 +114,8 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall addMediaDevice(cachedDevice); } } mIsA2dpProfileReady = a2dpProfile.isProfileReady(); } private void addConnectedHearingAidDevices() { Loading @@ -103,6 +124,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall Log.w(TAG, "addConnectedA2dpDevices() hap profile is null!"); return; } final List<Long> devicesHiSyncIds = new ArrayList<>(); final List<BluetoothDevice> devices = hapProfile.getConnectedDevices(); final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = Loading @@ -128,13 +150,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); } Loading @@ -143,16 +166,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 Loading @@ -164,8 +177,6 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall final List<MediaDevice> removeDevicesList = new ArrayList<>(); for (MediaDevice device : mMediaDevices) { if (device instanceof BluetoothMediaDevice) { ((BluetoothMediaDevice) device).getCachedDevice() .unregisterCallback(mCachedDeviceCallback); removeDevicesList.add(device); } } Loading @@ -185,7 +196,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall private boolean isCachedDeviceConnected(CachedBluetoothDevice cachedDevice) { final boolean isConnectedHearingAidDevice = cachedDevice.isConnectedHearingAidDevice(); final boolean isConnectedA2dpDevice = cachedDevice.isConnectedA2dpDevice(); Log.d(TAG, "isCachedDeviceConnected() cachedDevice : " + cachedDevice.getName() Log.d(TAG, "isCachedDeviceConnected() cachedDevice : " + cachedDevice + ", is hearing aid connected : " + isConnectedHearingAidDevice + ", is a2dp connected : " + isConnectedA2dpDevice); Loading @@ -210,7 +221,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); } Loading @@ -226,7 +236,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall @Override public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, int bluetoothProfile) { Log.d(TAG, "onProfileConnectionStateChanged() device: " + cachedDevice.getName() Log.d(TAG, "onProfileConnectionStateChanged() device: " + cachedDevice + ", state: " + state + ", bluetoothProfile: " + bluetoothProfile); if (isCachedDeviceConnected(cachedDevice)) { Loading @@ -240,8 +250,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall @Override public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { Log.d(TAG, "onAclConnectionStateChanged() device: " + cachedDevice.getName() + ", state: " + state); Log.d(TAG, "onAclConnectionStateChanged() device: " + cachedDevice + ", state: " + state); if (isCachedDeviceConnected(cachedDevice)) { addMediaDevice(cachedDevice); Loading @@ -252,10 +261,29 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall } } class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback { @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); dispatchActiveDeviceChanged(id); } } class DeviceProfileNotReadyObserverCallback implements CachedBluetoothDevice.Callback { @Override public void onDeviceAttributesChanged() { dispatchDeviceAttributesChanged(); if (!mIsA2dpProfileReady && !mIsHearingAidProfileReady) { for (CachedBluetoothDevice device : mCachedDevices) { device.unregisterCallback(mObserverCallback); } buildBluetoothDeviceList(); dispatchDeviceListAdded(); } } } } packages/SettingsLib/src/com/android/settingslib/media/ConnectionRecordManager.java 0 → 100644 +89 −0 Original line number Diff line number Diff line /* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settingslib.media; import android.content.Context; import android.content.SharedPreferences; /** * ConnectionRecordManager represents the sharedPreferences operation on device usage record */ public class ConnectionRecordManager { private static final Object sInstanceSync = new Object(); private static final String KEY_LAST_SELECTED_DEVICE = "last_selected_device"; private static final String SHARED_PREFERENCES_NAME = "seamless_transfer_record"; private static final String TAG = "ConnectionRecordManager"; private static ConnectionRecordManager sInstance; private String mLastSelectedDevice; /** * Get an {@code ConnectionRecordManager} instance (create one if necessary). */ public static ConnectionRecordManager getInstance() { synchronized (sInstanceSync) { if (sInstance == null) { sInstance = new ConnectionRecordManager(); } } return sInstance; } private SharedPreferences getSharedPreferences(Context context) { return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); } /** * Get connection record from sharedPreferences * * @param id a unique device Id * @return the the usage result */ public synchronized int fetchConnectionRecord(Context context, String id) { return getSharedPreferences(context).getInt(id, 0); } /** * Get the last selected device from sharedPreferences */ public synchronized void fetchLastSelectedDevice(Context context) { mLastSelectedDevice = getSharedPreferences(context).getString(KEY_LAST_SELECTED_DEVICE, null); } /** * Set device usage time and last selected device in sharedPreference * * @param id a unique device Id * @param record usage times */ public synchronized void setConnectionRecord(Context context, String id, int record) { final SharedPreferences.Editor editor = getSharedPreferences(context).edit(); // Update used times mLastSelectedDevice = id; editor.putInt(mLastSelectedDevice, record); // Update last used device editor.putString(KEY_LAST_SELECTED_DEVICE, mLastSelectedDevice); editor.apply(); } /** * @return the last selected device */ public synchronized String getLastSelectedDevice() { return mLastSelectedDevice; } } packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java +11 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.settingslib.media; import android.content.Context; import android.widget.Toast; import androidx.mediarouter.media.MediaRouter; Loading @@ -33,6 +34,7 @@ public class InfoMediaDevice extends MediaDevice { InfoMediaDevice(Context context, MediaRouter.RouteInfo info) { super(context, MediaDeviceType.TYPE_CAST_DEVICE); mRouteInfo = info; initDeviceRecord(); } @Override Loading @@ -51,15 +53,23 @@ public class InfoMediaDevice extends MediaDevice { return MediaDeviceUtils.getId(mRouteInfo); } @Override public void notifyConnectedChanged() { //TODO(b/117129183): check mIsConnected state } @Override public void connect() { //TODO(b/117129183): use MediaController2 to transfer media mIsConnected = true; super.connect(); //mIsConnected = true; Toast.makeText(mContext, "This is cast device !", Toast.LENGTH_SHORT).show(); } @Override public void disconnect() { //TODO(b/117129183): disconnected last select device mIsConnected = false; //mIsConnected = false; } } packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +53 −14 Original line number Diff line number Diff line Loading @@ -28,15 +28,20 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * LocalMediaManager provide interface to get MediaDevice list and transfer media to MediaDevice. */ public class LocalMediaManager implements BluetoothCallback { private static final Comparator<MediaDevice> COMPARATOR = Comparator.naturalOrder(); private static final String TAG = "LocalMediaManager"; public static final String NOTIFICATION_EXTRA = "notification_extra"; public static final String NOTIFICATION_PACKAGE_NAME = "notification_package_name"; @Retention(RetentionPolicy.SOURCE) @IntDef({MediaDeviceState.STATE_CONNECTED, MediaDeviceState.STATE_CONNECTING, Loading @@ -56,7 +61,6 @@ public class LocalMediaManager implements BluetoothCallback { private InfoMediaManager mInfoMediaManager; private LocalBluetoothManager mLocalBluetoothManager; private MediaDevice mLastConnectedDevice; private MediaDevice mPhoneDevice; /** Loading Loading @@ -96,29 +100,43 @@ public class LocalMediaManager implements BluetoothCallback { * @param connectDevice the MediaDevice */ public void connectDevice(MediaDevice connectDevice) { if (connectDevice == mLastConnectedDevice) { final MediaDevice currentDevice = getCurrentConnectedDevice(); final MediaDevice device = MediaDeviceUtils.findMediaDevice(mMediaDevices, connectDevice.getId()); if (device != null && currentDevice != null && device.getId().equals(currentDevice.getId())) { return; } if (mLastConnectedDevice != null) { mLastConnectedDevice.disconnect(); //TODO(b/117129183): For demo, will remove check connectDevice is InfoMediaDevice. if (currentDevice != null && !(connectDevice instanceof InfoMediaDevice)) { currentDevice.disconnect(); } connectDevice.connect(); if (connectDevice.isConnected()) { mLastConnectedDevice = connectDevice; } device.connect(); final int state = connectDevice.isConnected() final int state = device.isConnected() ? MediaDeviceState.STATE_CONNECTED : MediaDeviceState.STATE_DISCONNECTED; dispatchSelectedDeviceStateChanged(connectDevice, state); dispatchSelectedDeviceStateChanged(mMediaDevices, device, state); } void dispatchSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state) { private MediaDevice getCurrentConnectedDevice() { for (MediaDevice device : mMediaDevices) { if (device.isConnected()) { return device; } } Log.w(TAG, "getCurrentConnectedDevice() cannot find current connected device !"); return null; } void dispatchSelectedDeviceStateChanged(List<MediaDevice> mMediaDevices, MediaDevice device, @MediaDeviceState int state) { synchronized (mCallbacks) { for (DeviceCallback callback : mCallbacks) { callback.onSelectedDeviceStateChanged(device, state); callback.onSelectedDeviceStateChanged(new ArrayList<>(mMediaDevices), device, state); } } } Loading Loading @@ -153,6 +171,7 @@ public class LocalMediaManager implements BluetoothCallback { void dispatchDeviceListUpdate() { synchronized (mCallbacks) { Collections.sort(mMediaDevices, COMPARATOR); for (DeviceCallback callback : mCallbacks) { callback.onDeviceListUpdate(new ArrayList<>(mMediaDevices)); } Loading Loading @@ -206,6 +225,25 @@ public class LocalMediaManager implements BluetoothCallback { public void onDeviceAttributesChanged() { dispatchDeviceListUpdate(); } @Override public void onActiveDeviceChanged(String id) { final MediaDevice currentDevice = getCurrentConnectedDevice(); final MediaDevice connectDevice = MediaDeviceUtils.findMediaDevice(mMediaDevices, id); if (connectDevice != null && currentDevice != null && connectDevice.getId().equals(currentDevice.getId())) { return; } if (currentDevice != null) { currentDevice.notifyConnectedChanged(); } if (connectDevice != null) { connectDevice.notifyConnectedChanged(); } dispatchDeviceListUpdate(); } } Loading @@ -229,6 +267,7 @@ public class LocalMediaManager implements BluetoothCallback { * {@link MediaDeviceState#STATE_CONNECTING}, * {@link MediaDeviceState#STATE_DISCONNECTED} */ void onSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state); void onSelectedDeviceStateChanged(List<MediaDevice> devices, MediaDevice device, @MediaDeviceState int state); } } Loading
packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java +29 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package com.android.settingslib.media; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.util.Log; Loading @@ -33,6 +35,13 @@ public class BluetoothMediaDevice extends MediaDevice { BluetoothMediaDevice(Context context, CachedBluetoothDevice device) { super(context, MediaDeviceType.TYPE_BLUETOOTH_DEVICE); mCachedDevice = device; initDeviceRecord(); buildConnectedState(device); } private void buildConnectedState(CachedBluetoothDevice device) { mIsConnected = device.isActiveDevice(BluetoothProfile.A2DP) || device.isActiveDevice(BluetoothProfile.HEARING_AID); } @Override Loading @@ -51,10 +60,16 @@ public class BluetoothMediaDevice extends MediaDevice { return MediaDeviceUtils.getId(mCachedDevice); } @Override public void notifyConnectedChanged() { buildConnectedState(mCachedDevice); } @Override public void 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); } Loading @@ -70,4 +85,18 @@ public class BluetoothMediaDevice extends MediaDevice { public CachedBluetoothDevice getCachedDevice() { return mCachedDevice; } @Override protected boolean isCarKitDevice() { final BluetoothClass bluetoothClass = mCachedDevice.getDevice().getBluetoothClass(); if (bluetoothClass != null) { switch (bluetoothClass.getDeviceClass()) { // Both are common CarKit class case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: return true; } } return false; } }
packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java +50 −22 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -30,6 +31,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** Loading @@ -39,8 +41,8 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall private static final String TAG = "BluetoothMediaManager"; private final DeviceAttributeChangeCallback mCachedDeviceCallback = new DeviceAttributeChangeCallback(); private final DeviceProfileNotReadyObserverCallback mObserverCallback = new DeviceProfileNotReadyObserverCallback(); private LocalBluetoothManager mLocalBluetoothManager; private LocalBluetoothProfileManager mProfileManager; Loading @@ -48,6 +50,10 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall private MediaDevice mLastAddedDevice; private MediaDevice mLastRemovedDevice; private boolean mIsA2dpProfileReady = false; private boolean mIsHearingAidProfileReady = false; private Collection<CachedBluetoothDevice> mCachedDevices; BluetoothMediaManager(Context context, LocalBluetoothManager localBluetoothManager, Notification notification) { super(context, notification); Loading @@ -62,6 +68,18 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall 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 all devices in CachedDeviceManager. // When one of these device is connected to profile, will call buildBluetoothDeviceList() // again to find the connected devices. if (!mIsA2dpProfileReady && !mIsHearingAidProfileReady) { mCachedDevices = mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy(); for (CachedBluetoothDevice device : mCachedDevices) { device.registerCallback(mObserverCallback); } } } private void buildBluetoothDeviceList() { Loading @@ -75,6 +93,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall Log.w(TAG, "addConnectedA2dpDevices() a2dp profile is null!"); return; } final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices(); final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = mLocalBluetoothManager.getCachedDeviceManager(); Loading @@ -95,6 +114,8 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall addMediaDevice(cachedDevice); } } mIsA2dpProfileReady = a2dpProfile.isProfileReady(); } private void addConnectedHearingAidDevices() { Loading @@ -103,6 +124,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall Log.w(TAG, "addConnectedA2dpDevices() hap profile is null!"); return; } final List<Long> devicesHiSyncIds = new ArrayList<>(); final List<BluetoothDevice> devices = hapProfile.getConnectedDevices(); final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = Loading @@ -128,13 +150,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); } Loading @@ -143,16 +166,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 Loading @@ -164,8 +177,6 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall final List<MediaDevice> removeDevicesList = new ArrayList<>(); for (MediaDevice device : mMediaDevices) { if (device instanceof BluetoothMediaDevice) { ((BluetoothMediaDevice) device).getCachedDevice() .unregisterCallback(mCachedDeviceCallback); removeDevicesList.add(device); } } Loading @@ -185,7 +196,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall private boolean isCachedDeviceConnected(CachedBluetoothDevice cachedDevice) { final boolean isConnectedHearingAidDevice = cachedDevice.isConnectedHearingAidDevice(); final boolean isConnectedA2dpDevice = cachedDevice.isConnectedA2dpDevice(); Log.d(TAG, "isCachedDeviceConnected() cachedDevice : " + cachedDevice.getName() Log.d(TAG, "isCachedDeviceConnected() cachedDevice : " + cachedDevice + ", is hearing aid connected : " + isConnectedHearingAidDevice + ", is a2dp connected : " + isConnectedA2dpDevice); Loading @@ -210,7 +221,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); } Loading @@ -226,7 +236,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall @Override public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, int bluetoothProfile) { Log.d(TAG, "onProfileConnectionStateChanged() device: " + cachedDevice.getName() Log.d(TAG, "onProfileConnectionStateChanged() device: " + cachedDevice + ", state: " + state + ", bluetoothProfile: " + bluetoothProfile); if (isCachedDeviceConnected(cachedDevice)) { Loading @@ -240,8 +250,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall @Override public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { Log.d(TAG, "onAclConnectionStateChanged() device: " + cachedDevice.getName() + ", state: " + state); Log.d(TAG, "onAclConnectionStateChanged() device: " + cachedDevice + ", state: " + state); if (isCachedDeviceConnected(cachedDevice)) { addMediaDevice(cachedDevice); Loading @@ -252,10 +261,29 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall } } class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback { @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); dispatchActiveDeviceChanged(id); } } class DeviceProfileNotReadyObserverCallback implements CachedBluetoothDevice.Callback { @Override public void onDeviceAttributesChanged() { dispatchDeviceAttributesChanged(); if (!mIsA2dpProfileReady && !mIsHearingAidProfileReady) { for (CachedBluetoothDevice device : mCachedDevices) { device.unregisterCallback(mObserverCallback); } buildBluetoothDeviceList(); dispatchDeviceListAdded(); } } } }
packages/SettingsLib/src/com/android/settingslib/media/ConnectionRecordManager.java 0 → 100644 +89 −0 Original line number Diff line number Diff line /* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settingslib.media; import android.content.Context; import android.content.SharedPreferences; /** * ConnectionRecordManager represents the sharedPreferences operation on device usage record */ public class ConnectionRecordManager { private static final Object sInstanceSync = new Object(); private static final String KEY_LAST_SELECTED_DEVICE = "last_selected_device"; private static final String SHARED_PREFERENCES_NAME = "seamless_transfer_record"; private static final String TAG = "ConnectionRecordManager"; private static ConnectionRecordManager sInstance; private String mLastSelectedDevice; /** * Get an {@code ConnectionRecordManager} instance (create one if necessary). */ public static ConnectionRecordManager getInstance() { synchronized (sInstanceSync) { if (sInstance == null) { sInstance = new ConnectionRecordManager(); } } return sInstance; } private SharedPreferences getSharedPreferences(Context context) { return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); } /** * Get connection record from sharedPreferences * * @param id a unique device Id * @return the the usage result */ public synchronized int fetchConnectionRecord(Context context, String id) { return getSharedPreferences(context).getInt(id, 0); } /** * Get the last selected device from sharedPreferences */ public synchronized void fetchLastSelectedDevice(Context context) { mLastSelectedDevice = getSharedPreferences(context).getString(KEY_LAST_SELECTED_DEVICE, null); } /** * Set device usage time and last selected device in sharedPreference * * @param id a unique device Id * @param record usage times */ public synchronized void setConnectionRecord(Context context, String id, int record) { final SharedPreferences.Editor editor = getSharedPreferences(context).edit(); // Update used times mLastSelectedDevice = id; editor.putInt(mLastSelectedDevice, record); // Update last used device editor.putString(KEY_LAST_SELECTED_DEVICE, mLastSelectedDevice); editor.apply(); } /** * @return the last selected device */ public synchronized String getLastSelectedDevice() { return mLastSelectedDevice; } }
packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java +11 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.settingslib.media; import android.content.Context; import android.widget.Toast; import androidx.mediarouter.media.MediaRouter; Loading @@ -33,6 +34,7 @@ public class InfoMediaDevice extends MediaDevice { InfoMediaDevice(Context context, MediaRouter.RouteInfo info) { super(context, MediaDeviceType.TYPE_CAST_DEVICE); mRouteInfo = info; initDeviceRecord(); } @Override Loading @@ -51,15 +53,23 @@ public class InfoMediaDevice extends MediaDevice { return MediaDeviceUtils.getId(mRouteInfo); } @Override public void notifyConnectedChanged() { //TODO(b/117129183): check mIsConnected state } @Override public void connect() { //TODO(b/117129183): use MediaController2 to transfer media mIsConnected = true; super.connect(); //mIsConnected = true; Toast.makeText(mContext, "This is cast device !", Toast.LENGTH_SHORT).show(); } @Override public void disconnect() { //TODO(b/117129183): disconnected last select device mIsConnected = false; //mIsConnected = false; } }
packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +53 −14 Original line number Diff line number Diff line Loading @@ -28,15 +28,20 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * LocalMediaManager provide interface to get MediaDevice list and transfer media to MediaDevice. */ public class LocalMediaManager implements BluetoothCallback { private static final Comparator<MediaDevice> COMPARATOR = Comparator.naturalOrder(); private static final String TAG = "LocalMediaManager"; public static final String NOTIFICATION_EXTRA = "notification_extra"; public static final String NOTIFICATION_PACKAGE_NAME = "notification_package_name"; @Retention(RetentionPolicy.SOURCE) @IntDef({MediaDeviceState.STATE_CONNECTED, MediaDeviceState.STATE_CONNECTING, Loading @@ -56,7 +61,6 @@ public class LocalMediaManager implements BluetoothCallback { private InfoMediaManager mInfoMediaManager; private LocalBluetoothManager mLocalBluetoothManager; private MediaDevice mLastConnectedDevice; private MediaDevice mPhoneDevice; /** Loading Loading @@ -96,29 +100,43 @@ public class LocalMediaManager implements BluetoothCallback { * @param connectDevice the MediaDevice */ public void connectDevice(MediaDevice connectDevice) { if (connectDevice == mLastConnectedDevice) { final MediaDevice currentDevice = getCurrentConnectedDevice(); final MediaDevice device = MediaDeviceUtils.findMediaDevice(mMediaDevices, connectDevice.getId()); if (device != null && currentDevice != null && device.getId().equals(currentDevice.getId())) { return; } if (mLastConnectedDevice != null) { mLastConnectedDevice.disconnect(); //TODO(b/117129183): For demo, will remove check connectDevice is InfoMediaDevice. if (currentDevice != null && !(connectDevice instanceof InfoMediaDevice)) { currentDevice.disconnect(); } connectDevice.connect(); if (connectDevice.isConnected()) { mLastConnectedDevice = connectDevice; } device.connect(); final int state = connectDevice.isConnected() final int state = device.isConnected() ? MediaDeviceState.STATE_CONNECTED : MediaDeviceState.STATE_DISCONNECTED; dispatchSelectedDeviceStateChanged(connectDevice, state); dispatchSelectedDeviceStateChanged(mMediaDevices, device, state); } void dispatchSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state) { private MediaDevice getCurrentConnectedDevice() { for (MediaDevice device : mMediaDevices) { if (device.isConnected()) { return device; } } Log.w(TAG, "getCurrentConnectedDevice() cannot find current connected device !"); return null; } void dispatchSelectedDeviceStateChanged(List<MediaDevice> mMediaDevices, MediaDevice device, @MediaDeviceState int state) { synchronized (mCallbacks) { for (DeviceCallback callback : mCallbacks) { callback.onSelectedDeviceStateChanged(device, state); callback.onSelectedDeviceStateChanged(new ArrayList<>(mMediaDevices), device, state); } } } Loading Loading @@ -153,6 +171,7 @@ public class LocalMediaManager implements BluetoothCallback { void dispatchDeviceListUpdate() { synchronized (mCallbacks) { Collections.sort(mMediaDevices, COMPARATOR); for (DeviceCallback callback : mCallbacks) { callback.onDeviceListUpdate(new ArrayList<>(mMediaDevices)); } Loading Loading @@ -206,6 +225,25 @@ public class LocalMediaManager implements BluetoothCallback { public void onDeviceAttributesChanged() { dispatchDeviceListUpdate(); } @Override public void onActiveDeviceChanged(String id) { final MediaDevice currentDevice = getCurrentConnectedDevice(); final MediaDevice connectDevice = MediaDeviceUtils.findMediaDevice(mMediaDevices, id); if (connectDevice != null && currentDevice != null && connectDevice.getId().equals(currentDevice.getId())) { return; } if (currentDevice != null) { currentDevice.notifyConnectedChanged(); } if (connectDevice != null) { connectDevice.notifyConnectedChanged(); } dispatchDeviceListUpdate(); } } Loading @@ -229,6 +267,7 @@ public class LocalMediaManager implements BluetoothCallback { * {@link MediaDeviceState#STATE_CONNECTING}, * {@link MediaDeviceState#STATE_DISCONNECTED} */ void onSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state); void onSelectedDeviceStateChanged(List<MediaDevice> devices, MediaDevice device, @MediaDeviceState int state); } }