Loading packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java 0 → 100644 +261 −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.app.Notification; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.util.Log; import com.android.settingslib.bluetooth.A2dpProfile; import com.android.settingslib.bluetooth.BluetoothCallback; 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 java.util.ArrayList; import java.util.List; /** * BluetoothMediaManager provide interface to get Bluetooth device list. */ public class BluetoothMediaManager extends MediaManager implements BluetoothCallback { private static final String TAG = "BluetoothMediaManager"; private final DeviceAttributeChangeCallback mCachedDeviceCallback = new DeviceAttributeChangeCallback(); private LocalBluetoothManager mLocalBluetoothManager; private LocalBluetoothProfileManager mProfileManager; private MediaDevice mLastAddedDevice; private MediaDevice mLastRemovedDevice; BluetoothMediaManager(Context context, LocalBluetoothManager localBluetoothManager, Notification notification) { super(context, notification); mLocalBluetoothManager = localBluetoothManager; mProfileManager = mLocalBluetoothManager.getProfileManager(); } @Override public void startScan() { mMediaDevices.clear(); mLocalBluetoothManager.getEventManager().registerCallback(this); buildBluetoothDeviceList(); dispatchDeviceListAdded(); } private void buildBluetoothDeviceList() { addConnectedA2dpDevices(); addConnectedHearingAidDevices(); } private void addConnectedA2dpDevices() { final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile(); if (a2dpProfile == null) { Log.w(TAG, "addConnectedA2dpDevices() a2dp profile is null!"); return; } final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices(); final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = mLocalBluetoothManager.getCachedDeviceManager(); for (BluetoothDevice device : devices) { final CachedBluetoothDevice cachedDevice = cachedBluetoothDeviceManager.findDevice(device); if (cachedDevice == null) { Log.w(TAG, "Can't found CachedBluetoothDevice : " + device.getName()); continue; } Log.d(TAG, "addConnectedA2dpDevices() device : " + cachedDevice.getName() + ", is connected : " + cachedDevice.isConnected()); if (cachedDevice.isConnected()) { addMediaDevice(cachedDevice); } } } private void addConnectedHearingAidDevices() { final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile(); if (hapProfile == null) { Log.w(TAG, "addConnectedA2dpDevices() hap profile is null!"); return; } final List<Long> devicesHiSyncIds = new ArrayList<>(); final List<BluetoothDevice> devices = hapProfile.getConnectedDevices(); final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = mLocalBluetoothManager.getCachedDeviceManager(); for (BluetoothDevice device : devices) { final CachedBluetoothDevice cachedDevice = cachedBluetoothDeviceManager.findDevice(device); if (cachedDevice == null) { Log.w(TAG, "Can't found CachedBluetoothDevice : " + device.getName()); continue; } Log.d(TAG, "addConnectedHearingAidDevices() device : " + cachedDevice.getName() + ", is connected : " + cachedDevice.isConnected()); final long hiSyncId = hapProfile.getHiSyncId(device); // device with same hiSyncId should not be shown in the UI. // So do not add it into connectedDevices. if (!devicesHiSyncIds.contains(hiSyncId) && cachedDevice.isConnected()) { devicesHiSyncIds.add(hiSyncId); addMediaDevice(cachedDevice); } } } 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); } } @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 public void onBluetoothStateChanged(int bluetoothState) { if (BluetoothAdapter.STATE_ON == bluetoothState) { buildBluetoothDeviceList(); dispatchDeviceListAdded(); } else if (BluetoothAdapter.STATE_OFF == bluetoothState) { final List<MediaDevice> removeDevicesList = new ArrayList<>(); for (MediaDevice device : mMediaDevices) { if (device instanceof BluetoothMediaDevice) { ((BluetoothMediaDevice) device).getCachedDevice() .unregisterCallback(mCachedDeviceCallback); removeDevicesList.add(device); } } mMediaDevices.removeAll(removeDevicesList); dispatchDeviceListRemoved(removeDevicesList); } } @Override public void onDeviceAdded(CachedBluetoothDevice cachedDevice) { if (isCachedDeviceConnected(cachedDevice)) { addMediaDevice(cachedDevice); dispatchDeviceAdded(cachedDevice); } } private boolean isCachedDeviceConnected(CachedBluetoothDevice cachedDevice) { final boolean isConnectedHearingAidDevice = cachedDevice.isConnectedHearingAidDevice(); final boolean isConnectedA2dpDevice = cachedDevice.isConnectedA2dpDevice(); Log.d(TAG, "isCachedDeviceConnected() cachedDevice : " + cachedDevice.getName() + ", is hearing aid connected : " + isConnectedHearingAidDevice + ", is a2dp connected : " + isConnectedA2dpDevice); return isConnectedHearingAidDevice || isConnectedA2dpDevice; } private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) { if (mLastAddedDevice != null && MediaDeviceUtils.getId(cachedDevice) == mLastAddedDevice.getId()) { dispatchDeviceAdded(mLastAddedDevice); } } @Override public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { if (!isCachedDeviceConnected(cachedDevice)) { removeMediaDevice(cachedDevice); dispatchDeviceRemoved(cachedDevice); } } private void removeMediaDevice(CachedBluetoothDevice cachedDevice) { final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice)); if (mediaDevice != null) { cachedDevice.unregisterCallback(mCachedDeviceCallback); mLastRemovedDevice = mediaDevice; mMediaDevices.remove(mediaDevice); } } void dispatchDeviceRemoved(CachedBluetoothDevice cachedDevice) { if (mLastRemovedDevice != null && MediaDeviceUtils.getId(cachedDevice) == mLastRemovedDevice.getId()) { dispatchDeviceRemoved(mLastRemovedDevice); } } @Override public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, int bluetoothProfile) { Log.d(TAG, "onProfileConnectionStateChanged() device: " + cachedDevice.getName() + ", state: " + state + ", bluetoothProfile: " + bluetoothProfile); if (isCachedDeviceConnected(cachedDevice)) { addMediaDevice(cachedDevice); dispatchDeviceAdded(cachedDevice); } else { removeMediaDevice(cachedDevice); dispatchDeviceRemoved(cachedDevice); } } @Override public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { Log.d(TAG, "onAclConnectionStateChanged() device: " + cachedDevice.getName() + ", state: " + state); if (isCachedDeviceConnected(cachedDevice)) { addMediaDevice(cachedDevice); dispatchDeviceAdded(cachedDevice); } else { removeMediaDevice(cachedDevice); dispatchDeviceRemoved(cachedDevice); } } class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback { @Override public void onDeviceAttributesChanged() { dispatchDeviceAttributesChanged(); } } } packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java 0 → 100644 +92 −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.app.Notification; import android.content.Context; import android.util.Log; import androidx.mediarouter.media.MediaRouteSelector; import androidx.mediarouter.media.MediaRouter; /** * InfoMediaManager provide interface to get InfoMediaDevice list. */ public class InfoMediaManager extends MediaManager { private static final String TAG = "InfoMediaManager"; private final MediaRouterCallback mMediaRouterCallback = new MediaRouterCallback(); private MediaRouter mMediaRouter; private String mPackageName; InfoMediaManager(Context context, String packageName, Notification notification) { super(context, notification); mMediaRouter = MediaRouter.getInstance(context); mPackageName = packageName; } @Override public void startScan() { mMediaDevices.clear(); startScanCastDevice(); } private void startScanCastDevice() { final MediaRouteSelector selector = new MediaRouteSelector.Builder() .addControlCategory(getControlCategoryByPackageName(mPackageName)) .build(); mMediaRouter.addCallback(selector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } private 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"; } @Override public void stopScan() { mMediaRouter.removeCallback(mMediaRouterCallback); } class MediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) { MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(route)); if (mediaDevice == null) { mediaDevice = new InfoMediaDevice(mContext, route); Log.d(TAG, "onRouteAdded() route : " + route.getName()); mMediaDevices.add(mediaDevice); dispatchDeviceAdded(mediaDevice); } } @Override public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo route) { final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(route)); if (mediaDevice != null) { Log.d(TAG, "onRouteRemoved() route : " + route.getName()); mMediaDevices.remove(mediaDevice); dispatchDeviceRemoved(mediaDevice); } } } } packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java 0 → 100644 +234 −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.app.Notification; import android.content.Context; import android.util.Log; import androidx.annotation.IntDef; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.LocalBluetoothManager; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * LocalMediaManager provide interface to get MediaDevice list and transfer media to MediaDevice. */ public class LocalMediaManager implements BluetoothCallback { private static final String TAG = "LocalMediaManager"; @Retention(RetentionPolicy.SOURCE) @IntDef({MediaDeviceState.STATE_CONNECTED, MediaDeviceState.STATE_CONNECTING, MediaDeviceState.STATE_DISCONNECTED}) public @interface MediaDeviceState { int STATE_CONNECTED = 1; int STATE_CONNECTING = 2; int STATE_DISCONNECTED = 3; } private final Collection<DeviceCallback> mCallbacks = new ArrayList<>(); private final MediaDeviceCallback mMediaDeviceCallback = new MediaDeviceCallback(); private Context mContext; private List<MediaDevice> mMediaDevices = new ArrayList<>(); private BluetoothMediaManager mBluetoothMediaManager; private InfoMediaManager mInfoMediaManager; private LocalBluetoothManager mLocalBluetoothManager; private MediaDevice mLastConnectedDevice; private MediaDevice mPhoneDevice; /** * Register to start receiving callbacks for MediaDevice events. */ public void registerCallback(DeviceCallback callback) { synchronized (mCallbacks) { mCallbacks.add(callback); } } /** * Unregister to stop receiving callbacks for MediaDevice events */ public void unregisterCallback(DeviceCallback callback) { synchronized (mCallbacks) { mCallbacks.remove(callback); } } public LocalMediaManager(Context context, String packageName, Notification notification) { mContext = context; mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, /* onInitCallback= */ null); if (mLocalBluetoothManager == null) { Log.e(TAG, "Bluetooth is not supported on this device"); return; } mBluetoothMediaManager = new BluetoothMediaManager(context, mLocalBluetoothManager, notification); mInfoMediaManager = new InfoMediaManager(context, packageName, notification); } /** * Connect the MediaDevice to transfer media * @param connectDevice the MediaDevice */ public void connectDevice(MediaDevice connectDevice) { if (connectDevice == mLastConnectedDevice) { return; } if (mLastConnectedDevice != null) { mLastConnectedDevice.disconnect(); } connectDevice.connect(); if (connectDevice.isConnected()) { mLastConnectedDevice = connectDevice; } final int state = connectDevice.isConnected() ? MediaDeviceState.STATE_CONNECTED : MediaDeviceState.STATE_DISCONNECTED; dispatchSelectedDeviceStateChanged(connectDevice, state); } void dispatchSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state) { synchronized (mCallbacks) { for (DeviceCallback callback : mCallbacks) { callback.onSelectedDeviceStateChanged(device, state); } } } /** * Start scan connected MediaDevice */ public void startScan() { mMediaDevices.clear(); mBluetoothMediaManager.registerCallback(mMediaDeviceCallback); mInfoMediaManager.registerCallback(mMediaDeviceCallback); mBluetoothMediaManager.startScan(); mInfoMediaManager.startScan(); } private void addPhoneDeviceIfNecessary() { // add phone device to list if there have any Bluetooth device and cast device. if (mMediaDevices.size() > 0 && !mMediaDevices.contains(mPhoneDevice)) { if (mPhoneDevice == null) { mPhoneDevice = new PhoneMediaDevice(mContext, mLocalBluetoothManager); } mMediaDevices.add(mPhoneDevice); } } private void removePhoneMediaDeviceIfNecessary() { // if PhoneMediaDevice is the last item in the list, remove it. if (mMediaDevices.size() == 1 && mMediaDevices.contains(mPhoneDevice)) { mMediaDevices.clear(); } } void dispatchDeviceListUpdate() { synchronized (mCallbacks) { for (DeviceCallback callback : mCallbacks) { callback.onDeviceListUpdate(new ArrayList<>(mMediaDevices)); } } } /** * Stop scan MediaDevice */ public void stopScan() { mBluetoothMediaManager.unregisterCallback(mMediaDeviceCallback); mInfoMediaManager.unregisterCallback(mMediaDeviceCallback); mBluetoothMediaManager.stopScan(); mInfoMediaManager.stopScan(); } class MediaDeviceCallback implements MediaManager.MediaDeviceCallback { @Override public void onDeviceAdded(MediaDevice device) { if (!mMediaDevices.contains(device)) { mMediaDevices.add(device); addPhoneDeviceIfNecessary(); dispatchDeviceListUpdate(); } } @Override public void onDeviceListAdded(List<MediaDevice> devices) { mMediaDevices.addAll(devices); addPhoneDeviceIfNecessary(); dispatchDeviceListUpdate(); } @Override public void onDeviceRemoved(MediaDevice device) { if (mMediaDevices.contains(device)) { mMediaDevices.remove(device); removePhoneMediaDeviceIfNecessary(); dispatchDeviceListUpdate(); } } @Override public void onDeviceListRemoved(List<MediaDevice> devices) { mMediaDevices.removeAll(devices); removePhoneMediaDeviceIfNecessary(); dispatchDeviceListUpdate(); } @Override public void onDeviceAttributesChanged() { dispatchDeviceListUpdate(); } } /** * Callback for notifying device information updating */ public interface DeviceCallback { /** * Callback for notifying device list updated. * * @param devices MediaDevice list */ void onDeviceListUpdate(List<MediaDevice> devices); /** * Callback for notifying the connected device is changed. * * @param device the changed connected MediaDevice * @param state the current MediaDevice state, the possible values are: * {@link MediaDeviceState#STATE_CONNECTED}, * {@link MediaDeviceState#STATE_CONNECTING}, * {@link MediaDeviceState#STATE_DISCONNECTED} */ void onSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state); } } packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java 0 → 100644 +157 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java 0 → 100644 +261 −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.app.Notification; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.util.Log; import com.android.settingslib.bluetooth.A2dpProfile; import com.android.settingslib.bluetooth.BluetoothCallback; 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 java.util.ArrayList; import java.util.List; /** * BluetoothMediaManager provide interface to get Bluetooth device list. */ public class BluetoothMediaManager extends MediaManager implements BluetoothCallback { private static final String TAG = "BluetoothMediaManager"; private final DeviceAttributeChangeCallback mCachedDeviceCallback = new DeviceAttributeChangeCallback(); private LocalBluetoothManager mLocalBluetoothManager; private LocalBluetoothProfileManager mProfileManager; private MediaDevice mLastAddedDevice; private MediaDevice mLastRemovedDevice; BluetoothMediaManager(Context context, LocalBluetoothManager localBluetoothManager, Notification notification) { super(context, notification); mLocalBluetoothManager = localBluetoothManager; mProfileManager = mLocalBluetoothManager.getProfileManager(); } @Override public void startScan() { mMediaDevices.clear(); mLocalBluetoothManager.getEventManager().registerCallback(this); buildBluetoothDeviceList(); dispatchDeviceListAdded(); } private void buildBluetoothDeviceList() { addConnectedA2dpDevices(); addConnectedHearingAidDevices(); } private void addConnectedA2dpDevices() { final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile(); if (a2dpProfile == null) { Log.w(TAG, "addConnectedA2dpDevices() a2dp profile is null!"); return; } final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices(); final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = mLocalBluetoothManager.getCachedDeviceManager(); for (BluetoothDevice device : devices) { final CachedBluetoothDevice cachedDevice = cachedBluetoothDeviceManager.findDevice(device); if (cachedDevice == null) { Log.w(TAG, "Can't found CachedBluetoothDevice : " + device.getName()); continue; } Log.d(TAG, "addConnectedA2dpDevices() device : " + cachedDevice.getName() + ", is connected : " + cachedDevice.isConnected()); if (cachedDevice.isConnected()) { addMediaDevice(cachedDevice); } } } private void addConnectedHearingAidDevices() { final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile(); if (hapProfile == null) { Log.w(TAG, "addConnectedA2dpDevices() hap profile is null!"); return; } final List<Long> devicesHiSyncIds = new ArrayList<>(); final List<BluetoothDevice> devices = hapProfile.getConnectedDevices(); final CachedBluetoothDeviceManager cachedBluetoothDeviceManager = mLocalBluetoothManager.getCachedDeviceManager(); for (BluetoothDevice device : devices) { final CachedBluetoothDevice cachedDevice = cachedBluetoothDeviceManager.findDevice(device); if (cachedDevice == null) { Log.w(TAG, "Can't found CachedBluetoothDevice : " + device.getName()); continue; } Log.d(TAG, "addConnectedHearingAidDevices() device : " + cachedDevice.getName() + ", is connected : " + cachedDevice.isConnected()); final long hiSyncId = hapProfile.getHiSyncId(device); // device with same hiSyncId should not be shown in the UI. // So do not add it into connectedDevices. if (!devicesHiSyncIds.contains(hiSyncId) && cachedDevice.isConnected()) { devicesHiSyncIds.add(hiSyncId); addMediaDevice(cachedDevice); } } } 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); } } @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 public void onBluetoothStateChanged(int bluetoothState) { if (BluetoothAdapter.STATE_ON == bluetoothState) { buildBluetoothDeviceList(); dispatchDeviceListAdded(); } else if (BluetoothAdapter.STATE_OFF == bluetoothState) { final List<MediaDevice> removeDevicesList = new ArrayList<>(); for (MediaDevice device : mMediaDevices) { if (device instanceof BluetoothMediaDevice) { ((BluetoothMediaDevice) device).getCachedDevice() .unregisterCallback(mCachedDeviceCallback); removeDevicesList.add(device); } } mMediaDevices.removeAll(removeDevicesList); dispatchDeviceListRemoved(removeDevicesList); } } @Override public void onDeviceAdded(CachedBluetoothDevice cachedDevice) { if (isCachedDeviceConnected(cachedDevice)) { addMediaDevice(cachedDevice); dispatchDeviceAdded(cachedDevice); } } private boolean isCachedDeviceConnected(CachedBluetoothDevice cachedDevice) { final boolean isConnectedHearingAidDevice = cachedDevice.isConnectedHearingAidDevice(); final boolean isConnectedA2dpDevice = cachedDevice.isConnectedA2dpDevice(); Log.d(TAG, "isCachedDeviceConnected() cachedDevice : " + cachedDevice.getName() + ", is hearing aid connected : " + isConnectedHearingAidDevice + ", is a2dp connected : " + isConnectedA2dpDevice); return isConnectedHearingAidDevice || isConnectedA2dpDevice; } private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) { if (mLastAddedDevice != null && MediaDeviceUtils.getId(cachedDevice) == mLastAddedDevice.getId()) { dispatchDeviceAdded(mLastAddedDevice); } } @Override public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { if (!isCachedDeviceConnected(cachedDevice)) { removeMediaDevice(cachedDevice); dispatchDeviceRemoved(cachedDevice); } } private void removeMediaDevice(CachedBluetoothDevice cachedDevice) { final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice)); if (mediaDevice != null) { cachedDevice.unregisterCallback(mCachedDeviceCallback); mLastRemovedDevice = mediaDevice; mMediaDevices.remove(mediaDevice); } } void dispatchDeviceRemoved(CachedBluetoothDevice cachedDevice) { if (mLastRemovedDevice != null && MediaDeviceUtils.getId(cachedDevice) == mLastRemovedDevice.getId()) { dispatchDeviceRemoved(mLastRemovedDevice); } } @Override public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, int bluetoothProfile) { Log.d(TAG, "onProfileConnectionStateChanged() device: " + cachedDevice.getName() + ", state: " + state + ", bluetoothProfile: " + bluetoothProfile); if (isCachedDeviceConnected(cachedDevice)) { addMediaDevice(cachedDevice); dispatchDeviceAdded(cachedDevice); } else { removeMediaDevice(cachedDevice); dispatchDeviceRemoved(cachedDevice); } } @Override public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { Log.d(TAG, "onAclConnectionStateChanged() device: " + cachedDevice.getName() + ", state: " + state); if (isCachedDeviceConnected(cachedDevice)) { addMediaDevice(cachedDevice); dispatchDeviceAdded(cachedDevice); } else { removeMediaDevice(cachedDevice); dispatchDeviceRemoved(cachedDevice); } } class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback { @Override public void onDeviceAttributesChanged() { dispatchDeviceAttributesChanged(); } } }
packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java 0 → 100644 +92 −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.app.Notification; import android.content.Context; import android.util.Log; import androidx.mediarouter.media.MediaRouteSelector; import androidx.mediarouter.media.MediaRouter; /** * InfoMediaManager provide interface to get InfoMediaDevice list. */ public class InfoMediaManager extends MediaManager { private static final String TAG = "InfoMediaManager"; private final MediaRouterCallback mMediaRouterCallback = new MediaRouterCallback(); private MediaRouter mMediaRouter; private String mPackageName; InfoMediaManager(Context context, String packageName, Notification notification) { super(context, notification); mMediaRouter = MediaRouter.getInstance(context); mPackageName = packageName; } @Override public void startScan() { mMediaDevices.clear(); startScanCastDevice(); } private void startScanCastDevice() { final MediaRouteSelector selector = new MediaRouteSelector.Builder() .addControlCategory(getControlCategoryByPackageName(mPackageName)) .build(); mMediaRouter.addCallback(selector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } private 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"; } @Override public void stopScan() { mMediaRouter.removeCallback(mMediaRouterCallback); } class MediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) { MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(route)); if (mediaDevice == null) { mediaDevice = new InfoMediaDevice(mContext, route); Log.d(TAG, "onRouteAdded() route : " + route.getName()); mMediaDevices.add(mediaDevice); dispatchDeviceAdded(mediaDevice); } } @Override public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo route) { final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(route)); if (mediaDevice != null) { Log.d(TAG, "onRouteRemoved() route : " + route.getName()); mMediaDevices.remove(mediaDevice); dispatchDeviceRemoved(mediaDevice); } } } }
packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java 0 → 100644 +234 −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.app.Notification; import android.content.Context; import android.util.Log; import androidx.annotation.IntDef; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.LocalBluetoothManager; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * LocalMediaManager provide interface to get MediaDevice list and transfer media to MediaDevice. */ public class LocalMediaManager implements BluetoothCallback { private static final String TAG = "LocalMediaManager"; @Retention(RetentionPolicy.SOURCE) @IntDef({MediaDeviceState.STATE_CONNECTED, MediaDeviceState.STATE_CONNECTING, MediaDeviceState.STATE_DISCONNECTED}) public @interface MediaDeviceState { int STATE_CONNECTED = 1; int STATE_CONNECTING = 2; int STATE_DISCONNECTED = 3; } private final Collection<DeviceCallback> mCallbacks = new ArrayList<>(); private final MediaDeviceCallback mMediaDeviceCallback = new MediaDeviceCallback(); private Context mContext; private List<MediaDevice> mMediaDevices = new ArrayList<>(); private BluetoothMediaManager mBluetoothMediaManager; private InfoMediaManager mInfoMediaManager; private LocalBluetoothManager mLocalBluetoothManager; private MediaDevice mLastConnectedDevice; private MediaDevice mPhoneDevice; /** * Register to start receiving callbacks for MediaDevice events. */ public void registerCallback(DeviceCallback callback) { synchronized (mCallbacks) { mCallbacks.add(callback); } } /** * Unregister to stop receiving callbacks for MediaDevice events */ public void unregisterCallback(DeviceCallback callback) { synchronized (mCallbacks) { mCallbacks.remove(callback); } } public LocalMediaManager(Context context, String packageName, Notification notification) { mContext = context; mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, /* onInitCallback= */ null); if (mLocalBluetoothManager == null) { Log.e(TAG, "Bluetooth is not supported on this device"); return; } mBluetoothMediaManager = new BluetoothMediaManager(context, mLocalBluetoothManager, notification); mInfoMediaManager = new InfoMediaManager(context, packageName, notification); } /** * Connect the MediaDevice to transfer media * @param connectDevice the MediaDevice */ public void connectDevice(MediaDevice connectDevice) { if (connectDevice == mLastConnectedDevice) { return; } if (mLastConnectedDevice != null) { mLastConnectedDevice.disconnect(); } connectDevice.connect(); if (connectDevice.isConnected()) { mLastConnectedDevice = connectDevice; } final int state = connectDevice.isConnected() ? MediaDeviceState.STATE_CONNECTED : MediaDeviceState.STATE_DISCONNECTED; dispatchSelectedDeviceStateChanged(connectDevice, state); } void dispatchSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state) { synchronized (mCallbacks) { for (DeviceCallback callback : mCallbacks) { callback.onSelectedDeviceStateChanged(device, state); } } } /** * Start scan connected MediaDevice */ public void startScan() { mMediaDevices.clear(); mBluetoothMediaManager.registerCallback(mMediaDeviceCallback); mInfoMediaManager.registerCallback(mMediaDeviceCallback); mBluetoothMediaManager.startScan(); mInfoMediaManager.startScan(); } private void addPhoneDeviceIfNecessary() { // add phone device to list if there have any Bluetooth device and cast device. if (mMediaDevices.size() > 0 && !mMediaDevices.contains(mPhoneDevice)) { if (mPhoneDevice == null) { mPhoneDevice = new PhoneMediaDevice(mContext, mLocalBluetoothManager); } mMediaDevices.add(mPhoneDevice); } } private void removePhoneMediaDeviceIfNecessary() { // if PhoneMediaDevice is the last item in the list, remove it. if (mMediaDevices.size() == 1 && mMediaDevices.contains(mPhoneDevice)) { mMediaDevices.clear(); } } void dispatchDeviceListUpdate() { synchronized (mCallbacks) { for (DeviceCallback callback : mCallbacks) { callback.onDeviceListUpdate(new ArrayList<>(mMediaDevices)); } } } /** * Stop scan MediaDevice */ public void stopScan() { mBluetoothMediaManager.unregisterCallback(mMediaDeviceCallback); mInfoMediaManager.unregisterCallback(mMediaDeviceCallback); mBluetoothMediaManager.stopScan(); mInfoMediaManager.stopScan(); } class MediaDeviceCallback implements MediaManager.MediaDeviceCallback { @Override public void onDeviceAdded(MediaDevice device) { if (!mMediaDevices.contains(device)) { mMediaDevices.add(device); addPhoneDeviceIfNecessary(); dispatchDeviceListUpdate(); } } @Override public void onDeviceListAdded(List<MediaDevice> devices) { mMediaDevices.addAll(devices); addPhoneDeviceIfNecessary(); dispatchDeviceListUpdate(); } @Override public void onDeviceRemoved(MediaDevice device) { if (mMediaDevices.contains(device)) { mMediaDevices.remove(device); removePhoneMediaDeviceIfNecessary(); dispatchDeviceListUpdate(); } } @Override public void onDeviceListRemoved(List<MediaDevice> devices) { mMediaDevices.removeAll(devices); removePhoneMediaDeviceIfNecessary(); dispatchDeviceListUpdate(); } @Override public void onDeviceAttributesChanged() { dispatchDeviceListUpdate(); } } /** * Callback for notifying device information updating */ public interface DeviceCallback { /** * Callback for notifying device list updated. * * @param devices MediaDevice list */ void onDeviceListUpdate(List<MediaDevice> devices); /** * Callback for notifying the connected device is changed. * * @param device the changed connected MediaDevice * @param state the current MediaDevice state, the possible values are: * {@link MediaDeviceState#STATE_CONNECTED}, * {@link MediaDeviceState#STATE_CONNECTING}, * {@link MediaDeviceState#STATE_DISCONNECTED} */ void onSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state); } }
packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java 0 → 100644 +157 −0 File added.Preview size limit exceeded, changes collapsed. Show changes