diff options
| author | 2018-11-12 17:42:08 +0800 | |
|---|---|---|
| committer | 2018-11-13 11:25:38 +0800 | |
| commit | a73686fc3428de145bb6f26f28e7c7e4b7cca5fc (patch) | |
| tree | b0afb577491aeb401296ac3935335fce939e91b6 | |
| parent | b89929aae60178d39c3d6880c5927b66badf35f9 (diff) | |
Implement LocalMediaManager for seamless transfer
Bug: 117129183
Test: Build pass
Change-Id: I388435f928d2be3519993ffcaf41588dc4422ea2
4 files changed, 744 insertions, 0 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java new file mode 100644 index 000000000000..04188e936cf6 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java @@ -0,0 +1,261 @@ +/* + * 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(); + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java new file mode 100644 index 000000000000..6907238082fc --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -0,0 +1,92 @@ +/* + * 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); + } + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java new file mode 100644 index 000000000000..e375ea016ec2 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -0,0 +1,234 @@ +/* + * 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); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java new file mode 100644 index 000000000000..72b6b09d637e --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java @@ -0,0 +1,157 @@ +/* + * 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 java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * MediaManager provide interface to get MediaDevice list. + */ +public abstract class MediaManager { + + private static final String TAG = "MediaManager"; + + protected final Collection<MediaDeviceCallback> mCallbacks = new ArrayList<>(); + protected final List<MediaDevice> mMediaDevices = new ArrayList<>(); + + protected Context mContext; + protected Notification mNotification; + + MediaManager(Context context, Notification notification) { + mContext = context; + mNotification = notification; + } + + protected void registerCallback(MediaDeviceCallback callback) { + synchronized (mCallbacks) { + if (!mCallbacks.contains(callback)) { + mCallbacks.add(callback); + } + } + } + + protected void unregisterCallback(MediaDeviceCallback callback) { + synchronized (mCallbacks) { + if (mCallbacks.contains(callback)) { + mCallbacks.remove(callback); + } + } + } + + /** + * Start scan connected MediaDevice + */ + public abstract void startScan(); + + /** + * Stop scan MediaDevice + */ + public abstract void stopScan(); + + protected MediaDevice findMediaDevice(String id) { + for (MediaDevice mediaDevice : mMediaDevices) { + if (mediaDevice.getId().equals(id)) { + return mediaDevice; + } + } + Log.e(TAG, "findMediaDevice() can't found device"); + return null; + } + + protected void dispatchDeviceAdded(MediaDevice mediaDevice) { + synchronized (mCallbacks) { + for (MediaDeviceCallback callback : mCallbacks) { + callback.onDeviceAdded(mediaDevice); + } + } + } + + protected void dispatchDeviceRemoved(MediaDevice mediaDevice) { + synchronized (mCallbacks) { + for (MediaDeviceCallback callback : mCallbacks) { + callback.onDeviceRemoved(mediaDevice); + } + } + } + + protected void dispatchDeviceListAdded() { + synchronized (mCallbacks) { + for (MediaDeviceCallback callback : mCallbacks) { + callback.onDeviceListAdded(mMediaDevices); + } + } + } + + protected void dispatchDeviceListRemoved(List<MediaDevice> devices) { + synchronized (mCallbacks) { + for (MediaDeviceCallback callback : mCallbacks) { + callback.onDeviceListRemoved(devices); + } + } + } + + protected void dispatchDeviceAttributesChanged() { + synchronized (mCallbacks) { + for (MediaDeviceCallback callback : mCallbacks) { + callback.onDeviceAttributesChanged(); + } + } + } + + /** + * Callback for notifying device is added, removed and attributes changed. + */ + public interface MediaDeviceCallback { + /** + * Callback for notifying MediaDevice is added. + * + * @param device the MediaDevice + */ + void onDeviceAdded(MediaDevice device); + + /** + * Callback for notifying MediaDevice list is added. + * + * @param devices the MediaDevice list + */ + void onDeviceListAdded(List<MediaDevice> devices); + + /** + * Callback for notifying MediaDevice is removed. + * + * @param device the MediaDevice + */ + void onDeviceRemoved(MediaDevice device); + + /** + * Callback for notifying MediaDevice list is removed. + * + * @param devices the MediaDevice list + */ + void onDeviceListRemoved(List<MediaDevice> devices); + + /** + * Callback for notifying MediaDevice attributes is changed. + */ + void onDeviceAttributesChanged(); + } +} |