package android.media;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
/**
+ * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
+ * @hide
+ */
+ public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
+
+ private static final String[] FLAG_NAMES = {
+ "FLAG_SHOW_UI",
+ "FLAG_ALLOW_RINGER_MODES",
+ "FLAG_PLAY_SOUND",
+ "FLAG_REMOVE_SOUND_AND_VIBRATE",
+ "FLAG_VIBRATE",
+ "FLAG_FIXED_VOLUME",
+ "FLAG_BLUETOOTH_ABS_VOLUME",
+ "FLAG_SHOW_SILENT_HINT",
+ "FLAG_HDMI_SYSTEM_AUDIO_VOLUME",
+ "FLAG_ACTIVE_MEDIA_ONLY",
+ "FLAG_SHOW_UI_WARNINGS",
+ "FLAG_SHOW_VIBRATE_HINT",
+ };
+
+ /** @hide */
+ public static String flagsToString(int flags) {
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < FLAG_NAMES.length; i++) {
+ final int flag = 1 << i;
+ if ((flags & flag) != 0) {
+ if (sb.length() > 0) {
+ sb.append(',');
+ }
+ sb.append(FLAG_NAMES[i]);
+ flags &= ~flag;
+ }
+ }
+ if (flags != 0) {
+ if (sb.length() > 0) {
+ sb.append(',');
+ }
+ sb.append(flags);
+ }
+ return sb.toString();
+ }
+
+ /**
* Ringer mode that will be silent and will not vibrate. (This overrides the
* vibrate setting.)
*
public int getRingerMode() {
IAudioService service = getService();
try {
- return service.getRingerMode();
+ return service.getRingerModeExternal();
} catch (RemoteException e) {
Log.e(TAG, "Dead object in getRingerMode", e);
return RINGER_MODE_NORMAL;
* @see #isVolumeFixed()
*/
public void setRingerMode(int ringerMode) {
- setRingerMode(ringerMode, true /*checkZen*/);
- }
-
- /**
- * @see #setRingerMode(int)
- * @param checkZen Update zen mode if necessary to compensate.
- * @hide
- */
- public void setRingerMode(int ringerMode, boolean checkZen) {
if (!isValidRingerMode(ringerMode)) {
return;
}
IAudioService service = getService();
try {
- service.setRingerMode(ringerMode, checkZen);
+ service.setRingerModeExternal(ringerMode, mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setRingerMode", e);
}
return status;
}
- // when adding new flags, add them to AUDIOFOCUS_FLAGS_ALL
+ // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
/** @hide */
+ @SystemApi
public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
/** @hide */
- public static final int AUDIOFOCUS_FLAGS_ALL = AUDIOFOCUS_FLAG_DELAY_OK;
+ @SystemApi
+ public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 1;
+ /** @hide */
+ public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK;
+ /** @hide */
+ public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
+ | AUDIOFOCUS_FLAG_LOCK;
/**
* @hide
+ * Request audio focus.
+ * Send a request to obtain the audio focus. This method differs from
+ * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
+ * that the requester accepts delayed grants of audio focus.
* @param l the listener to be notified of audio focus changes. It is not allowed to be null
* when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
* @param requestAttributes non null {@link AudioAttributes} describing the main reason for
* usecases such as voice memo recording, or speech recognition.
* Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
* as the playback of a song or a video.
- * @param flags use 0 when not using any flags for the request, which behaves like
- * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
- * focus is granted immediately, or the grant request fails because the system is in a
- * state where focus cannot change (e.g. a phone call).
- * Use {link #AUDIOFOCUS_FLAG_DELAY_OK} if it is ok for the requester to not be granted
- * audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
- * the system is in a state where focus cannot change, but be granted focus later when
- * this condition ends.
+ * @param flags 0 or {link #AUDIOFOCUS_FLAG_DELAY_OK}.
+ * <br>Use 0 when not using any flags for the request, which behaves like
+ * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
+ * focus is granted immediately, or the grant request fails because the system is in a
+ * state where focus cannot change (e.g. a phone call).
+ * <br>Use {link #AUDIOFOCUS_FLAG_DELAY_OK} if it is ok for the requester to not be granted
+ * audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
+ * the system is in a state where focus cannot change, but be granted focus later when
+ * this condition ends.
* @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
* or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
* The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
* without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
* @throws IllegalArgumentException
*/
+ @SystemApi
public int requestAudioFocus(OnAudioFocusChangeListener l,
- AudioAttributes requestAttributes,
+ @NonNull AudioAttributes requestAttributes,
int durationHint,
int flags) throws IllegalArgumentException {
+ if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
+ throw new IllegalArgumentException("Invalid flags 0x"
+ + Integer.toHexString(flags).toUpperCase());
+ }
+ return requestAudioFocus(l, requestAttributes, durationHint,
+ flags & AUDIOFOCUS_FLAGS_APPS,
+ null /* no AudioPolicy*/);
+ }
+
+ /**
+ * @hide
+ * Request or lock audio focus.
+ * This method is to be used by system components that have registered an
+ * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
+ * so focus granting is temporarily disabled.
+ * @param l see the description of the same parameter in
+ * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
+ * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
+ * requesting audio focus.
+ * @param durationHint see the description of the same parameter in
+ * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
+ * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
+ * {@link #AUDIOFOCUS_FLAG_LOCK}
+ * <br>Use 0 when not using any flags for the request, which behaves like
+ * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
+ * focus is granted immediately, or the grant request fails because the system is in a
+ * state where focus cannot change (e.g. a phone call).
+ * <br>Use {link #AUDIOFOCUS_FLAG_DELAY_OK} if it is ok for the requester to not be granted
+ * audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
+ * the system is in a state where focus cannot change, but be granted focus later when
+ * this condition ends.
+ * <br>Use {@link #AUDIOFOCUS_FLAG_LOCK} when locking audio focus so granting is
+ * temporarily disabled.
+ * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
+ * focus, or null.
+ * @return see the description of the same return value in
+ * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
+ * @throws IllegalArgumentException
+ */
+ public int requestAudioFocus(OnAudioFocusChangeListener l,
+ @NonNull AudioAttributes requestAttributes,
+ int durationHint,
+ int flags,
+ AudioPolicy ap) throws IllegalArgumentException {
// parameter checking
if (requestAttributes == null) {
throw new IllegalArgumentException("Illegal null AudioAttributes argument");
(durationHint > AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
throw new IllegalArgumentException("Invalid duration hint");
}
- if (flags != (flags & AUDIOFOCUS_FLAGS_ALL)) {
+ if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
throw new IllegalArgumentException("Illegal flags 0x"
+ Integer.toHexString(flags).toUpperCase());
}
throw new IllegalArgumentException(
"Illegal null focus listener when flagged as accepting delayed focus grant");
}
+ if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
+ throw new IllegalArgumentException(
+ "Illegal null audio policy when locking audio focus");
+ }
int status = AUDIOFOCUS_REQUEST_FAILED;
registerAudioFocusListener(l);
try {
status = service.requestAudioFocus(requestAttributes, durationHint, mICallBack,
mAudioFocusDispatcher, getIdForAudioFocusListener(l),
- mContext.getOpPackageName() /* package name */, flags);
+ mContext.getOpPackageName() /* package name */, flags,
+ ap != null ? ap.token() : null);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);
+ Log.e(TAG, "Can't call requestAudioFocus() on AudioService:", e);
}
return status;
}
.setInternalLegacyStreamType(streamType).build(),
durationHint, mICallBack, null,
MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
- mContext.getOpPackageName(), 0 /* flags, legacy behavior*/ );
+ mContext.getOpPackageName(),
+ AUDIOFOCUS_FLAG_LOCK,
+ null /* policy token */);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
+ Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService:", e);
}
}
public void abandonAudioFocusForCall() {
IAudioService service = getService();
try {
- service.abandonAudioFocus(null, MediaFocusControl.IN_VOICE_COMM_FOCUS_ID);
+ service.abandonAudioFocus(null, MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
+ null /*AudioAttributes, legacy behavior*/);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e);
+ Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService:", e);
}
}
* @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
*/
public int abandonAudioFocus(OnAudioFocusChangeListener l) {
+ return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
+ }
+
+ /**
+ * @hide
+ * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
+ * @param l the listener with which focus was requested.
+ * @param aa the {@link AudioAttributes} with which audio focus was requested
+ * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
+ */
+ @SystemApi
+ public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
int status = AUDIOFOCUS_REQUEST_FAILED;
unregisterAudioFocusListener(l);
IAudioService service = getService();
try {
status = service.abandonAudioFocus(mAudioFocusDispatcher,
- getIdForAudioFocusListener(l));
+ getIdForAudioFocusListener(l), aa);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call abandonAudioFocus() on AudioService due to "+e);
+ Log.e(TAG, "Can't call abandonAudioFocus() on AudioService:", e);
}
return status;
}
-
//====================================================================
// Remote Control
/**
}
/**
+ * Only useful for volume controllers.
+ * @hide
+ */
+ public void setRingerModeInternal(int ringerMode) {
+ try {
+ getService().setRingerModeInternal(ringerMode, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error calling setRingerModeInternal", e);
+ }
+ }
+
+ /**
+ * Only useful for volume controllers.
+ * @hide
+ */
+ public int getRingerModeInternal() {
+ try {
+ return getService().getRingerModeInternal();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error calling getRingerModeInternal", e);
+ return RINGER_MODE_NORMAL;
+ }
+ }
+
+ /**
* Set Hdmi Cec system audio mode.
*
* @param on whether to be on system audio mode