summaryrefslogtreecommitdiffstats
path: root/media/java
diff options
context:
space:
mode:
authorJean-Michel Trivi <jmtrivi@google.com>2013-07-29 18:09:41 -0700
committerJean-Michel Trivi <jmtrivi@google.com>2013-07-30 11:27:08 -0700
commit83283f23eb1b7c1576e253c644b8aade6f657d0a (patch)
tree3c0219a9e5f116b73088715333d49fee1c36622f /media/java
parent00bf4b18173b8921d7a5cecbd8b8d3745470b5d0 (diff)
downloadframeworks_base-83283f23eb1b7c1576e253c644b8aade6f657d0a.zip
frameworks_base-83283f23eb1b7c1576e253c644b8aade6f657d0a.tar.gz
frameworks_base-83283f23eb1b7c1576e253c644b8aade6f657d0a.tar.bz2
Audio focus request managed by FocusRequester class
Move all audio focus request functionality under a new class/file. Clean up encapsulation of data related to the request. Change-Id: I989796e1ee1a5fc99799a64e1612294e0e40fa6d
Diffstat (limited to 'media/java')
-rw-r--r--media/java/android/media/FocusRequester.java210
-rw-r--r--media/java/android/media/MediaFocusControl.java200
2 files changed, 245 insertions, 165 deletions
diff --git a/media/java/android/media/FocusRequester.java b/media/java/android/media/FocusRequester.java
new file mode 100644
index 0000000..e1a175d
--- /dev/null
+++ b/media/java/android/media/FocusRequester.java
@@ -0,0 +1,210 @@
+/*
+ * 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 {
+
+ /**
+ * Used to indicate no audio focus has been gained or lost.
+ */
+ private static final int AUDIOFOCUS_NONE = 0;
+
+ // on purpose not using this classe's name, as it will only be used from MediaFocusControl
+ private static final String TAG = "MediaFocusControl";
+
+ private AudioFocusDeathHandler mDeathHandler;
+ private final IAudioFocusDispatcher mFocusDispatcher;
+ 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 MediaFocusControl.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 = AUDIOFOCUS_NONE;
+ }
+
+
+ boolean canDispatchFocus() {
+ return (mFocusDispatcher != null);
+ }
+
+ 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 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_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.
+ * @param gainRequest
+ * @return the audio focus loss type that matches the gain request
+ */
+ private int focusLossForGainRequest(int gainRequest) {
+ // FIXME to be updated to take into account mFocusLossReceived
+ return -gainRequest; // focus loss codes are the inverse of the gain codes
+ }
+
+ void handleExternalFocusGain(int focusGain) {
+ try {
+ int focusLoss = focusLossForGainRequest(focusGain);
+ mFocusDispatcher.dispatchAudioFocusChange(focusLoss, mClientId);
+ mFocusLossReceived = focusLoss;
+ } catch (android.os.RemoteException e) {
+ Log.e(TAG, "Failure to signal loss of focus: ", e);
+ }
+ }
+
+ void handleFocusGain(int focusGain) {
+ try {
+ mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
+ mFocusLossReceived = 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 {
+ mFocusDispatcher.dispatchAudioFocusChange(
+ focusLoss, mClientId);
+ } catch (android.os.RemoteException e) {
+ Log.e(TAG, "Failure to signal loss of audio focus due to:", e);
+ }
+ }
+
+}
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 2b9d809..ca57b92 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -66,11 +66,6 @@ public class MediaFocusControl implements OnFinished {
/** Debug volumes */
protected static final boolean DEBUG_VOL = false;
- /**
- * Used to indicate no audio focus has been gained or lost.
- */
- private static final int AUDIOFOCUS_NONE = 0;
-
/** Used to alter media button redirection when the phone is ringing. */
private boolean mIsRinging = false;
@@ -270,11 +265,11 @@ public class MediaFocusControl implements OnFinished {
*/
protected void discardAudioFocusOwner() {
synchronized(mAudioFocusLock) {
- if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
+ if (!mFocusStack.empty() && mFocusStack.peek().canDispatchFocus()) {
// notify the current focus owner it lost focus after removing it from stack
- final FocusStackEntry exFocusOwner = mFocusStack.pop();
+ final FocusRequester exFocusOwner = mFocusStack.pop();
exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS);
- exFocusOwner.unlinkToDeath();
+ exFocusOwner.release();
// clear RCD
synchronized(mRCStack) {
clearRemoteControlDisplay_syncAfRcs();
@@ -285,128 +280,14 @@ public class MediaFocusControl implements OnFinished {
private void notifyTopOfAudioFocusStack() {
// notify the top of the stack it gained focus
- if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
+ if (!mFocusStack.empty() && mFocusStack.peek().canDispatchFocus()) {
if (canReassignAudioFocus()) {
mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
}
}
}
-
- private static class FocusStackEntry {
- int mStreamType = -1;// no stream type
- IAudioFocusDispatcher mFocusDispatcher = null;
- IBinder mSourceRef = null;
- String mClientId;
- /** the audio focus gain request that caused the addition of this entry in the stack */
- int mFocusGainRequest;
- int mFocusLossReceived;
- AudioFocusDeathHandler mHandler;
- String mPackageName;
- int mCallingUid;
-
- static String focusChangeToString(int focus) {
- switch(focus) {
- 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_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 + "]";
- }
- }
-
- String focusGainToString() {
- return focusChangeToString(mFocusGainRequest);
- }
-
- String focusLossToString() {
- if (mFocusLossReceived == 0) {
- return "none";
- } else {
- return focusChangeToString(mFocusLossReceived);
- }
- }
-
- FocusStackEntry(int streamType, int focusRequest,
- IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
- String pn, int uid) {
- mStreamType = streamType;
- mFocusDispatcher = afl;
- mSourceRef = source;
- mClientId = id;
- mFocusGainRequest = focusRequest;
- mFocusLossReceived = AUDIOFOCUS_NONE;
- mHandler = hdlr;
- mPackageName = pn;
- mCallingUid = uid;
- }
-
- void unlinkToDeath() {
- try {
- if (mSourceRef != null && mHandler != null) {
- mSourceRef.unlinkToDeath(mHandler, 0);
- mHandler = null;
- }
- } catch (java.util.NoSuchElementException e) {
- Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()");
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- unlinkToDeath(); // unlink exception handled inside method
- super.finalize();
- }
-
- /**
- * For a given audio focus gain request, return the audio focus loss type that will result
- * from it.
- * @param gainRequest
- * @return the audio focus loss type that matches the gain request
- */
- int focusLossForGainRequest(int gainRequest) {
- return -1 * gainRequest; // focus loss codes are the inverse of the gain codes
- }
-
- void handleExternalFocusGain(int focusGain) {
- try {
- int focusLoss = focusLossForGainRequest(focusGain);
- mFocusDispatcher.dispatchAudioFocusChange(focusLoss, mClientId);
- mFocusLossReceived = focusLoss;
- } catch (RemoteException e) {
- Log.e(TAG, " Failure to signal loss of focus: ", e);
- }
- }
-
- void handleFocusGain(int focusGain) {
- try {
- mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
- mFocusLossReceived = AUDIOFOCUS_NONE;
- } catch (RemoteException e) {
- Log.e(TAG, " Failure to signal gain of audio focus due to: ", e);
- }
- }
-
- void handleFocusLoss(int focusLoss) {
- try {
- mFocusDispatcher.dispatchAudioFocusChange(
- focusLoss, mClientId);
- } catch (RemoteException e) {
- Log.e(TAG, "Failure to signal loss of audio focus due to:", e);
- }
- }
- }
-
- private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
+ private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>();
/**
* Helper function:
@@ -415,16 +296,9 @@ public class MediaFocusControl implements OnFinished {
private void dumpFocusStack(PrintWriter pw) {
pw.println("\nAudio Focus stack entries (last is top of stack):");
synchronized(mAudioFocusLock) {
- Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
+ Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) {
- FocusStackEntry fse = stackIterator.next();
- pw.println(" source:" + fse.mSourceRef
- + " -- pack: " + fse.mPackageName
- + " -- client: " + fse.mClientId
- + " -- gain: " + fse.focusGainToString()
- + " -- loss: " + fse.focusLossToString()
- + " -- uid: " + fse.mCallingUid
- + " -- stream: " + fse.mStreamType);
+ stackIterator.next().dump(pw);
}
}
}
@@ -439,11 +313,11 @@ public class MediaFocusControl implements OnFinished {
*/
private void removeFocusStackEntry(String clientToRemove, boolean signal) {
// is the current top of the focus stack abandoning focus? (because of request, not death)
- if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove))
+ if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
{
//Log.i(TAG, " removeFocusStackEntry() removing top of stack");
- FocusStackEntry fse = mFocusStack.pop();
- fse.unlinkToDeath();
+ FocusRequester fr = mFocusStack.pop();
+ fr.release();
if (signal) {
// notify the new top of the stack it gained focus
notifyTopOfAudioFocusStack();
@@ -457,14 +331,14 @@ public class MediaFocusControl implements OnFinished {
// no need to update focus.
// (using an iterator on the stack so we can safely remove an entry after having
// evaluated it, traversal order doesn't matter here)
- Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
+ Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) {
- FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
- if(fse.mClientId.equals(clientToRemove)) {
+ FocusRequester fr = (FocusRequester)stackIterator.next();
+ if(fr.hasSameClient(clientToRemove)) {
Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for "
- + fse.mClientId);
+ + clientToRemove);
stackIterator.remove();
- fse.unlinkToDeath();
+ fr.release();
}
}
}
@@ -478,15 +352,14 @@ public class MediaFocusControl implements OnFinished {
private void removeFocusStackEntryForClient(IBinder cb) {
// is the owner of the audio focus part of the client to remove?
boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
- mFocusStack.peek().mSourceRef.equals(cb);
+ mFocusStack.peek().hasSameBinder(cb);
// (using an iterator on the stack so we can safely remove an entry after having
// evaluated it, traversal order doesn't matter here)
- Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
+ Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) {
- FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
- if(fse.mSourceRef.equals(cb)) {
- Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for "
- + fse.mClientId);
+ FocusRequester fr = (FocusRequester)stackIterator.next();
+ if(fr.hasSameBinder(cb)) {
+ Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for " + cb);
stackIterator.remove();
// the client just died, no need to unlink to its death
}
@@ -509,7 +382,7 @@ public class MediaFocusControl implements OnFinished {
private boolean canReassignAudioFocus() {
// focus requests are rejected during a phone call or when the phone is ringing
// this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
- if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) {
+ if (!mFocusStack.isEmpty() && mFocusStack.peek().hasSameClient(IN_VOICE_COMM_FOCUS_ID)) {
return false;
}
return true;
@@ -519,7 +392,7 @@ public class MediaFocusControl implements OnFinished {
* Inner class to monitor audio focus client deaths, and remove them from the audio focus
* stack if necessary.
*/
- private class AudioFocusDeathHandler implements IBinder.DeathRecipient {
+ protected class AudioFocusDeathHandler implements IBinder.DeathRecipient {
private IBinder mCb; // To be notified of client's death
AudioFocusDeathHandler(IBinder cb) {
@@ -574,10 +447,10 @@ public class MediaFocusControl implements OnFinished {
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
- if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
+ if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
// if focus is already owned by this client and the reason for acquiring the focus
// hasn't changed, don't do anything
- if (mFocusStack.peek().mFocusGainRequest == focusChangeHint) {
+ if (mFocusStack.peek().getGainRequest() == focusChangeHint) {
// unlink death handler so it can be gc'ed.
// linkToDeath() creates a JNI global reference preventing collection.
cb.unlinkToDeath(afdh, 0);
@@ -585,12 +458,12 @@ public class MediaFocusControl implements OnFinished {
}
// the reason for the audio focus request has changed: remove the current top of
// stack and respond as if we had a new focus owner
- FocusStackEntry fse = mFocusStack.pop();
- fse.unlinkToDeath();
+ FocusRequester fr = mFocusStack.pop();
+ fr.release();
}
// notify current top of stack it is losing focus
- if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
+ if (!mFocusStack.empty() && mFocusStack.peek().canDispatchFocus()) {
mFocusStack.peek().handleExternalFocusGain(focusChangeHint);
}
@@ -598,7 +471,7 @@ public class MediaFocusControl implements OnFinished {
removeFocusStackEntry(clientId, false /* signal */);
// push focus requester at the top of the audio focus stack
- mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
+ mFocusStack.push(new FocusRequester(mainStreamType, focusChangeHint, fd, cb,
clientId, afdh, callingPackageName, Binder.getCallingUid()));
// there's a new top of the stack, let the remote control know
@@ -1609,13 +1482,13 @@ public class MediaFocusControl implements OnFinished {
// characteristics:
// - focus gain on STREAM_MUSIC stream
// - non-transient focus gain on a stream other than music
- FocusStackEntry af = null;
+ FocusRequester af = null;
try {
for (int index = mFocusStack.size()-1; index >= 0; index--) {
- FocusStackEntry fse = mFocusStack.elementAt(index);
- if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
- || (fse.mFocusGainRequest == AudioManager.AUDIOFOCUS_GAIN)) {
- af = fse;
+ FocusRequester fr = mFocusStack.elementAt(index);
+ if ((fr.getStreamType() == AudioManager.STREAM_MUSIC)
+ || (fr.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN)) {
+ af = fr;
break;
}
}
@@ -1629,16 +1502,13 @@ public class MediaFocusControl implements OnFinished {
}
// if the audio focus and RC owners belong to different packages, there is a mismatch, clear
- if ((mRCStack.peek().mCallingPackageName != null)
- && (af.mPackageName != null)
- && !(mRCStack.peek().mCallingPackageName.compareTo(
- af.mPackageName) == 0)) {
+ if (!af.hasSamePackage(mRCStack.peek().mCallingPackageName)) {
clearRemoteControlDisplay_syncAfRcs();
return;
}
// if the audio focus didn't originate from the same Uid as the one in which the remote
// control information will be retrieved, clear
- if (mRCStack.peek().mCallingUid != af.mCallingUid) {
+ if (!af.hasSameUid(mRCStack.peek().mCallingUid)) {
clearRemoteControlDisplay_syncAfRcs();
return;
}