summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Spurlock <jspurlock@google.com>2014-03-10 08:33:35 -0400
committerJohn Spurlock <jspurlock@google.com>2014-03-19 15:32:51 -0400
commit1af30c7ac480e5d335f267a3ac3b2e6c748ce240 (patch)
tree584362f9abb3f28a21f144811fd86fc2bc3c73f0
parent31dc8f701fb14e185bf1c1b35d68bd7d1a42a54a (diff)
downloadframeworks_base-1af30c7ac480e5d335f267a3ac3b2e6c748ce240.zip
frameworks_base-1af30c7ac480e5d335f267a3ac3b2e6c748ce240.tar.gz
frameworks_base-1af30c7ac480e5d335f267a3ac3b2e6c748ce240.tar.bz2
Add stream-level suppression to vibrate/audio services.
- Add new audio restriction layer to app-ops. Restrictions add additional constraints to audio operations at a stream-level. Restrictions do not affect the persistable state, and are purely additive: that is, they can only impose additional contstraints, not enable something that has already been disabled. Restrictions also support a whitelisted set of exempt package names. - Add new audio stream-level checks to app-ops. - Implement a provisional OP_PLAY_AUDIO suppression to three java entry points MediaPlayer, AudioTrack, & SoundPool. - Enhance vibrator api to take stream information as an optional hint - the constants correspond to AudioManager stream types. OP_VIBRATE now supports the stream-level restriction check. - Simplify Vibrator subclasses by adding default implementations for two .vibrate calls. - Migrate NoMan's zen-mode control to use the new app-ops stream-level restriction mechanism. Change-Id: Ifae8952647202f728cf1c73e881452660c704678
-rw-r--r--api/current.txt6
-rw-r--r--core/java/android/app/AppOpsManager.java48
-rw-r--r--core/java/android/hardware/input/InputManager.java28
-rw-r--r--core/java/android/os/IVibratorService.aidl4
-rw-r--r--core/java/android/os/NullVibrator.java20
-rw-r--r--core/java/android/os/SystemVibrator.java25
-rw-r--r--core/java/android/os/Vibrator.java74
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl2
-rw-r--r--media/java/android/media/AudioService.java8
-rw-r--r--media/java/android/media/AudioTrack.java37
-rw-r--r--media/java/android/media/MediaPlayer.java59
-rw-r--r--media/java/android/media/SoundPool.java43
-rw-r--r--media/jni/android_media_MediaPlayer.cpp21
-rw-r--r--media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp4
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindowManager.java4
-rw-r--r--services/core/java/com/android/server/AppOpsService.java87
-rw-r--r--services/core/java/com/android/server/VibratorService.java28
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java113
18 files changed, 437 insertions, 174 deletions
diff --git a/api/current.txt b/api/current.txt
index e72354b..139e927 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -19546,8 +19546,10 @@ package android.os {
public abstract class Vibrator {
method public abstract void cancel();
method public abstract boolean hasVibrator();
- method public abstract void vibrate(long);
- method public abstract void vibrate(long[], int);
+ method public void vibrate(long);
+ method public void vibrate(long, int);
+ method public void vibrate(long[], int);
+ method public void vibrate(long[], int, int);
}
public class WorkSource implements android.os.Parcelable {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 079cf7a..b616c1e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -780,6 +780,25 @@ public class AppOpsManager {
}
}
+ /**
+ * Set a non-persisted restriction on an audio operation at a stream-level.
+ * Restrictions are temporary additional constraints imposed on top of the persisted rules
+ * defined by {@link #setMode}.
+ *
+ * @param code The operation to restrict.
+ * @param stream The {@link android.media.AudioManager} stream type.
+ * @param mode The restriction mode (MODE_IGNORED,MODE_ERRORED) or MODE_ALLOWED to unrestrict.
+ * @param exceptionPackages Optional list of packages to exclude from the restriction.
+ * @hide
+ */
+ public void setRestriction(int code, int stream, int mode, String[] exceptionPackages) {
+ try {
+ final int uid = Binder.getCallingUid();
+ mService.setAudioRestriction(code, stream, uid, mode, exceptionPackages);
+ } catch (RemoteException e) {
+ }
+ }
+
/** @hide */
public void resetAllModes() {
try {
@@ -1009,6 +1028,35 @@ public class AppOpsManager {
}
/**
+ * Like {@link #checkOp} but at a stream-level for audio operations.
+ * @hide
+ */
+ public int checkAudioOp(int op, int stream, int uid, String packageName) {
+ try {
+ final int mode = mService.checkAudioOperation(op, stream, uid, packageName);
+ if (mode == MODE_ERRORED) {
+ throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
+ }
+ return mode;
+ } catch (RemoteException e) {
+ }
+ return MODE_IGNORED;
+ }
+
+ /**
+ * Like {@link #checkAudioOp} but instead of throwing a {@link SecurityException} it
+ * returns {@link #MODE_ERRORED}.
+ * @hide
+ */
+ public int checkAudioOpNoThrow(int op, int stream, int uid, String packageName) {
+ try {
+ return mService.checkAudioOperation(op, stream, uid, packageName);
+ } catch (RemoteException e) {
+ }
+ return MODE_IGNORED;
+ }
+
+ /**
* Make note of an application performing an operation. Note that you must pass
* in both the uid and name of the application to be checked; this function will verify
* that these two match, and if not, return {@link #MODE_IGNORED}. If this call
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index e3a3830..0c0dfe9 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -853,13 +853,21 @@ public final class InputManager {
return true;
}
+ /**
+ * @hide
+ */
@Override
- public void vibrate(long milliseconds) {
+ public void vibrate(int owningUid, String owningPackage, long milliseconds,
+ int streamHint) {
vibrate(new long[] { 0, milliseconds}, -1);
}
+ /**
+ * @hide
+ */
@Override
- public void vibrate(long[] pattern, int repeat) {
+ public void vibrate(int owningUid, String owningPackage, long[] pattern, int repeat,
+ int streamHint) {
if (repeat >= pattern.length) {
throw new ArrayIndexOutOfBoundsException();
}
@@ -870,22 +878,6 @@ public final class InputManager {
}
}
- /**
- * @hide
- */
- @Override
- public void vibrate(int owningUid, String owningPackage, long milliseconds) {
- vibrate(milliseconds);
- }
-
- /**
- * @hide
- */
- @Override
- public void vibrate(int owningUid, String owningPackage, long[] pattern, int repeat) {
- vibrate(pattern, repeat);
- }
-
@Override
public void cancel() {
try {
diff --git a/core/java/android/os/IVibratorService.aidl b/core/java/android/os/IVibratorService.aidl
index 456ffb1..4854bc0 100644
--- a/core/java/android/os/IVibratorService.aidl
+++ b/core/java/android/os/IVibratorService.aidl
@@ -20,8 +20,8 @@ package android.os;
interface IVibratorService
{
boolean hasVibrator();
- void vibrate(int uid, String packageName, long milliseconds, IBinder token);
- void vibratePattern(int uid, String packageName, in long[] pattern, int repeat, IBinder token);
+ void vibrate(int uid, String packageName, long milliseconds, int streamHint, IBinder token);
+ void vibratePattern(int uid, String packageName, in long[] pattern, int repeat, int streamHint, IBinder token);
void cancelVibrate(IBinder token);
}
diff --git a/core/java/android/os/NullVibrator.java b/core/java/android/os/NullVibrator.java
index af90bdb..536da32 100644
--- a/core/java/android/os/NullVibrator.java
+++ b/core/java/android/os/NullVibrator.java
@@ -36,22 +36,11 @@ public class NullVibrator extends Vibrator {
return false;
}
- @Override
- public void vibrate(long milliseconds) {
- }
-
- @Override
- public void vibrate(long[] pattern, int repeat) {
- if (repeat >= pattern.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
- }
-
/**
* @hide
*/
@Override
- public void vibrate(int owningUid, String owningPackage, long milliseconds) {
+ public void vibrate(int owningUid, String owningPackage, long milliseconds, int streamHint) {
vibrate(milliseconds);
}
@@ -59,8 +48,11 @@ public class NullVibrator extends Vibrator {
* @hide
*/
@Override
- public void vibrate(int owningUid, String owningPackage, long[] pattern, int repeat) {
- vibrate(pattern, repeat);
+ public void vibrate(int owningUid, String owningPackage, long[] pattern, int repeat,
+ int streamHint) {
+ if (repeat >= pattern.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
}
@Override
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index 700f80d..13bc4f6 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -16,7 +16,6 @@
package android.os;
-import android.app.ActivityThread;
import android.content.Context;
import android.util.Log;
@@ -28,18 +27,16 @@ import android.util.Log;
public class SystemVibrator extends Vibrator {
private static final String TAG = "Vibrator";
- private final String mPackageName;
private final IVibratorService mService;
private final Binder mToken = new Binder();
public SystemVibrator() {
- mPackageName = ActivityThread.currentPackageName();
mService = IVibratorService.Stub.asInterface(
ServiceManager.getService("vibrator"));
}
public SystemVibrator(Context context) {
- mPackageName = context.getOpPackageName();
+ super(context);
mService = IVibratorService.Stub.asInterface(
ServiceManager.getService("vibrator"));
}
@@ -57,27 +54,17 @@ public class SystemVibrator extends Vibrator {
return false;
}
- @Override
- public void vibrate(long milliseconds) {
- vibrate(Process.myUid(), mPackageName, milliseconds);
- }
-
- @Override
- public void vibrate(long[] pattern, int repeat) {
- vibrate(Process.myUid(), mPackageName, pattern, repeat);
- }
-
/**
* @hide
*/
@Override
- public void vibrate(int owningUid, String owningPackage, long milliseconds) {
+ public void vibrate(int owningUid, String owningPackage, long milliseconds, int streamHint) {
if (mService == null) {
Log.w(TAG, "Failed to vibrate; no vibrator service.");
return;
}
try {
- mService.vibrate(owningUid, owningPackage, milliseconds, mToken);
+ mService.vibrate(owningUid, owningPackage, milliseconds, streamHint, mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
}
@@ -87,7 +74,8 @@ public class SystemVibrator extends Vibrator {
* @hide
*/
@Override
- public void vibrate(int owningUid, String owningPackage, long[] pattern, int repeat) {
+ public void vibrate(int owningUid, String owningPackage, long[] pattern, int repeat,
+ int streamHint) {
if (mService == null) {
Log.w(TAG, "Failed to vibrate; no vibrator service.");
return;
@@ -97,7 +85,8 @@ public class SystemVibrator extends Vibrator {
// anyway
if (repeat < pattern.length) {
try {
- mService.vibratePattern(owningUid, owningPackage, pattern, repeat, mToken);
+ mService.vibratePattern(owningUid, owningPackage, pattern, repeat, streamHint,
+ mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
}
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 5d55143..53034d8 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -16,7 +16,9 @@
package android.os;
+import android.app.ActivityThread;
import android.content.Context;
+import android.media.AudioManager;
/**
* Class that operates the vibrator on the device.
@@ -28,10 +30,21 @@ import android.content.Context;
* {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as the argument.
*/
public abstract class Vibrator {
+
+ private final String mPackageName;
+
/**
* @hide to prevent subclassing from outside of the framework
*/
public Vibrator() {
+ mPackageName = ActivityThread.currentPackageName();
+ }
+
+ /**
+ * @hide to prevent subclassing from outside of the framework
+ */
+ protected Vibrator(Context context) {
+ mPackageName = context.getOpPackageName();
}
/**
@@ -40,7 +53,7 @@ public abstract class Vibrator {
* @return True if the hardware has a vibrator, else false.
*/
public abstract boolean hasVibrator();
-
+
/**
* Vibrate constantly for the specified period of time.
* <p>This method requires the caller to hold the permission
@@ -48,7 +61,23 @@ public abstract class Vibrator {
*
* @param milliseconds The number of milliseconds to vibrate.
*/
- public abstract void vibrate(long milliseconds);
+ public void vibrate(long milliseconds) {
+ vibrate(milliseconds, AudioManager.USE_DEFAULT_STREAM_TYPE);
+ }
+
+ /**
+ * Vibrate constantly for the specified period of time.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#VIBRATE}.
+ *
+ * @param milliseconds The number of milliseconds to vibrate.
+ * @param streamHint An {@link AudioManager} stream type corresponding to the vibration type.
+ * For example, specify {@link AudioManager.STREAM_ALARM} for alarm vibrations or
+ * {@link AudioManager.STREAM_RING} for vibrations associated with incoming calls.
+ */
+ public void vibrate(long milliseconds, int streamHint) {
+ vibrate(Process.myUid(), mPackageName, milliseconds, streamHint);
+ }
/**
* Vibrate with a given pattern.
@@ -70,21 +99,52 @@ public abstract class Vibrator {
* @param repeat the index into pattern at which to repeat, or -1 if
* you don't want to repeat.
*/
- public abstract void vibrate(long[] pattern, int repeat);
+ public void vibrate(long[] pattern, int repeat) {
+ vibrate(pattern, repeat, AudioManager.USE_DEFAULT_STREAM_TYPE);
+ }
+
+ /**
+ * Vibrate with a given pattern.
+ *
+ * <p>
+ * Pass in an array of ints that are the durations for which to turn on or off
+ * the vibrator in milliseconds. The first value indicates the number of milliseconds
+ * to wait before turning the vibrator on. The next value indicates the number of milliseconds
+ * for which to keep the vibrator on before turning it off. Subsequent values alternate
+ * between durations in milliseconds to turn the vibrator off or to turn the vibrator on.
+ * </p><p>
+ * To cause the pattern to repeat, pass the index into the pattern array at which
+ * to start the repeat, or -1 to disable repeating.
+ * </p>
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#VIBRATE}.
+ *
+ * @param pattern an array of longs of times for which to turn the vibrator on or off.
+ * @param repeat the index into pattern at which to repeat, or -1 if
+ * you don't want to repeat.
+ * @param streamHint An {@link AudioManager} stream type corresponding to the vibration type.
+ * For example, specify {@link AudioManager.STREAM_ALARM} for alarm vibrations or
+ * {@link AudioManager.STREAM_RING} for vibrations associated with incoming calls.
+ */
+ public void vibrate(long[] pattern, int repeat, int streamHint) {
+ vibrate(Process.myUid(), mPackageName, pattern, repeat, streamHint);
+ }
/**
* @hide
- * Like {@link #vibrate(long)}, but allowing the caller to specify that
+ * Like {@link #vibrate(long, int)}, but allowing the caller to specify that
* the vibration is owned by someone else.
*/
- public abstract void vibrate(int owningUid, String owningPackage, long milliseconds);
+ public abstract void vibrate(int owningUid, String owningPackage,
+ long milliseconds, int streamHint);
/**
* @hide
- * Like {@link #vibrate(long[], int)}, but allowing the caller to specify that
+ * Like {@link #vibrate(long[], int, int)}, but allowing the caller to specify that
* the vibration is owned by someone else.
*/
- public abstract void vibrate(int owningUid, String owningPackage, long[] pattern, int repeat);
+ public abstract void vibrate(int owningUid, String owningPackage,
+ long[] pattern, int repeat, int streamHint);
/**
* Turn the vibrator off.
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 16c41f3..cd75010 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -36,4 +36,6 @@ interface IAppOpsService {
List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
void setMode(int code, int uid, String packageName, int mode);
void resetAllModes();
+ int checkAudioOperation(int code, int stream, int uid, String packageName);
+ void setAudioRestriction(int code, int stream, int uid, int mode, in String[] exceptionPackages);
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 46b74da..fe510f6 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -258,7 +258,7 @@ public class AudioService extends IAudioService.Stub {
private final boolean mUseFixedVolume;
// stream names used by dumpStreamStates()
- private final String[] STREAM_NAMES = new String[] {
+ private static final String[] STREAM_NAMES = new String[] {
"STREAM_VOICE_CALL",
"STREAM_SYSTEM",
"STREAM_RING",
@@ -614,6 +614,12 @@ public class AudioService extends IAudioService.Stub {
pw.println(Integer.toHexString(mMuteAffectedStreams));
}
+ /** @hide */
+ public static String streamToString(int stream) {
+ if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
+ if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
+ return "UNKNOWN_STREAM_" + stream;
+ }
private void updateStreamVolumeAlias(boolean updateVolumes) {
int dtmfStreamAlias;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 5611efb..dee8705 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -23,11 +23,20 @@ import java.nio.ByteBuffer;
import java.nio.NioUtils;
import android.annotation.IntDef;
+import android.app.ActivityThread;
+import android.app.AppOpsManager;
+import android.content.Context;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
+import com.android.internal.app.IAppOpsService;
+
/**
* The AudioTrack class manages and plays a single audio resource for Java applications.
@@ -239,7 +248,10 @@ public class AudioTrack
* Audio session ID
*/
private int mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
-
+ /**
+ * Reference to the app-ops service.
+ */
+ private final IAppOpsService mAppOps;
//--------------------------------
// Used exclusively by native code
@@ -343,6 +355,9 @@ public class AudioTrack
audioBuffSizeCheck(bufferSizeInBytes);
+ IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
+ mAppOps = IAppOpsService.Stub.asInterface(b);
+
if (sessionId < 0) {
throw new IllegalArgumentException("Invalid audio session ID: "+sessionId);
}
@@ -841,6 +856,9 @@ public class AudioTrack
* {@link #ERROR_INVALID_OPERATION}
*/
public int setStereoVolume(float leftVolume, float rightVolume) {
+ if (isRestricted()) {
+ return SUCCESS;
+ }
if (mState == STATE_UNINITIALIZED) {
return ERROR_INVALID_OPERATION;
}
@@ -1014,13 +1032,25 @@ public class AudioTrack
if (mState != STATE_INITIALIZED) {
throw new IllegalStateException("play() called on uninitialized AudioTrack.");
}
-
+ if (isRestricted()) {
+ setVolume(0);
+ }
synchronized(mPlayStateLock) {
native_start();
mPlayState = PLAYSTATE_PLAYING;
}
}
+ private boolean isRestricted() {
+ try {
+ final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, mStreamType,
+ Process.myUid(), ActivityThread.currentPackageName());
+ return mode != AppOpsManager.MODE_ALLOWED;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
/**
* Stops playing the audio data.
* When used on an instance created in {@link #MODE_STREAM} mode, audio will stop playing
@@ -1296,6 +1326,9 @@ public class AudioTrack
* {@link #ERROR_INVALID_OPERATION}
*/
public int setAuxEffectSendLevel(float level) {
+ if (isRestricted()) {
+ return SUCCESS;
+ }
if (mState == STATE_UNINITIALIZED) {
return ERROR_INVALID_OPERATION;
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index e20a4af..1b92410 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -16,6 +16,8 @@
package android.media;
+import android.app.ActivityThread;
+import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -32,6 +34,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -42,6 +46,8 @@ import android.media.MediaTimeProvider;
import android.media.SubtitleController;
import android.media.SubtitleData;
+import com.android.internal.app.IAppOpsService;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -576,6 +582,8 @@ public class MediaPlayer implements SubtitleController.Listener
private PowerManager.WakeLock mWakeLock = null;
private boolean mScreenOnWhilePlaying;
private boolean mStayAwake;
+ private final IAppOpsService mAppOps;
+ private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
/**
* Default constructor. Consider using one of the create() methods for
@@ -599,6 +607,8 @@ public class MediaPlayer implements SubtitleController.Listener
mOutOfBandSubtitleTracks = new Vector<SubtitleTrack>();
mOpenSubtitleSources = new Vector<InputStream>();
mInbandSubtitleTracks = new SubtitleTrack[0];
+ IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
+ mAppOps = IAppOpsService.Stub.asInterface(b);
/* Native setup requires a weak reference to our object.
* It's easier to create it here than in C++.
@@ -1055,13 +1065,35 @@ public class MediaPlayer implements SubtitleController.Listener
*
* @throws IllegalStateException if it is called in an invalid state
*/
- public void start() throws IllegalStateException {
+ public void start() throws IllegalStateException {
+ if (isRestricted()) {
+ _setVolume(0, 0);
+ }
stayAwake(true);
_start();
}
private native void _start() throws IllegalStateException;
+ private boolean isRestricted() {
+ try {
+ final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
+ getAudioStreamType(), Process.myUid(), ActivityThread.currentPackageName());
+ return mode != AppOpsManager.MODE_ALLOWED;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ private int getAudioStreamType() {
+ if (mStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+ mStreamType = _getAudioStreamType();
+ }
+ return mStreamType;
+ }
+
+ private native int _getAudioStreamType() throws IllegalStateException;
+
/**
* Stops playback after playback has been stopped or paused.
*
@@ -1402,7 +1434,12 @@ public class MediaPlayer implements SubtitleController.Listener
* @param streamtype the audio stream type
* @see android.media.AudioManager
*/
- public native void setAudioStreamType(int streamtype);
+ public void setAudioStreamType(int streamtype) {
+ _setAudioStreamType(streamtype);
+ mStreamType = streamtype;
+ }
+
+ private native void _setAudioStreamType(int streamtype);
/**
* Sets the player to be looping or non-looping.
@@ -1435,7 +1472,14 @@ public class MediaPlayer implements SubtitleController.Listener
* The single parameter form below is preferred if the channel volumes don't need
* to be set independently.
*/
- public native void setVolume(float leftVolume, float rightVolume);
+ public void setVolume(float leftVolume, float rightVolume) {
+ if (isRestricted()) {
+ return;
+ }
+ _setVolume(leftVolume, rightVolume);
+ }
+
+ private native void _setVolume(float leftVolume, float rightVolume);
/**
* Similar, excepts sets volume of all channels to same value.
@@ -1500,7 +1544,14 @@ public class MediaPlayer implements SubtitleController.Listener
* 0 < x <= R -> level = 10^(72*(x-R)/20/R)
* @param level send level scalar
*/
- public native void setAuxEffectSendLevel(float level);
+ public void setAuxEffectSendLevel(float level) {
+ if (isRestricted()) {
+ return;
+ }
+ _setAuxEffectSendLevel(level);
+ }
+
+ private native void _setAuxEffectSendLevel(float level);
/*
* @param request Parcel destinated to the media player. The
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index f1b256e..14f0c69 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -20,16 +20,24 @@ import java.io.File;
import java.io.FileDescriptor;
import java.lang.ref.WeakReference;
+import android.app.ActivityThread;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.util.AndroidRuntimeException;
import android.util.Log;
+import com.android.internal.app.IAppOpsService;
+
/**
* The SoundPool class manages and plays audio resources for applications.
@@ -449,6 +457,8 @@ public class SoundPool {
private SoundPool mProxy;
private final Object mLock;
+ private final int mStreamType;
+ private final IAppOpsService mAppOps;
// SoundPool messages
//
@@ -463,6 +473,9 @@ public class SoundPool {
}
mLock = new Object();
mProxy = proxy;
+ mStreamType = streamType;
+ IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
+ mAppOps = IAppOpsService.Stub.asInterface(b);
}
public int load(String path, int priority)
@@ -522,9 +535,27 @@ public class SoundPool {
public native final boolean unload(int soundID);
- public native final int play(int soundID, float leftVolume, float rightVolume,
+ public final int play(int soundID, float leftVolume, float rightVolume,
+ int priority, int loop, float rate) {
+ if (isRestricted()) {
+ leftVolume = rightVolume = 0;
+ }
+ return _play(soundID, leftVolume, rightVolume, priority, loop, rate);
+ }
+
+ public native final int _play(int soundID, float leftVolume, float rightVolume,
int priority, int loop, float rate);
+ private boolean isRestricted() {
+ try {
+ final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
+ mStreamType, Process.myUid(), ActivityThread.currentPackageName());
+ return mode != AppOpsManager.MODE_ALLOWED;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
public native final void pause(int streamID);
public native final void resume(int streamID);
@@ -535,8 +566,14 @@ public class SoundPool {
public native final void stop(int streamID);
- public native final void setVolume(int streamID,
- float leftVolume, float rightVolume);
+ public final void setVolume(int streamID, float leftVolume, float rightVolume) {
+ if (isRestricted()) {
+ return;
+ }
+ _setVolume(streamID, leftVolume, rightVolume);
+ }
+
+ private native final void _setVolume(int streamID, float leftVolume, float rightVolume);
public void setVolume(int streamID, float volume) {
setVolume(streamID, volume, volume);
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index dc3ae5b..abebd48 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -500,6 +500,20 @@ android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, jint str
process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL );
}
+static jint
+android_media_MediaPlayer_getAudioStreamType(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return 0;
+ }
+ audio_stream_type_t streamtype;
+ process_media_player_call( env, thiz, mp->getAudioStreamType(&streamtype), NULL, NULL );
+ ALOGV("getAudioStreamType: %d (streamtype)", streamtype);
+ return (jint) streamtype;
+}
+
static void
android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
{
@@ -841,10 +855,11 @@ static JNINativeMethod gMethods[] = {
{"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration},
{"_release", "()V", (void *)android_media_MediaPlayer_release},
{"_reset", "()V", (void *)android_media_MediaPlayer_reset},
- {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
+ {"_setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
+ {"_getAudioStreamType", "()I", (void *)android_media_MediaPlayer_getAudioStreamType},
{"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
{"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
- {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
+ {"_setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
{"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
{"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
{"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
@@ -853,7 +868,7 @@ static JNINativeMethod gMethods[] = {
{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
{"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
{"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
- {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
+ {"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
{"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect},
{"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
{"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint},
diff --git a/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp b/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp
index 9cc55ab..bda3b6b 100644
--- a/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp
+++ b/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp
@@ -229,7 +229,7 @@ static JNINativeMethod gMethods[] = {
"(I)Z",
(void *)android_media_SoundPool_SoundPoolImpl_unload
},
- { "play",
+ { "_play",
"(IFFIIF)I",
(void *)android_media_SoundPool_SoundPoolImpl_play
},
@@ -253,7 +253,7 @@ static JNINativeMethod gMethods[] = {
"(I)V",
(void *)android_media_SoundPool_SoundPoolImpl_stop
},
- { "setVolume",
+ { "_setVolume",
"(IFF)V",
(void *)android_media_SoundPool_SoundPoolImpl_setVolume
},
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1cca164..afa68da 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -5083,10 +5083,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if (pattern.length == 1) {
// One-shot vibration
- mVibrator.vibrate(owningUid, owningPackage, pattern[0]);
+ mVibrator.vibrate(owningUid, owningPackage, pattern[0], AudioManager.STREAM_SYSTEM);
} else {
// Pattern vibration
- mVibrator.vibrate(owningUid, owningPackage, pattern, -1);
+ mVibrator.vibrate(owningUid, owningPackage, pattern, -1, AudioManager.STREAM_SYSTEM);
}
return true;
}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index e5615c0..e26747c 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -33,6 +33,7 @@ import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.media.AudioService;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Handler;
@@ -42,6 +43,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Pair;
@@ -123,6 +125,8 @@ public class AppOpsService extends IAppOpsService.Stub {
= new ArrayMap<String, ArrayList<Callback>>();
final ArrayMap<IBinder, Callback> mModeWatchers
= new ArrayMap<IBinder, Callback>();
+ final SparseArray<SparseArray<Restriction>> mAudioRestrictions
+ = new SparseArray<SparseArray<Restriction>>();
public final class Callback implements DeathRecipient {
final IAppOpsCallback mCallback;
@@ -553,6 +557,58 @@ public class AppOpsService extends IAppOpsService.Stub {
}
@Override
+ public int checkAudioOperation(int code, int stream, int uid, String packageName) {
+ synchronized (this) {
+ final int mode = checkRestrictionLocked(code, stream, uid, packageName);
+ if (mode != AppOpsManager.MODE_ALLOWED) {
+ return mode;
+ }
+ }
+ return checkOperation(code, uid, packageName);
+ }
+
+ private int checkRestrictionLocked(int code, int stream, int uid, String packageName) {
+ final SparseArray<Restriction> streamRestrictions = mAudioRestrictions.get(code);
+ if (streamRestrictions != null) {
+ final Restriction r = streamRestrictions.get(stream);
+ if (r != null && !r.exceptionPackages.contains(packageName)) {
+ return r.mode;
+ }
+ }
+ return AppOpsManager.MODE_ALLOWED;
+ }
+
+ @Override
+ public void setAudioRestriction(int code, int stream, int uid, int mode,
+ String[] exceptionPackages) {
+ verifyIncomingUid(uid);
+ verifyIncomingOp(code);
+ synchronized (this) {
+ SparseArray<Restriction> streamRestrictions = mAudioRestrictions.get(code);
+ if (streamRestrictions == null) {
+ streamRestrictions = new SparseArray<Restriction>();
+ mAudioRestrictions.put(code, streamRestrictions);
+ }
+ streamRestrictions.remove(stream);
+ if (mode != AppOpsManager.MODE_ALLOWED) {
+ final Restriction r = new Restriction();
+ r.mode = mode;
+ if (exceptionPackages != null) {
+ final int N = exceptionPackages.length;
+ r.exceptionPackages = new ArraySet<String>(N);
+ for (int i = 0; i < N; i++) {
+ final String pkg = exceptionPackages[i];
+ if (pkg != null) {
+ r.exceptionPackages.add(pkg.trim());
+ }
+ }
+ }
+ streamRestrictions.put(stream, r);
+ }
+ }
+ }
+
+ @Override
public int checkPackage(int uid, String packageName) {
synchronized (this) {
if (getOpsLocked(uid, packageName, true) != null) {
@@ -1048,6 +1104,31 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
}
+ if (mAudioRestrictions.size() > 0) {
+ boolean printedHeader = false;
+ for (int o=0; o<mAudioRestrictions.size(); o++) {
+ final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
+ final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
+ for (int i=0; i<restrictions.size(); i++) {
+ if (!printedHeader){
+ pw.println(" Audio Restrictions:");
+ printedHeader = true;
+ needSep = true;
+ }
+ final int stream = restrictions.keyAt(i);
+ pw.print(" "); pw.print(op);
+ pw.print(" stream="); pw.print(AudioService.streamToString(stream));
+ Restriction r = restrictions.valueAt(i);
+ pw.print(": mode="); pw.println(r.mode);
+ if (!r.exceptionPackages.isEmpty()) {
+ pw.println(" Exceptions:");
+ for (int j=0; j<r.exceptionPackages.size(); j++) {
+ pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
+ }
+ }
+ }
+ }
+ }
if (needSep) {
pw.println();
}
@@ -1080,4 +1161,10 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
}
+
+ private static final class Restriction {
+ private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
+ int mode;
+ ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
+ }
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 28eb948..52f9aa9 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -84,24 +84,27 @@ public class VibratorService extends IVibratorService.Stub
private final long mStartTime;
private final long[] mPattern;
private final int mRepeat;
+ private final int mStreamHint;
private final int mUid;
private final String mPackageName;
- Vibration(IBinder token, long millis, int uid, String packageName) {
- this(token, millis, null, 0, uid, packageName);
+ Vibration(IBinder token, long millis, int streamHint, int uid, String packageName) {
+ this(token, millis, null, 0, streamHint, uid, packageName);
}
- Vibration(IBinder token, long[] pattern, int repeat, int uid, String packageName) {
- this(token, 0, pattern, repeat, uid, packageName);
+ Vibration(IBinder token, long[] pattern, int repeat, int streamHint, int uid,
+ String packageName) {
+ this(token, 0, pattern, repeat, streamHint, uid, packageName);
}
private Vibration(IBinder token, long millis, long[] pattern,
- int repeat, int uid, String packageName) {
+ int repeat, int streamHint, int uid, String packageName) {
mToken = token;
mTimeout = millis;
mStartTime = SystemClock.uptimeMillis();
mPattern = pattern;
mRepeat = repeat;
+ mStreamHint = streamHint;
mUid = uid;
mPackageName = packageName;
}
@@ -191,7 +194,8 @@ public class VibratorService extends IVibratorService.Stub
Binder.getCallingPid(), Binder.getCallingUid(), null);
}
- public void vibrate(int uid, String packageName, long milliseconds, IBinder token) {
+ public void vibrate(int uid, String packageName, long milliseconds, int streamHint,
+ IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
@@ -207,7 +211,7 @@ public class VibratorService extends IVibratorService.Stub
return;
}
- Vibration vib = new Vibration(token, milliseconds, uid, packageName);
+ Vibration vib = new Vibration(token, milliseconds, streamHint, uid, packageName);
final long ident = Binder.clearCallingIdentity();
try {
@@ -233,7 +237,7 @@ public class VibratorService extends IVibratorService.Stub
}
public void vibratePattern(int uid, String packageName, long[] pattern, int repeat,
- IBinder token) {
+ int streamHint, IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
@@ -258,7 +262,7 @@ public class VibratorService extends IVibratorService.Stub
return;
}
- Vibration vib = new Vibration(token, pattern, repeat, uid, packageName);
+ Vibration vib = new Vibration(token, pattern, repeat, streamHint, uid, packageName);
try {
token.linkToDeath(vib, 0);
} catch (RemoteException e) {
@@ -342,8 +346,12 @@ public class VibratorService extends IVibratorService.Stub
// Lock held on mVibrations
private void startVibrationLocked(final Vibration vib) {
try {
- int mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
+ int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
+ vib.mStreamHint, vib.mUid, vib.mPackageName);
+ if (mode == AppOpsManager.MODE_ALLOWED) {
+ mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
AppOpsManager.OP_VIBRATE, vib.mUid, vib.mPackageName);
+ }
if (mode != AppOpsManager.MODE_ALLOWED) {
if (mode == AppOpsManager.MODE_ERRORED) {
Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e2226aa..7c2de8b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -206,10 +206,6 @@ public class NotificationManagerService extends SystemService {
final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
private int mZenMode;
- private int mPreZenAlarmVolume = -1;
- private int mPreZenRingerMode = -1;
- private boolean mZenMutingAlarm;
- private boolean mZenMutingRinger;
// temporary, until we update apps to provide metadata
private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList(
"com.google.android.dialer",
@@ -1122,9 +1118,6 @@ public class NotificationManagerService extends SystemService {
private final Uri ZEN_MODE
= Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
- private final Uri MODE_RINGER
- = Settings.Global.getUriFor(Settings.Global.MODE_RINGER);
-
SettingsObserver(Handler handler) {
super(handler);
}
@@ -1137,8 +1130,6 @@ public class NotificationManagerService extends SystemService {
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(ZEN_MODE,
false, this);
- resolver.registerContentObserver(MODE_RINGER,
- false, this);
update(null);
}
@@ -1162,9 +1153,6 @@ public class NotificationManagerService extends SystemService {
if (ZEN_MODE.equals(uri)) {
updateZenMode();
}
- if (MODE_RINGER.equals(uri)) {
- updateRingerMode();
- }
}
}
@@ -1230,7 +1218,6 @@ public class NotificationManagerService extends SystemService {
Settings.Global.DEVICE_PROVISIONED, 0)) {
mDisableNotificationAlerts = true;
}
- updateRingerMode();
updateZenMode();
// register for various Intents
@@ -1694,10 +1681,6 @@ public class NotificationManagerService extends SystemService {
pw.println(" mVibrateNotification=" + mVibrateNotification);
pw.println(" mDisableNotificationAlerts=" + mDisableNotificationAlerts);
pw.println(" mZenMode=" + Settings.Global.zenModeToString(mZenMode));
- pw.println(" mPreZenAlarmVolume=" + mPreZenAlarmVolume);
- pw.println(" mPreZenRingerMode=" + mPreZenRingerMode);
- pw.println(" mZenMutingAlarm=" + mZenMutingAlarm);
- pw.println(" mZenMutingRinger=" + mZenMutingRinger);
pw.println(" mSystemReady=" + mSystemReady);
pw.println(" mArchive=" + mArchive.toString());
Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
@@ -2023,7 +2006,7 @@ public class NotificationManagerService extends SystemService {
useDefaultVibrate ? mDefaultVibrationPattern
: mFallbackVibrationPattern,
((notification.flags & Notification.FLAG_INSISTENT) != 0)
- ? 0: -1);
+ ? 0: -1, notification.audioStreamType);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -2033,7 +2016,7 @@ public class NotificationManagerService extends SystemService {
mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(),
notification.vibrate,
((notification.flags & Notification.FLAG_INSISTENT) != 0)
- ? 0: -1);
+ ? 0: -1, notification.audioStreamType);
}
}
}
@@ -2552,17 +2535,6 @@ public class NotificationManagerService extends SystemService {
}
}
- private void updateRingerMode() {
- final int ringerMode = Settings.Global.getInt(getContext().getContentResolver(),
- Settings.Global.MODE_RINGER, -1);
- final boolean nonSilentRingerMode = ringerMode == AudioManager.RINGER_MODE_NORMAL
- || ringerMode == AudioManager.RINGER_MODE_VIBRATE;
- if (mZenMode != Settings.Global.ZEN_MODE_OFF && nonSilentRingerMode) {
- Settings.Global.putInt(getContext().getContentResolver(),
- Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
- }
- }
-
private void updateZenMode() {
final int mode = Settings.Global.getInt(getContext().getContentResolver(),
Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
@@ -2572,62 +2544,31 @@ public class NotificationManagerService extends SystemService {
Settings.Global.zenModeToString(mode)));
}
mZenMode = mode;
- if (mAudioManager != null) {
- // call audio
- final boolean muteCalls = mZenMode != Settings.Global.ZEN_MODE_OFF;
- if (muteCalls) {
- if (!mZenMutingRinger) {
- if (DBG) Slog.d(TAG, "Muting STREAM_RING");
- mAudioManager.setStreamMute(AudioManager.STREAM_RING, true);
- mZenMutingRinger = true;
- }
- // calls vibrate if ringer mode = vibrate, so set the ringer mode as well
- final int ringerMode = mAudioManager.getRingerMode();
- if (ringerMode != AudioManager.RINGER_MODE_SILENT) {
- if (DBG) Slog.d(TAG, "Saving ringer mode of " + ringerMode);
- mPreZenRingerMode = ringerMode;
- mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
- }
- } else {
- if (mZenMutingRinger) {
- if (DBG) Slog.d(TAG, "Unmuting STREAM_RING");
- mAudioManager.setStreamMute(AudioManager.STREAM_RING, false);
- mZenMutingRinger = false;
- }
- if (mPreZenRingerMode != -1) {
- if (DBG) Slog.d(TAG, "Restoring ringer mode to " + mPreZenRingerMode);
- mAudioManager.setRingerMode(mPreZenRingerMode);
- mPreZenRingerMode = -1;
- }
- }
- // alarm audio
- final boolean muteAlarms = mZenMode == Settings.Global.ZEN_MODE_FULL;
- if (muteAlarms) {
- if (!mZenMutingAlarm) {
- if (DBG) Slog.d(TAG, "Muting STREAM_ALARM");
- mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, true);
- mZenMutingAlarm = true;
- }
- // alarms don't simply respect mute, so set the volume as well
- final int volume = mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM);
- if (volume != 0) {
- if (DBG) Slog.d(TAG, "Saving STREAM_ALARM volume of " + volume);
- mPreZenAlarmVolume = volume;
- mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, 0, 0);
- }
- } else {
- if (mZenMutingAlarm) {
- if (DBG) Slog.d(TAG, "Unmuting STREAM_ALARM");
- mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, false);
- mZenMutingAlarm = false;
- }
- if (mPreZenAlarmVolume != -1) {
- if (DBG) Slog.d(TAG, "Restoring STREAM_ALARM volume to " + mPreZenAlarmVolume);
- mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, mPreZenAlarmVolume, 0);
- mPreZenAlarmVolume = -1;
- }
- }
- }
+
+ final String[] exceptionPackages = null; // none (for now)
+
+ // call restrictions
+ final boolean muteCalls = mZenMode != Settings.Global.ZEN_MODE_OFF;
+ mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.STREAM_RING,
+ muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
+ exceptionPackages);
+ mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, AudioManager.STREAM_RING,
+ muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
+ exceptionPackages);
+
+ // alarm restrictions
+ final boolean muteAlarms = mZenMode == Settings.Global.ZEN_MODE_FULL;
+ mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.STREAM_ALARM,
+ muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
+ exceptionPackages);
+ mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, AudioManager.STREAM_ALARM,
+ muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
+ exceptionPackages);
+
+ // restrict vibrations with no hints
+ mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.USE_DEFAULT_STREAM_TYPE,
+ (muteAlarms || muteCalls) ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
+ exceptionPackages);
}
private void updateRelatedUserCache(Context context) {