• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.media;
18 
19 import static android.media.AudioManager.STREAM_DEVICES_CHANGED_ACTION;
20 
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.media.AudioManager;
26 import android.media.RoutingSessionInfo;
27 import android.net.Uri;
28 import android.os.UserHandle;
29 import android.os.UserManager;
30 import android.text.TextUtils;
31 import android.util.Log;
32 
33 import androidx.annotation.VisibleForTesting;
34 
35 import com.android.settings.slices.SliceBackgroundWorker;
36 import com.android.settingslib.RestrictedLockUtilsInternal;
37 import com.android.settingslib.Utils;
38 import com.android.settingslib.media.LocalMediaManager;
39 import com.android.settingslib.media.MediaDevice;
40 import com.android.settingslib.utils.ThreadUtils;
41 
42 import java.util.ArrayList;
43 import java.util.Collection;
44 import java.util.List;
45 import java.util.concurrent.CopyOnWriteArrayList;
46 
47 /**
48  * SliceBackgroundWorker for get MediaDevice list and handle MediaDevice state change event.
49  */
50 public class MediaDeviceUpdateWorker extends SliceBackgroundWorker
51         implements LocalMediaManager.DeviceCallback {
52 
53     private static final String TAG = "MediaDeviceUpdateWorker";
54     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
55 
56     public static final String MEDIA_PACKAGE_NAME = "media_package_name";
57 
58     protected final Context mContext;
59     protected final Collection<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
60     private final DevicesChangedBroadcastReceiver mReceiver;
61     private final String mPackageName;
62 
63     private boolean mIsTouched;
64     private MediaDevice mTopDevice;
65 
66     @VisibleForTesting
67     LocalMediaManager mLocalMediaManager;
68 
MediaDeviceUpdateWorker(Context context, Uri uri)69     public MediaDeviceUpdateWorker(Context context, Uri uri) {
70         super(context, uri);
71         mContext = context;
72         mPackageName = uri.getQueryParameter(MEDIA_PACKAGE_NAME);
73         mReceiver = new DevicesChangedBroadcastReceiver();
74     }
75 
76     @Override
onSlicePinned()77     protected void onSlicePinned() {
78         mMediaDevices.clear();
79         mIsTouched = false;
80         if (mLocalMediaManager == null || !TextUtils.equals(mPackageName,
81                 mLocalMediaManager.getPackageName())) {
82             mLocalMediaManager = new LocalMediaManager(mContext, mPackageName, null);
83         }
84 
85         mLocalMediaManager.registerCallback(this);
86         final IntentFilter intentFilter = new IntentFilter(STREAM_DEVICES_CHANGED_ACTION);
87         mContext.registerReceiver(mReceiver, intentFilter);
88         mLocalMediaManager.startScan();
89     }
90 
91     @Override
onSliceUnpinned()92     protected void onSliceUnpinned() {
93         mLocalMediaManager.unregisterCallback(this);
94         mContext.unregisterReceiver(mReceiver);
95         mLocalMediaManager.stopScan();
96     }
97 
98     @Override
close()99     public void close() {
100         mLocalMediaManager = null;
101     }
102 
103     @Override
onDeviceListUpdate(List<MediaDevice> devices)104     public void onDeviceListUpdate(List<MediaDevice> devices) {
105         buildMediaDevices(devices);
106         notifySliceChange();
107     }
108 
buildMediaDevices(List<MediaDevice> devices)109     private void buildMediaDevices(List<MediaDevice> devices) {
110         mMediaDevices.clear();
111         mMediaDevices.addAll(devices);
112     }
113 
114     @Override
onSelectedDeviceStateChanged(MediaDevice device, int state)115     public void onSelectedDeviceStateChanged(MediaDevice device, int state) {
116         notifySliceChange();
117     }
118 
119     @Override
onDeviceAttributesChanged()120     public void onDeviceAttributesChanged() {
121         notifySliceChange();
122     }
123 
124     @Override
onRequestFailed(int reason)125     public void onRequestFailed(int reason) {
126         notifySliceChange();
127     }
128 
getMediaDevices()129     public Collection<MediaDevice> getMediaDevices() {
130         return mMediaDevices;
131     }
132 
connectDevice(MediaDevice device)133     public void connectDevice(MediaDevice device) {
134         ThreadUtils.postOnBackgroundThread(() -> {
135             if (mLocalMediaManager.connectDevice(device)) {
136                 ThreadUtils.postOnMainThread(() -> {
137                     notifySliceChange();
138                 });
139             }
140         });
141     }
142 
getMediaDeviceById(String id)143     public MediaDevice getMediaDeviceById(String id) {
144         return mMediaDevices.stream()
145                 .filter(it -> TextUtils.equals(it.getId(), id))
146                 .findFirst()
147                 .orElse(null);
148     }
149 
getCurrentConnectedMediaDevice()150     public MediaDevice getCurrentConnectedMediaDevice() {
151         return mLocalMediaManager.getCurrentConnectedDevice();
152     }
153 
setIsTouched(boolean isTouched)154     void setIsTouched(boolean isTouched) {
155         mIsTouched = isTouched;
156     }
157 
getIsTouched()158     boolean getIsTouched() {
159         return mIsTouched;
160     }
161 
setTopDevice(MediaDevice device)162     void setTopDevice(MediaDevice device) {
163         mTopDevice = device;
164     }
165 
getTopDevice()166     MediaDevice getTopDevice() {
167         return getMediaDeviceById(mTopDevice.getId());
168     }
169 
addDeviceToPlayMedia(MediaDevice device)170     boolean addDeviceToPlayMedia(MediaDevice device) {
171         return mLocalMediaManager.addDeviceToPlayMedia(device);
172     }
173 
removeDeviceFromPlayMedia(MediaDevice device)174     boolean removeDeviceFromPlayMedia(MediaDevice device) {
175         return mLocalMediaManager.removeDeviceFromPlayMedia(device);
176     }
177 
getSelectableMediaDevice()178     List<MediaDevice> getSelectableMediaDevice() {
179         return mLocalMediaManager.getSelectableMediaDevice();
180     }
181 
getSelectedMediaDevice()182     List<MediaDevice> getSelectedMediaDevice() {
183         return mLocalMediaManager.getSelectedMediaDevice();
184     }
185 
getDeselectableMediaDevice()186     List<MediaDevice> getDeselectableMediaDevice() {
187         return mLocalMediaManager.getDeselectableMediaDevice();
188     }
189 
isDeviceIncluded(Collection<MediaDevice> deviceCollection, MediaDevice targetDevice)190     boolean isDeviceIncluded(Collection<MediaDevice> deviceCollection, MediaDevice targetDevice) {
191         for (MediaDevice device : deviceCollection) {
192             if (TextUtils.equals(device.getId(), targetDevice.getId())) {
193                 return true;
194             }
195         }
196         return false;
197     }
198 
adjustSessionVolume(String sessionId, int volume)199     void adjustSessionVolume(String sessionId, int volume) {
200         mLocalMediaManager.adjustSessionVolume(sessionId, volume);
201     }
202 
adjustSessionVolume(int volume)203     void adjustSessionVolume(int volume) {
204         mLocalMediaManager.adjustSessionVolume(volume);
205     }
206 
getSessionVolumeMax()207     int getSessionVolumeMax() {
208         return mLocalMediaManager.getSessionVolumeMax();
209     }
210 
getSessionVolume()211     int getSessionVolume() {
212         return mLocalMediaManager.getSessionVolume();
213     }
214 
getSessionName()215     CharSequence getSessionName() {
216         return mLocalMediaManager.getSessionName();
217     }
218 
getActiveRemoteMediaDevice()219     List<RoutingSessionInfo> getActiveRemoteMediaDevice() {
220         final List<RoutingSessionInfo> sessionInfos = new ArrayList<>();
221         for (RoutingSessionInfo info : mLocalMediaManager.getActiveMediaSession()) {
222             if (!info.isSystemSession()) {
223                 if (DEBUG) {
224                     Log.d(TAG, "getActiveRemoteMediaDevice() info : " + info.toString()
225                             + ", package name : " + info.getClientPackageName());
226                 }
227                 sessionInfos.add(info);
228             }
229         }
230         return sessionInfos;
231     }
232 
233     /**
234      * Request to set volume.
235      *
236      * @param device for the targeted device.
237      * @param volume for the new value.
238      *
239      */
adjustVolume(MediaDevice device, int volume)240     public void adjustVolume(MediaDevice device, int volume) {
241         ThreadUtils.postOnBackgroundThread(() -> {
242             device.requestSetVolume(volume);
243         });
244     }
245 
getPackageName()246     String getPackageName() {
247         return mPackageName;
248     }
249 
hasAdjustVolumeUserRestriction()250     boolean hasAdjustVolumeUserRestriction() {
251         if (RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
252                 mContext, UserManager.DISALLOW_ADJUST_VOLUME, UserHandle.myUserId()) != null) {
253             return true;
254         }
255         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
256         return um.hasBaseUserRestriction(UserManager.DISALLOW_ADJUST_VOLUME,
257                 UserHandle.of(UserHandle.myUserId()));
258 
259     }
260 
shouldDisableMediaOutput(String packageName)261     boolean shouldDisableMediaOutput(String packageName) {
262         return mLocalMediaManager.shouldDisableMediaOutput(packageName);
263     }
264 
shouldEnableVolumeSeekBar(RoutingSessionInfo sessionInfo)265     boolean shouldEnableVolumeSeekBar(RoutingSessionInfo sessionInfo) {
266         return mLocalMediaManager.shouldEnableVolumeSeekBar(sessionInfo);
267     }
268 
269     private class DevicesChangedBroadcastReceiver extends BroadcastReceiver {
270         @Override
onReceive(Context context, Intent intent)271         public void onReceive(Context context, Intent intent) {
272             final String action = intent.getAction();
273             if (TextUtils.equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION, action)
274                     && Utils.isAudioModeOngoingCall(mContext)) {
275                 notifySliceChange();
276             }
277         }
278     }
279 }
280