| /* |
| * 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 static android.media.MediaRoute2Info.DEVICE_TYPE_BLUETOOTH; |
| import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_TV; |
| import static android.media.MediaRoute2Info.DEVICE_TYPE_UNKNOWN; |
| |
| import android.app.Notification; |
| import android.bluetooth.BluetoothAdapter; |
| import android.bluetooth.BluetoothDevice; |
| import android.content.Context; |
| import android.media.MediaRoute2Info; |
| import android.media.MediaRouter2Manager; |
| import android.media.RoutingSessionInfo; |
| import android.text.TextUtils; |
| import android.util.Log; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.settingslib.bluetooth.CachedBluetoothDevice; |
| import com.android.settingslib.bluetooth.LocalBluetoothManager; |
| |
| import java.util.List; |
| import java.util.concurrent.Executor; |
| import java.util.concurrent.Executors; |
| |
| /** |
| * InfoMediaManager provide interface to get InfoMediaDevice list. |
| */ |
| public class InfoMediaManager extends MediaManager { |
| |
| private static final String TAG = "InfoMediaManager"; |
| |
| @VisibleForTesting |
| final RouterManagerCallback mMediaRouterCallback = new RouterManagerCallback(); |
| @VisibleForTesting |
| final Executor mExecutor = Executors.newSingleThreadExecutor(); |
| @VisibleForTesting |
| MediaRouter2Manager mRouterManager; |
| @VisibleForTesting |
| String mPackageName; |
| |
| private MediaDevice mCurrentConnectedDevice; |
| private LocalBluetoothManager mBluetoothManager; |
| |
| public InfoMediaManager(Context context, String packageName, Notification notification, |
| LocalBluetoothManager localBluetoothManager) { |
| super(context, notification); |
| |
| mRouterManager = MediaRouter2Manager.getInstance(context); |
| mBluetoothManager = localBluetoothManager; |
| if (!TextUtils.isEmpty(packageName)) { |
| mPackageName = packageName; |
| } |
| } |
| |
| @Override |
| public void startScan() { |
| mMediaDevices.clear(); |
| mRouterManager.registerCallback(mExecutor, mMediaRouterCallback); |
| refreshDevices(); |
| } |
| |
| @VisibleForTesting |
| String getControlCategoryByPackageName(String packageName) { |
| //TODO(b/117129183): Use package name to get ControlCategory. |
| //Since api not ready, return fixed ControlCategory for prototype. |
| return "com.google.android.gms.cast.CATEGORY_CAST"; |
| } |
| |
| @Override |
| public void stopScan() { |
| mRouterManager.unregisterCallback(mMediaRouterCallback); |
| } |
| |
| /** |
| * Get current device that played media. |
| * @return MediaDevice |
| */ |
| public MediaDevice getCurrentConnectedDevice() { |
| return mCurrentConnectedDevice; |
| } |
| |
| private void refreshDevices() { |
| mMediaDevices.clear(); |
| mCurrentConnectedDevice = null; |
| if (TextUtils.isEmpty(mPackageName)) { |
| buildAllRoutes(); |
| } else { |
| buildAvailableRoutes(); |
| } |
| dispatchDeviceListAdded(); |
| } |
| |
| private void buildAllRoutes() { |
| for (MediaRoute2Info route : mRouterManager.getAllRoutes()) { |
| addMediaDevice(route); |
| } |
| } |
| |
| private void buildAvailableRoutes() { |
| for (MediaRoute2Info route : mRouterManager.getAvailableRoutes(mPackageName)) { |
| addMediaDevice(route); |
| } |
| } |
| |
| private void addMediaDevice(MediaRoute2Info route) { |
| final int deviceType = route.getDeviceType(); |
| MediaDevice mediaDevice = null; |
| switch (deviceType) { |
| case DEVICE_TYPE_UNKNOWN: |
| //TODO(b/148765806): use correct device type once api is ready. |
| final String defaultRoute = "DEFAULT_ROUTE"; |
| if (TextUtils.equals(defaultRoute, route.getOriginalId())) { |
| mediaDevice = |
| new PhoneMediaDevice(mContext, mRouterManager, route, mPackageName); |
| } else { |
| mediaDevice = new InfoMediaDevice(mContext, mRouterManager, route, |
| mPackageName); |
| if (!TextUtils.isEmpty(mPackageName) |
| && TextUtils.equals(route.getClientPackageName(), mPackageName)) { |
| mCurrentConnectedDevice = mediaDevice; |
| } |
| } |
| break; |
| case DEVICE_TYPE_REMOTE_TV: |
| break; |
| case DEVICE_TYPE_BLUETOOTH: |
| final BluetoothDevice device = |
| BluetoothAdapter.getDefaultAdapter().getRemoteDevice(route.getOriginalId()); |
| final CachedBluetoothDevice cachedDevice = |
| mBluetoothManager.getCachedDeviceManager().findDevice(device); |
| mediaDevice = new BluetoothMediaDevice(mContext, cachedDevice, mRouterManager, |
| route, mPackageName); |
| break; |
| default: |
| Log.w(TAG, "addMediaDevice() unknown device type : " + deviceType); |
| break; |
| |
| } |
| |
| if (mediaDevice != null) { |
| mMediaDevices.add(mediaDevice); |
| } |
| } |
| |
| /** |
| * Transfer MediaDevice for media without package name. |
| */ |
| public boolean connectDeviceWithoutPackageName(MediaDevice device) { |
| boolean isConnected = false; |
| final List<RoutingSessionInfo> infos = mRouterManager.getActiveSessions(); |
| if (infos.size() > 0) { |
| final RoutingSessionInfo info = infos.get(0); |
| final MediaRouter2Manager.RoutingController controller = |
| mRouterManager.getControllerForSession(info); |
| |
| controller.transferToRoute(device.mRouteInfo); |
| isConnected = true; |
| } |
| return isConnected; |
| } |
| |
| class RouterManagerCallback extends MediaRouter2Manager.Callback { |
| |
| @Override |
| public void onRoutesAdded(List<MediaRoute2Info> routes) { |
| refreshDevices(); |
| } |
| |
| @Override |
| public void onControlCategoriesChanged(String packageName, List<String> controlCategories) { |
| if (TextUtils.equals(mPackageName, packageName)) { |
| refreshDevices(); |
| } |
| } |
| |
| @Override |
| public void onRoutesChanged(List<MediaRoute2Info> routes) { |
| refreshDevices(); |
| } |
| } |
| } |