Move to Android N-MR1 SDK.
[android_tools.git] / sdk / sources / android-25 / android / media / PlayerBase.java
blobb262d97cfb8e10503c1994949ca80ddd5b2ba032
1 /*
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;
34 /**
35 * Class to encapsulate a number of common player operations:
36 * - AppOps for OP_PLAY_AUDIO
37 * - more to come (routing, transport control)
38 * @hide
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;
48 // for AppOps
49 private final IAppOpsService mAppOps;
50 private final IAppOpsCallback mAppOpsCallback;
51 private boolean mHasAppOpsPlayAudio = true;
52 private final Object mAppOpsLock = new Object();
55 /**
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) {
60 if (attr == null) {
61 throw new IllegalArgumentException("Illegal null AudioAttributes");
63 mAttributes = attr;
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();
78 try {
79 mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
80 ActivityThread.currentPackageName(), mAppOpsCallback);
81 } catch (RemoteException e) {
82 mHasAppOpsPlayAudio = false;
87 /**
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) {
92 if (attr == null) {
93 throw new IllegalArgumentException("Illegal null AudioAttributes");
95 synchronized (mAppOpsLock) {
96 mAttributes = attr;
97 updateAppOpsPlayAudio_sync();
101 void baseStart() {
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()) {
114 return;
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.
134 void baseRelease() {
135 try {
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;
148 try {
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
159 try {
160 if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) {
161 if (mHasAppOpsPlayAudio) {
162 playerSetVolume(mLeftVolume, mRightVolume);
163 playerSetAuxEffectSendLevel(mAuxEffectSendLevel);
164 } else {
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
180 * the restrictions.
181 * @return
183 boolean isRestricted_sync() {
184 // check app ops
185 if (mHasAppOpsPlayAudio) {
186 return false;
188 // check bypass flag
189 if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
190 return false;
192 return true;
195 // Abstract methods a subclass needs to implement
196 abstract void playerSetVolume(float leftVolume, float rightVolume);
197 abstract int playerSetAuxEffectSendLevel(float level);