summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author hughchen <hughchen@google.com> 2018-11-12 17:42:08 +0800
committer hughchen <hughchen@google.com> 2018-11-13 11:25:38 +0800
commita73686fc3428de145bb6f26f28e7c7e4b7cca5fc (patch)
treeb0afb577491aeb401296ac3935335fce939e91b6
parentb89929aae60178d39c3d6880c5927b66badf35f9 (diff)
Implement LocalMediaManager for seamless transfer
Bug: 117129183 Test: Build pass Change-Id: I388435f928d2be3519993ffcaf41588dc4422ea2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java261
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java92
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java234
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java157
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();
+ }
+}