Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba50b97c authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Add new app ops for various interesting audio service things.

Media buttons: note when an application tries to take ownership
of the media buttons.
Audio focus: note when an application tries to take audio focus.
Volume levels: note changes to the volume level of the various
streams.

Maybe we should also have some ops for muting streams, soloing
streams, etc?

Change-Id: I79a5d477b0bad4ff61486cdb73ffb1196a674964
parent 72bd95b8
Loading
Loading
Loading
Loading
+37 −1
Original line number Diff line number Diff line
@@ -95,8 +95,17 @@ public class AppOpsManager {
    public static final int OP_PLAY_AUDIO = 28;
    public static final int OP_READ_CLIPBOARD = 29;
    public static final int OP_WRITE_CLIPBOARD = 30;
    public static final int OP_TAKE_MEDIA_BUTTONS = 31;
    public static final int OP_TAKE_AUDIO_FOCUS = 32;
    public static final int OP_AUDIO_MASTER_VOLUME = 33;
    public static final int OP_AUDIO_VOICE_VOLUME = 34;
    public static final int OP_AUDIO_RING_VOLUME = 35;
    public static final int OP_AUDIO_MEDIA_VOLUME = 36;
    public static final int OP_AUDIO_ALARM_VOLUME = 37;
    public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38;
    public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39;
    /** @hide */
    public static final int _NUM_OP = 31;
    public static final int _NUM_OP = 40;

    /**
     * This maps each operation to the operation that serves as the
@@ -138,6 +147,15 @@ public class AppOpsManager {
            OP_PLAY_AUDIO,
            OP_READ_CLIPBOARD,
            OP_WRITE_CLIPBOARD,
            OP_TAKE_MEDIA_BUTTONS,
            OP_TAKE_AUDIO_FOCUS,
            OP_AUDIO_MASTER_VOLUME,
            OP_AUDIO_VOICE_VOLUME,
            OP_AUDIO_RING_VOLUME,
            OP_AUDIO_MEDIA_VOLUME,
            OP_AUDIO_ALARM_VOLUME,
            OP_AUDIO_NOTIFICATION_VOLUME,
            OP_AUDIO_BLUETOOTH_VOLUME,
    };

    /**
@@ -176,6 +194,15 @@ public class AppOpsManager {
            "PLAY_AUDIO",
            "READ_CLIPBOARD",
            "WRITE_CLIPBOARD",
            "TAKE_MEDIA_BUTTONS",
            "TAKE_AUDIO_FOCUS",
            "AUDIO_MASTER_VOLUME",
            "AUDIO_VOICE_VOLUME",
            "AUDIO_RING_VOLUME",
            "AUDIO_MEDIA_VOLUME",
            "AUDIO_ALARM_VOLUME",
            "AUDIO_NOTIFICATION_VOLUME",
            "AUDIO_BLUETOOTH_VOLUME",
    };

    /**
@@ -214,6 +241,15 @@ public class AppOpsManager {
            null, // no permission for playing audio
            null, // no permission for reading clipboard
            null, // no permission for writing clipboard
            null, // no permission for taking media buttons
            null, // no permission for taking audio focus
            null, // no permission for changing master volume
            null, // no permission for changing voice volume
            null, // no permission for changing ring volume
            null, // no permission for changing media volume
            null, // no permission for changing alarm volume
            null, // no permission for changing notification volume
            null, // no permission for changing bluetooth volume
    };

    /**
+20 −17
Original line number Diff line number Diff line
@@ -551,9 +551,10 @@ public class AudioManager {
        IAudioService service = getService();
        try {
            if (mUseMasterVolume) {
                service.adjustMasterVolume(direction, flags);
                service.adjustMasterVolume(direction, flags, mContext.getBasePackageName());
            } else {
                service.adjustStreamVolume(streamType, direction, flags);
                service.adjustStreamVolume(streamType, direction, flags,
                        mContext.getBasePackageName());
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in adjustStreamVolume", e);
@@ -581,9 +582,9 @@ public class AudioManager {
        IAudioService service = getService();
        try {
            if (mUseMasterVolume) {
                service.adjustMasterVolume(direction, flags);
                service.adjustMasterVolume(direction, flags, mContext.getBasePackageName());
            } else {
                service.adjustVolume(direction, flags);
                service.adjustVolume(direction, flags, mContext.getBasePackageName());
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in adjustVolume", e);
@@ -611,9 +612,10 @@ public class AudioManager {
        IAudioService service = getService();
        try {
            if (mUseMasterVolume) {
                service.adjustMasterVolume(direction, flags);
                service.adjustMasterVolume(direction, flags, mContext.getBasePackageName());
            } else {
                service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
                service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags,
                        mContext.getBasePackageName());
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
@@ -632,7 +634,7 @@ public class AudioManager {
    public void adjustMasterVolume(int steps, int flags) {
        IAudioService service = getService();
        try {
            service.adjustMasterVolume(steps, flags);
            service.adjustMasterVolume(steps, flags, mContext.getBasePackageName());
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in adjustMasterVolume", e);
        }
@@ -784,9 +786,9 @@ public class AudioManager {
        IAudioService service = getService();
        try {
            if (mUseMasterVolume) {
                service.setMasterVolume(index, flags);
                service.setMasterVolume(index, flags, mContext.getBasePackageName());
            } else {
                service.setStreamVolume(streamType, index, flags);
                service.setStreamVolume(streamType, index, flags, mContext.getBasePackageName());
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in setStreamVolume", e);
@@ -843,16 +845,16 @@ public class AudioManager {
     * Sets the volume index for master volume.
     *
     * @param index The volume index to set. See
     *            {@link #getMasterMaxVolume(int)} for the largest valid value.
     *            {@link #getMasterMaxVolume()} for the largest valid value.
     * @param flags One or more flags.
     * @see #getMasterMaxVolume(int)
     * @see #getMasterVolume(int)
     * @see #getMasterMaxVolume()
     * @see #getMasterVolume()
     * @hide
     */
    public void setMasterVolume(int index, int flags) {
        IAudioService service = getService();
        try {
            service.setMasterVolume(index, flags);
            service.setMasterVolume(index, flags, mContext.getBasePackageName());
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in setMasterVolume", e);
        }
@@ -1563,7 +1565,8 @@ public class AudioManager {
        }
        IAudioService service = getService();
        try {
            service.adjustLocalOrRemoteStreamVolume(streamType, direction);
            service.adjustLocalOrRemoteStreamVolume(streamType, direction,
                    mContext.getBasePackageName());
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in adjustLocalOrRemoteStreamVolume", e);
        }
@@ -1582,7 +1585,7 @@ public class AudioManager {
     */
    /**
     * @hide
     * @deprecated Use {@link #setPrameters(String)} instead
     * @deprecated Use {@link #setParameters(String)} instead
     */
    @Deprecated public void setParameter(String key, String value) {
        setParameters(key+"="+value);
@@ -1964,7 +1967,7 @@ public class AudioManager {
        try {
            status = service.requestAudioFocus(streamType, durationHint, mICallBack,
                    mAudioFocusDispatcher, getIdForAudioFocusListener(l),
                    mContext.getPackageName() /* package name */);
                    mContext.getBasePackageName() /* package name */);
        } catch (RemoteException e) {
            Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);
        }
@@ -1986,7 +1989,7 @@ public class AudioManager {
        try {
            service.requestAudioFocus(streamType, durationHint, mICallBack, null,
                    AudioService.IN_VOICE_COMM_FOCUS_ID,
                    "system" /* dump-friendly package name */);
                    mContext.getBasePackageName());
        } catch (RemoteException e) {
            Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
        }
+67 −18
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.media.AudioManager.RINGER_MODE_VIBRATE;

import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
@@ -115,9 +116,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
    /** How long to delay before persisting a change in volume/ringer mode. */
    private static final int PERSIST_DELAY = 500;

    private Context mContext;
    private ContentResolver mContentResolver;
    private boolean mVoiceCapable;
    private final Context mContext;
    private final ContentResolver mContentResolver;
    private final AppOpsManager mAppOps;
    private final boolean mVoiceCapable;

    /** The UI */
    private VolumePanel mVolumePanel;
@@ -255,6 +257,23 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
    };
    private int[] mStreamVolumeAlias;

    /**
     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
     * after mapping through mStreamVolumeAlias.
     */
    private static final int[] STEAM_VOLUME_OPS = new int[] {
        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
    };

    private final boolean mUseFixedVolume;

    // stream names used by dumpStreamStates()
@@ -452,6 +471,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
    public AudioService(Context context) {
        mContext = context;
        mContentResolver = context.getContentResolver();
        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
        mVoiceCapable = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_voice_capable);

@@ -775,23 +795,26 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
    ///////////////////////////////////////////////////////////////////////////

    /** @see AudioManager#adjustVolume(int, int) */
    public void adjustVolume(int direction, int flags) {
        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags);
    public void adjustVolume(int direction, int flags, String callingPackage) {
        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags,
                callingPackage);
    }

    /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption
     *  on streamType: fixed to STREAM_MUSIC */
    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction) {
    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
            String callingPackage) {
        if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
        if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
        } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0);
            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0, callingPackage);
        }
    }

    /** @see AudioManager#adjustVolume(int, int) */
    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
            String callingPackage) {
        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
        int streamType;
        if (mVolumeControlStream != -1) {
@@ -814,12 +837,13 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
            //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()");
            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
        } else {
            adjustStreamVolume(streamType, direction, flags);
            adjustStreamVolume(streamType, direction, flags, callingPackage);
        }
    }

    /** @see AudioManager#adjustStreamVolume(int, int, int) */
    public void adjustStreamVolume(int streamType, int direction, int flags) {
    public void adjustStreamVolume(int streamType, int direction, int flags,
            String callingPackage) {
        if (mUseFixedVolume) {
            return;
        }
@@ -840,6 +864,11 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
        boolean adjustVolume = true;
        int step;

        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
                callingPackage) != AppOpsManager.MODE_ALLOWED) {
            return;
        }

        // reset any pending volume command
        synchronized (mSafeMediaVolumeState) {
            mPendingVolumeCommand = null;
@@ -905,7 +934,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
    }

    /** @see AudioManager#adjustMasterVolume(int, int) */
    public void adjustMasterVolume(int steps, int flags) {
    public void adjustMasterVolume(int steps, int flags, String callingPackage) {
        if (mUseFixedVolume) {
            return;
        }
@@ -920,7 +949,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
        }

        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
        setMasterVolume(volume, flags);
        setMasterVolume(volume, flags, callingPackage);
    }

    // StreamVolumeCommand contains the information needed to defer the process of
