13c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi/* 23c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * Copyright (C) 2016 The Android Open Source Project 33c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * 43c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License"); 53c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * you may not use this file except in compliance with the License. 63c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * You may obtain a copy of the License at 73c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * 83c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * http://www.apache.org/licenses/LICENSE-2.0 93c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * 103c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * Unless required by applicable law or agreed to in writing, software 113c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS, 123c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * See the License for the specific language governing permissions and 143c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * limitations under the License. 153c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi */ 163c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 173c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivipackage android.media; 183c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 193c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport java.lang.IllegalArgumentException; 203c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 213c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport android.annotation.NonNull; 223c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport android.app.ActivityThread; 233c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport android.app.AppOpsManager; 243c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport android.content.Context; 253c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport android.os.IBinder; 263c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport android.os.Process; 273c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport android.os.RemoteException; 283c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport android.os.ServiceManager; 293c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport android.util.Log; 303c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 313c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport com.android.internal.app.IAppOpsCallback; 323c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Triviimport com.android.internal.app.IAppOpsService; 333c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 343c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi/** 353c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * Class to encapsulate a number of common player operations: 363c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * - AppOps for OP_PLAY_AUDIO 373c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * - more to come (routing, transport control) 383c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * @hide 393c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi */ 403c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivipublic abstract class PlayerBase { 413c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 423c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi // parameters of the player that affect AppOps 433c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi protected AudioAttributes mAttributes; 443c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi protected float mLeftVolume = 1.0f; 453c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi protected float mRightVolume = 1.0f; 463c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi protected float mAuxEffectSendLevel = 0.0f; 473c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 483c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi // for AppOps 493c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi private final IAppOpsService mAppOps; 503c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi private final IAppOpsCallback mAppOpsCallback; 513c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi private boolean mHasAppOpsPlayAudio = true; 523c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi private final Object mAppOpsLock = new Object(); 533c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 543c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 553c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi /** 563c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * Constructor. Must be given audio attributes, as they are required for AppOps. 573c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * @param attr non-null audio attributes 583c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi */ 593c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi PlayerBase(@NonNull AudioAttributes attr) { 603c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi if (attr == null) { 613c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi throw new IllegalArgumentException("Illegal null AudioAttributes"); 623c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 633c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mAttributes = attr; 643c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); 653c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mAppOps = IAppOpsService.Stub.asInterface(b); 663c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi // initialize mHasAppOpsPlayAudio 673c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi updateAppOpsPlayAudio_sync(); 683c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed 693c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mAppOpsCallback = new IAppOpsCallback.Stub() { 703c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi public void opChanged(int op, int uid, String packageName) { 713c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi synchronized (mAppOpsLock) { 723c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi if (op == AppOpsManager.OP_PLAY_AUDIO) { 733c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi updateAppOpsPlayAudio_sync(); 743c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 753c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 763c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 773c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi }; 783c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi try { 793c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO, 803c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi ActivityThread.currentPackageName(), mAppOpsCallback); 813c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } catch (RemoteException e) { 823c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mHasAppOpsPlayAudio = false; 833c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 843c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 853c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 863c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 873c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi /** 883c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * To be called whenever the audio attributes of the player change 893c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * @param attr non-null audio attributes 903c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi */ 913c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi void baseUpdateAudioAttributes(@NonNull AudioAttributes attr) { 923c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi if (attr == null) { 933c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi throw new IllegalArgumentException("Illegal null AudioAttributes"); 943c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 953c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi synchronized (mAppOpsLock) { 963c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mAttributes = attr; 973c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi updateAppOpsPlayAudio_sync(); 983c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 993c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1003c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 1013c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi void baseStart() { 1023c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi synchronized (mAppOpsLock) { 1033c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi if (isRestricted_sync()) { 1043c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi playerSetVolume(0, 0); 1053c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1063c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1073c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1083c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 1093c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi void baseSetVolume(float leftVolume, float rightVolume) { 1103c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi synchronized (mAppOpsLock) { 1113c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mLeftVolume = leftVolume; 1123c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mRightVolume = rightVolume; 1133c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi if (isRestricted_sync()) { 1143c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi return; 1153c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1163c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1173c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi playerSetVolume(leftVolume, rightVolume); 1183c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1193c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 1203c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi int baseSetAuxEffectSendLevel(float level) { 1213c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi synchronized (mAppOpsLock) { 1223c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mAuxEffectSendLevel = level; 1233c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi if (isRestricted_sync()) { 1243c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi return AudioSystem.SUCCESS; 1253c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1263c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1273c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi return playerSetAuxEffectSendLevel(level); 1283c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1293c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 1303c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi /** 1313c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * To be called from a subclass release or finalize method. 1323c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * Releases AppOps related resources. 1333c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi */ 1343c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi void baseRelease() { 1353c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi try { 1363c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mAppOps.stopWatchingMode(mAppOpsCallback); 1373c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } catch (RemoteException e) { 1383c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi // nothing to do here, the object is supposed to be released anyway 1393c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1403c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1413c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 1423c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi /** 1433c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * To be called whenever a condition that might affect audibility of this player is updated. 1443c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * Must be called synchronized on mAppOpsLock. 1453c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi */ 1463c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi void updateAppOpsPlayAudio_sync() { 1473c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio; 1483c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi try { 1493c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, 1503c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mAttributes.getUsage(), 1513c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi Process.myUid(), ActivityThread.currentPackageName()); 1523c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mHasAppOpsPlayAudio = (mode == AppOpsManager.MODE_ALLOWED); 1533c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } catch (RemoteException e) { 1543c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi mHasAppOpsPlayAudio = false; 1553c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1563c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 1573c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi // AppsOps alters a player's volume; when the restriction changes, reflect it on the actual 1583c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi // volume used by the player 1593c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi try { 1603c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) { 1613c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi if (mHasAppOpsPlayAudio) { 1623c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi playerSetVolume(mLeftVolume, mRightVolume); 1633c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi playerSetAuxEffectSendLevel(mAuxEffectSendLevel); 1643c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } else { 1653c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi playerSetVolume(0.0f, 0.0f); 1663c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi playerSetAuxEffectSendLevel(0.0f); 1673c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1683c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1693c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } catch (Exception e) { 1703c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi // failing silently, player might not be in right state 1713c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1723c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1733c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 1743c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 1753c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi /** 1763c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * To be called by the subclass whenever an operation is potentially restricted. 1773c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * As the media player-common behavior are incorporated into this class, the subclass's need 1783c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * to call this method should be removed, and this method could become private. 1793c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * FIXME can this method be private so subclasses don't have to worry about when to check 1803c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * the restrictions. 1813c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi * @return 1823c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi */ 1833c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi boolean isRestricted_sync() { 1843c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { 1853c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi return false; 1863c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1873c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi return !mHasAppOpsPlayAudio; 1883c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi } 1893c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi 1903c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi // Abstract methods a subclass needs to implement 1913c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi abstract void playerSetVolume(float leftVolume, float rightVolume); 1923c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi abstract int playerSetAuxEffectSendLevel(float level); 1933c86a343dfca1b9e2e28c240dc894f60709e392cJean-Michel Trivi} 194