Summary of feature: Do not mute notifications when speech recognition recording is active, but when an app has requested audio focus with AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE. Implementation: Move definition of AUDIOFOCUS_NONE to AudioManager where other audio focus codes are defined. Add support for querying the current audio focus type. When audio focus is requested as GAIN_TRANSIENT_EXCLUSIVE, make the corresponding loss by LOSS_TRANSIENT. Before playing a notification, check whether GAIN_TRANSIENT_EXCLUSIVE has been requested. Bug 8251963 Change-Id: I41edc77326b70639d2fdcb4642c53109995b72a8
245 lines
8.5 KiB
Java
245 lines
8.5 KiB
Java
/*
|
|
* Copyright (C) 2013 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.media;
|
|
|
|
import android.media.MediaFocusControl.AudioFocusDeathHandler;
|
|
import android.os.IBinder;
|
|
import android.util.Log;
|
|
|
|
import java.io.PrintWriter;
|
|
|
|
/**
|
|
* @hide
|
|
* Class to handle all the information about a user of audio focus. The lifecycle of each
|
|
* instance is managed by android.media.MediaFocusControl, from its addition to the audio focus
|
|
* stack to its release.
|
|
*/
|
|
class FocusRequester {
|
|
|
|
// on purpose not using this classe's name, as it will only be used from MediaFocusControl
|
|
private static final String TAG = "MediaFocusControl";
|
|
private static final boolean DEBUG = false;
|
|
|
|
private AudioFocusDeathHandler mDeathHandler;
|
|
private final IAudioFocusDispatcher mFocusDispatcher; // may be null
|
|
private final IBinder mSourceRef;
|
|
private final String mClientId;
|
|
private final String mPackageName;
|
|
private final int mCallingUid;
|
|
/**
|
|
* the audio focus gain request that caused the addition of this object in the focus stack.
|
|
*/
|
|
private final int mFocusGainRequest;
|
|
/**
|
|
* the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if
|
|
* it never lost focus.
|
|
*/
|
|
private int mFocusLossReceived;
|
|
/**
|
|
* the stream type associated with the focus request
|
|
*/
|
|
private final int mStreamType;
|
|
|
|
FocusRequester(int streamType, int focusRequest,
|
|
IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
|
|
String pn, int uid) {
|
|
mStreamType = streamType;
|
|
mFocusDispatcher = afl;
|
|
mSourceRef = source;
|
|
mClientId = id;
|
|
mDeathHandler = hdlr;
|
|
mPackageName = pn;
|
|
mCallingUid = uid;
|
|
mFocusGainRequest = focusRequest;
|
|
mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
|
|
}
|
|
|
|
|
|
boolean hasSameClient(String otherClient) {
|
|
try {
|
|
return mClientId.compareTo(otherClient) == 0;
|
|
} catch (NullPointerException e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
boolean hasSameBinder(IBinder ib) {
|
|
return (mSourceRef != null) && mSourceRef.equals(ib);
|
|
}
|
|
|
|
boolean hasSamePackage(String pack) {
|
|
try {
|
|
return mPackageName.compareTo(pack) == 0;
|
|
} catch (NullPointerException e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
boolean hasSameUid(int uid) {
|
|
return mCallingUid == uid;
|
|
}
|
|
|
|
|
|
int getGainRequest() {
|
|
return mFocusGainRequest;
|
|
}
|
|
|
|
int getStreamType() {
|
|
return mStreamType;
|
|
}
|
|
|
|
|
|
private static String focusChangeToString(int focus) {
|
|
switch(focus) {
|
|
case AudioManager.AUDIOFOCUS_NONE:
|
|
return "none";
|
|
case AudioManager.AUDIOFOCUS_GAIN:
|
|
return "GAIN";
|
|
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
|
|
return "GAIN_TRANSIENT";
|
|
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
|
|
return "GAIN_TRANSIENT_MAY_DUCK";
|
|
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
|
|
return "GAIN_TRANSIENT_EXCLUSIVE";
|
|
case AudioManager.AUDIOFOCUS_LOSS:
|
|
return "LOSS";
|
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
|
return "LOSS_TRANSIENT";
|
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
|
return "LOSS_TRANSIENT_CAN_DUCK";
|
|
default:
|
|
return "[invalid focus change" + focus + "]";
|
|
}
|
|
}
|
|
|
|
private String focusGainToString() {
|
|
return focusChangeToString(mFocusGainRequest);
|
|
}
|
|
|
|
private String focusLossToString() {
|
|
return focusChangeToString(mFocusLossReceived);
|
|
}
|
|
|
|
void dump(PrintWriter pw) {
|
|
pw.println(" source:" + mSourceRef
|
|
+ " -- pack: " + mPackageName
|
|
+ " -- client: " + mClientId
|
|
+ " -- gain: " + focusGainToString()
|
|
+ " -- loss: " + focusLossToString()
|
|
+ " -- uid: " + mCallingUid
|
|
+ " -- stream: " + mStreamType);
|
|
}
|
|
|
|
|
|
void release() {
|
|
try {
|
|
if (mSourceRef != null && mDeathHandler != null) {
|
|
mSourceRef.unlinkToDeath(mDeathHandler, 0);
|
|
mDeathHandler = null;
|
|
}
|
|
} catch (java.util.NoSuchElementException e) {
|
|
Log.e(TAG, "FocusRequester.release() hit ", e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void finalize() throws Throwable {
|
|
release();
|
|
super.finalize();
|
|
}
|
|
|
|
/**
|
|
* For a given audio focus gain request, return the audio focus loss type that will result
|
|
* from it, taking into account any previous focus loss.
|
|
* @param gainRequest
|
|
* @return the audio focus loss type that matches the gain request
|
|
*/
|
|
private int focusLossForGainRequest(int gainRequest) {
|
|
switch(gainRequest) {
|
|
case AudioManager.AUDIOFOCUS_GAIN:
|
|
switch(mFocusLossReceived) {
|
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
|
case AudioManager.AUDIOFOCUS_LOSS:
|
|
case AudioManager.AUDIOFOCUS_NONE:
|
|
return AudioManager.AUDIOFOCUS_LOSS;
|
|
}
|
|
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
|
|
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
|
|
switch(mFocusLossReceived) {
|
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
|
case AudioManager.AUDIOFOCUS_NONE:
|
|
return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
|
|
case AudioManager.AUDIOFOCUS_LOSS:
|
|
return AudioManager.AUDIOFOCUS_LOSS;
|
|
}
|
|
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
|
|
switch(mFocusLossReceived) {
|
|
case AudioManager.AUDIOFOCUS_NONE:
|
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
|
return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
|
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
|
return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
|
|
case AudioManager.AUDIOFOCUS_LOSS:
|
|
return AudioManager.AUDIOFOCUS_LOSS;
|
|
}
|
|
default:
|
|
Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest);
|
|
return AudioManager.AUDIOFOCUS_NONE;
|
|
}
|
|
}
|
|
|
|
void handleExternalFocusGain(int focusGain) {
|
|
int focusLoss = focusLossForGainRequest(focusGain);
|
|
handleFocusLoss(focusLoss);
|
|
}
|
|
|
|
void handleFocusGain(int focusGain) {
|
|
try {
|
|
if (mFocusDispatcher != null) {
|
|
if (DEBUG) {
|
|
Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
|
|
+ mClientId);
|
|
}
|
|
mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
|
|
}
|
|
mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
|
|
} catch (android.os.RemoteException e) {
|
|
Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
|
|
}
|
|
}
|
|
|
|
void handleFocusLoss(int focusLoss) {
|
|
try {
|
|
if (focusLoss != mFocusLossReceived) {
|
|
if (mFocusDispatcher != null) {
|
|
if (DEBUG) {
|
|
Log.v(TAG, "dispatching " + focusChangeToString(focusLoss) + " to "
|
|
+ mClientId);
|
|
}
|
|
mFocusDispatcher.dispatchAudioFocusChange(focusLoss, mClientId);
|
|
}
|
|
mFocusLossReceived = focusLoss;
|
|
}
|
|
} catch (android.os.RemoteException e) {
|
|
Log.e(TAG, "Failure to signal loss of audio focus due to:", e);
|
|
}
|
|
}
|
|
|
|
}
|