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
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);
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);
}
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));
{"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},
<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" />
"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
"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
}
}
+ /** @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.
*
}
/**
+ * 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.
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();
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);
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, ...)
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);
}
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
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);
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;
}
}
}