@@ -956,27 +985,33 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
    }

    /** @see AudioManager#setStreamVolume(int, int, int) */
    public void setStreamVolume(int streamType, int index, int flags) {
    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
        if (mUseFixedVolume) {
            return;
        }

        ensureValidStreamType(streamType);
        VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]];
        int streamTypeAlias = mStreamVolumeAlias[streamType];
        VolumeStreamState streamState = mStreamStates[streamTypeAlias];

        final int device = getDeviceForStream(streamType);
        int oldIndex;

        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
                callingPackage) != AppOpsManager.MODE_ALLOWED) {
            return;
        }

        synchronized (mSafeMediaVolumeState) {
            // reset any pending volume command
            mPendingVolumeCommand = null;

            oldIndex = streamState.getIndex(device);

            index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]);
            index = rescaleIndex(index * 10, streamType, streamTypeAlias);

            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
            if ((mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
                    ((device & mFixedVolumeDevices) != 0)) {
                flags |= AudioManager.FLAG_FIXED_VOLUME;

@@ -991,7 +1026,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
                }
            }

            if (!checkSafeMediaVolume(mStreamVolumeAlias[streamType], index, device)) {
            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
                mVolumePanel.postDisplaySafeVolumeWarning(flags);
                mPendingVolumeCommand = new StreamVolumeCommand(
                                                    streamType, index, flags, device);
@@ -1249,11 +1284,16 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
        return getLastAudibleMasterVolume();
    }

    public void setMasterVolume(int volume, int flags) {
    public void setMasterVolume(int volume, int flags, String callingPackage) {
        if (mUseFixedVolume) {
            return;
        }

        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
                callingPackage) != AppOpsManager.MODE_ALLOWED) {
            return;
        }

        if (volume < 0) {
            volume = 0;
        } else if (volume > MAX_MASTER_VOLUME) {
@@ -4382,6 +4422,11 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        }

        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
                callingPackageName) != AppOpsManager.MODE_ALLOWED) {
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        }

        synchronized(mAudioFocusLock) {
            if (!canReassignAudioFocus()) {
                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
@@ -5182,6 +5227,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
            return;
        }
        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(),
                mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) {
            return;
        }
        RemoteControlStackEntry rcse = null;
        boolean wasInsideStack = false;
        try {
+9 −7
Original line number Diff line number Diff line
@@ -34,21 +34,23 @@ import android.view.KeyEvent;
 */
interface IAudioService {
    
    void adjustVolume(int direction, int flags);
    void adjustVolume(int direction, int flags, String callingPackage);

    oneway void adjustLocalOrRemoteStreamVolume(int streamType, int direction);
    oneway void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
            String callingPackage);

    void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags);
    void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
            String callingPackage);

    void adjustStreamVolume(int streamType, int direction, int flags);
    void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage);

    void adjustMasterVolume(int direction, int flags);
    void adjustMasterVolume(int direction, int flags, String callingPackage);

    void setStreamVolume(int streamType, int index, int flags);
    void setStreamVolume(int streamType, int index, int flags, String callingPackage);

    oneway void setRemoteStreamVolume(int index);

    void setMasterVolume(int index, int flags);
    void setMasterVolume(int index, int flags, String callingPackage);
    
    void setStreamSolo(int streamType, boolean state, IBinder cb);
   	
+5 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.media;

import android.app.ActivityThread;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -1162,7 +1163,8 @@ public class MediaRouter {
        public void requestSetVolume(int volume) {
            if (mPlaybackType == PLAYBACK_TYPE_LOCAL) {
                try {
                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0);
                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0,
                            ActivityThread.currentPackageName());
                } catch (RemoteException e) {
                    Log.e(TAG, "Error setting local stream volume", e);
                }
@@ -1182,7 +1184,8 @@ public class MediaRouter {
                try {
                    final int volume =
                            Math.max(0, Math.min(getVolume() + direction, getVolumeMax()));
                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0);
                    sStatic.mAudioService.setStreamVolume(mPlaybackStream, volume, 0,
                            ActivityThread.currentPackageName());
                } catch (RemoteException e) {
                    Log.e(TAG, "Error setting local stream volume", e);
                }
Loading