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