2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android
.media
;
19 import java
.lang
.IllegalArgumentException
;
21 import android
.annotation
.NonNull
;
22 import android
.app
.ActivityThread
;
23 import android
.app
.AppOpsManager
;
24 import android
.content
.Context
;
25 import android
.os
.IBinder
;
26 import android
.os
.Process
;
27 import android
.os
.RemoteException
;
28 import android
.os
.ServiceManager
;
29 import android
.util
.Log
;
31 import com
.android
.internal
.app
.IAppOpsCallback
;
32 import com
.android
.internal
.app
.IAppOpsService
;
35 * Class to encapsulate a number of common player operations:
36 * - AppOps for OP_PLAY_AUDIO
37 * - more to come (routing, transport control)
40 public abstract class PlayerBase
{
42 // parameters of the player that affect AppOps
43 protected AudioAttributes mAttributes
;
44 protected float mLeftVolume
= 1.0f
;
45 protected float mRightVolume
= 1.0f
;
46 protected float mAuxEffectSendLevel
= 0.0f
;
49 private final IAppOpsService mAppOps
;
50 private final IAppOpsCallback mAppOpsCallback
;
51 private boolean mHasAppOpsPlayAudio
= true;
52 private final Object mAppOpsLock
= new Object();
56 * Constructor. Must be given audio attributes, as they are required for AppOps.
57 * @param attr non-null audio attributes
59 PlayerBase(@NonNull AudioAttributes attr
) {
61 throw new IllegalArgumentException("Illegal null AudioAttributes");
64 IBinder b
= ServiceManager
.getService(Context
.APP_OPS_SERVICE
);
65 mAppOps
= IAppOpsService
.Stub
.asInterface(b
);
66 // initialize mHasAppOpsPlayAudio
67 updateAppOpsPlayAudio_sync();
68 // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
69 mAppOpsCallback
= new IAppOpsCallback
.Stub() {
70 public void opChanged(int op
, int uid
, String packageName
) {
71 synchronized (mAppOpsLock
) {
72 if (op
== AppOpsManager
.OP_PLAY_AUDIO
) {
73 updateAppOpsPlayAudio_sync();
79 mAppOps
.startWatchingMode(AppOpsManager
.OP_PLAY_AUDIO
,
80 ActivityThread
.currentPackageName(), mAppOpsCallback
);
81 } catch (RemoteException e
) {
82 mHasAppOpsPlayAudio
= false;
88 * To be called whenever the audio attributes of the player change
89 * @param attr non-null audio attributes
91 void baseUpdateAudioAttributes(@NonNull AudioAttributes attr
) {
93 throw new IllegalArgumentException("Illegal null AudioAttributes");
95 synchronized (mAppOpsLock
) {
97 updateAppOpsPlayAudio_sync();
102 synchronized (mAppOpsLock
) {
103 if (isRestricted_sync()) {
104 playerSetVolume(0, 0);
109 void baseSetVolume(float leftVolume
, float rightVolume
) {
110 synchronized (mAppOpsLock
) {
111 mLeftVolume
= leftVolume
;
112 mRightVolume
= rightVolume
;
113 if (isRestricted_sync()) {
117 playerSetVolume(leftVolume
, rightVolume
);
120 int baseSetAuxEffectSendLevel(float level
) {
121 synchronized (mAppOpsLock
) {
122 mAuxEffectSendLevel
= level
;
123 if (isRestricted_sync()) {
124 return AudioSystem
.SUCCESS
;
127 return playerSetAuxEffectSendLevel(level
);
131 * To be called from a subclass release or finalize method.
132 * Releases AppOps related resources.
136 mAppOps
.stopWatchingMode(mAppOpsCallback
);
137 } catch (RemoteException e
) {
138 // nothing to do here, the object is supposed to be released anyway
143 * To be called whenever a condition that might affect audibility of this player is updated.
144 * Must be called synchronized on mAppOpsLock.
146 void updateAppOpsPlayAudio_sync() {
147 boolean oldHasAppOpsPlayAudio
= mHasAppOpsPlayAudio
;
149 final int mode
= mAppOps
.checkAudioOperation(AppOpsManager
.OP_PLAY_AUDIO
,
150 mAttributes
.getUsage(),
151 Process
.myUid(), ActivityThread
.currentPackageName());
152 mHasAppOpsPlayAudio
= (mode
== AppOpsManager
.MODE_ALLOWED
);
153 } catch (RemoteException e
) {
154 mHasAppOpsPlayAudio
= false;
157 // AppsOps alters a player's volume; when the restriction changes, reflect it on the actual
158 // volume used by the player
160 if (oldHasAppOpsPlayAudio
!= mHasAppOpsPlayAudio
) {
161 if (mHasAppOpsPlayAudio
) {
162 playerSetVolume(mLeftVolume
, mRightVolume
);
163 playerSetAuxEffectSendLevel(mAuxEffectSendLevel
);
165 playerSetVolume(0.0f
, 0.0f
);
166 playerSetAuxEffectSendLevel(0.0f
);
169 } catch (Exception e
) {
170 // failing silently, player might not be in right state
176 * To be called by the subclass whenever an operation is potentially restricted.
177 * As the media player-common behavior are incorporated into this class, the subclass's need
178 * to call this method should be removed, and this method could become private.
179 * FIXME can this method be private so subclasses don't have to worry about when to check
183 boolean isRestricted_sync() {
185 if (mHasAppOpsPlayAudio
) {
189 if ((mAttributes
.getAllFlags() & AudioAttributes
.FLAG_BYPASS_INTERRUPTION_POLICY
) != 0) {
195 // Abstract methods a subclass needs to implement
196 abstract void playerSetVolume(float leftVolume
, float rightVolume
);
197 abstract int playerSetAuxEffectSendLevel(float level
);