OSDN Git Service

Add setMasterMono and getMasterMono
authorAndy Hung <hunga@google.com>
Sat, 19 Dec 2015 01:33:27 +0000 (17:33 -0800)
committerAndy Hung <hunga@google.com>
Fri, 8 Jan 2016 22:02:47 +0000 (14:02 -0800)
Bug: 15283594
Bug: 22700363
Change-Id: I5d0552938ec2a54be4450512974d92ff8c77b1e9

core/java/android/provider/Settings.java
core/jni/android_media_AudioSystem.cpp
core/res/AndroidManifest.xml
media/java/android/media/AudioManager.java
media/java/android/media/AudioSystem.java
media/java/android/media/IAudioService.aidl
services/core/java/com/android/server/audio/AudioService.java

index b883f9c..9bbcc35 100644 (file)
@@ -2592,6 +2592,15 @@ public final class Settings {
         private static final Validator MICROPHONE_MUTE_VALIDATOR = sBooleanValidator;
 
         /**
+         * Master mono (int 1 = mono, 0 = normal).
+         *
+         * @hide
+         */
+        public static final String MASTER_MONO = "master_mono";
+
+        private static final Validator MASTER_MONO_VALIDATOR = sBooleanValidator;
+
+        /**
          * Whether the notifications should use the ring volume (value of 1) or
          * a separate notification volume (value of 0). In most cases, users
          * will have this enabled so the notification and ringer volumes will be
@@ -3357,6 +3366,7 @@ public final class Settings {
             PRIVATE_SETTINGS.add(VOLUME_MASTER);
             PRIVATE_SETTINGS.add(VOLUME_MASTER_MUTE);
             PRIVATE_SETTINGS.add(MICROPHONE_MUTE);
+            PRIVATE_SETTINGS.add(MASTER_MONO);
             PRIVATE_SETTINGS.add(NOTIFICATIONS_USE_RING_VOLUME);
             PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT);
             PRIVATE_SETTINGS.add(MEDIA_BUTTON_RECEIVER);
@@ -3435,6 +3445,7 @@ public final class Settings {
             VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR);
             VALIDATORS.put(VOLUME_MASTER_MUTE, VOLUME_MASTER_MUTE_VALIDATOR);
             VALIDATORS.put(MICROPHONE_MUTE, MICROPHONE_MUTE_VALIDATOR);
+            VALIDATORS.put(MASTER_MONO, MASTER_MONO_VALIDATOR);
             VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR);
             VALIDATORS.put(VIBRATE_IN_SILENT, VIBRATE_IN_SILENT_VALIDATOR);
             VALIDATORS.put(MEDIA_BUTTON_RECEIVER, MEDIA_BUTTON_RECEIVER_VALIDATOR);
index 6d3c7d7..e162810 100644 (file)
@@ -498,6 +498,22 @@ android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
 }
 
 static jint
+android_media_AudioSystem_setMasterMono(JNIEnv *env, jobject thiz, jboolean mono)
+{
+    return (jint) check_AudioSystem_Command(AudioSystem::setMasterMono(mono));
+}
+
+static jboolean
+android_media_AudioSystem_getMasterMono(JNIEnv *env, jobject thiz)
+{
+    bool mono;
+    if (AudioSystem::getMasterMono(&mono) != NO_ERROR) {
+        mono = false;
+    }
+    return mono;
+}
+
+static jint
 android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
 {
     return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
@@ -1637,6 +1653,8 @@ static const JNINativeMethod gMethods[] = {
     {"getMasterVolume",     "()F",      (void *)android_media_AudioSystem_getMasterVolume},
     {"setMasterMute",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMute},
     {"getMasterMute",       "()Z",      (void *)android_media_AudioSystem_getMasterMute},
+    {"setMasterMono",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMono},
+    {"getMasterMono",       "()Z",      (void *)android_media_AudioSystem_getMasterMono},
     {"getDevicesForStream", "(I)I",     (void *)android_media_AudioSystem_getDevicesForStream},
     {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
     {"getPrimaryOutputFrameCount",   "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
index 37af59f..695672e 100644 (file)
     <protected-broadcast android:name="android.media.VOLUME_CHANGED_ACTION" />
     <protected-broadcast android:name="android.media.MASTER_VOLUME_CHANGED_ACTION" />
     <protected-broadcast android:name="android.media.MASTER_MUTE_CHANGED_ACTION" />
+    <protected-broadcast android:name="android.media.MASTER_MONO_CHANGED_ACTION" />
     <protected-broadcast android:name="android.media.SCO_AUDIO_STATE_CHANGED" />
     <protected-broadcast android:name="android.media.ACTION_SCO_AUDIO_STATE_UPDATED" />
 
index c658675..a092408 100644 (file)
@@ -176,6 +176,16 @@ public class AudioManager {
         "android.media.MASTER_MUTE_CHANGED_ACTION";
 
     /**
+     * @hide Broadcast intent when the master mono state changes.
+     * Includes the new mono state
+     *
+     * @see #EXTRA_MASTER_MONO
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String MASTER_MONO_CHANGED_ACTION =
+        "android.media.MASTER_MONO_CHANGED_ACTION";
+
+    /**
      * The new vibrate setting for a particular type.
      *
      * @see #VIBRATE_SETTING_CHANGED_ACTION
@@ -254,6 +264,13 @@ public class AudioManager {
         "android.media.EXTRA_STREAM_VOLUME_MUTED";
 
     /**
+     * @hide The new master mono state for the master mono changed intent.
+     * Value is boolean
+     */
+    public static final String EXTRA_MASTER_MONO =
+        "android.media.EXTRA_MASTER_MONO";
+
+    /**
      * Broadcast Action: Wired Headset plugged in or unplugged.
      *
      * You <em>cannot</em> receive this through components declared
@@ -880,6 +897,17 @@ public class AudioManager {
         }
     }
 
+    /** @hide */
+    public void setMasterMono(boolean mono) {
+        IAudioService service = getService();
+        try {
+            service.setMasterMono(mono, getContext().getOpPackageName(),
+                    UserHandle.getCallingUserId());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in setMasterMono", e);
+        }
+    }
+
     /**
      * Returns the current ringtone mode.
      *
@@ -1142,6 +1170,21 @@ public class AudioManager {
     }
 
     /**
+     * get master mono state.
+     *
+     * @hide
+     */
+    public boolean isMasterMono() {
+        IAudioService service = getService();
+        try {
+            return service.isMasterMono();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in isMasterMono", e);
+            return false;
+        }
+    }
+
+    /**
      * forces the stream controlled by hard volume keys
      * specifying streamType == -1 releases control to the
      * logic.
index c59d1c7..7bfd7ca 100644 (file)
@@ -624,6 +624,11 @@ public class AudioSystem
     public static native boolean getMasterMute();
     public static native int getDevicesForStream(int stream);
 
+    /** @hide returns true if master mono is enabled. */
+    public static native boolean getMasterMono();
+    /** @hide enables or disables the master mono mode. */
+    public static native int setMasterMono(boolean mono);
+
     // helpers for android.media.AudioManager.getProperty(), see description there for meaning
     public static native int getPrimaryOutputSamplingRate();
     public static native int getPrimaryOutputFrameCount();
index 693a519..dbb7661 100644 (file)
@@ -52,6 +52,10 @@ interface IAudioService {
 
     void setMasterMute(boolean mute, int flags, String callingPackage, int userId);
 
+    boolean isMasterMono();
+
+    void setMasterMono(boolean mute, String callingPackage, int userId);
+
     int getStreamVolume(int streamType);
 
     int getStreamMinVolume(int streamType);
index 40d01e7..b8cbecb 100644 (file)
@@ -220,6 +220,7 @@ public class AudioService extends IAudioService.Stub {
     private static final int MSG_UNMUTE_STREAM = 24;
     private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
     private static final int MSG_INDICATE_SYSTEM_READY = 26;
+    private static final int MSG_PERSIST_MASTER_MONO = 27;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -820,6 +821,12 @@ public class AudioService extends IAudioService.Stub {
             streamState.applyAllVolumes();
         }
 
+        // Restore mono mode
+        final boolean masterMono = System.getIntForUser(
+                mContentResolver, System.MASTER_MONO,
+                0 /* default */, UserHandle.USER_CURRENT) == 1;
+        AudioSystem.setMasterMono(masterMono);
+
         // Restore ringer mode
         setRingerModeInt(getRingerModeInternal(), false);
 
@@ -1079,6 +1086,14 @@ public class AudioService extends IAudioService.Stub {
         }
         AudioSystem.muteMicrophone(microphoneMute);
 
+        final boolean masterMono = System.getIntForUser(
+                cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
+        if (DEBUG_VOL) {
+            Log.d(TAG, String.format("Master mono %b, user=%d", masterMono, currentUser));
+        }
+        AudioSystem.setMasterMono(masterMono);
+        broadcastMasterMonoStatus(masterMono);
+
         // Each stream will read its own persisted settings
 
         // Broadcast the sticky intents
@@ -1835,6 +1850,52 @@ public class AudioService extends IAudioService.Stub {
                 userId);
     }
 
+    /** @hide */
+    public boolean isMasterMono() {
+        return AudioSystem.getMasterMono();
+    }
+
+    /** @hide */
+    public void setMasterMono(boolean mono, String callingPackage, int userId) {
+        int callingUid = Binder.getCallingUid();
+        // If we are being called by the system check for user we are going to change
+        // so we handle user restrictions correctly.
+        if (callingUid == android.os.Process.SYSTEM_UID) {
+            callingUid = UserHandle.getUid(userId, UserHandle.getAppId(callingUid));
+        }
+
+        if (userId != UserHandle.getCallingUserId() &&
+                mContext.checkCallingOrSelfPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                != PackageManager.PERMISSION_GRANTED) {
+            return;
+        }
+        if (DEBUG_VOL) {
+            Log.d(TAG, String.format("Master mono %b, user=%d", mono, userId));
+        }
+
+        if (getCurrentUserId() == userId) {
+            if (mono != AudioSystem.getMasterMono()) {
+                AudioSystem.setMasterMono(mono);
+                // Post a persist master mono msg
+                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1
+                        : 0 /* value */, userId, null /* obj */, 0 /* delay */);
+                // notify apps and settings
+                broadcastMasterMonoStatus(mono);
+            }
+        } else {
+            // Post a persist master mono msg
+            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1
+                    : 0 /* value */, userId, null /* obj */, 0 /* delay */);
+        }
+    }
+
+    private void broadcastMasterMonoStatus(boolean mono) {
+        Intent intent = new Intent(AudioManager.MASTER_MONO_CHANGED_ACTION);
+        intent.putExtra(AudioManager.EXTRA_MASTER_MONO, mono);
+        sendBroadcastToAll(intent);
+    }
+
     /** @see AudioManager#getStreamVolume(int) */
     public int getStreamVolume(int streamType) {
         ensureValidStreamType(streamType);
@@ -4534,6 +4595,13 @@ public class AudioService extends IAudioService.Stub {
                 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
                     onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
                     break;
+
+                case MSG_PERSIST_MASTER_MONO:
+                    Settings.System.putIntForUser(mContentResolver,
+                                                 Settings.System.MASTER_MONO,
+                                                 msg.arg1 /* value */,
+                                                 msg.arg2 /* userHandle */);
+                    break;
             }
         }
     }