Loading media/java/android/media/MediaFocusControl.java +101 −164 Original line number Diff line number Diff line Loading @@ -471,10 +471,6 @@ public class MediaFocusControl implements OnFinished { final FocusRequester exFocusOwner = mFocusStack.pop(); exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS); exFocusOwner.release(); // clear RCD synchronized(mPRStack) { clearRemoteControlDisplay_syncAfRcs(); } } } } Loading Loading @@ -535,10 +531,6 @@ public class MediaFocusControl implements OnFinished { if (signal) { // notify the new top of the stack it gained focus notifyTopOfAudioFocusStack(); // there's a new top of the stack, let the remote control know synchronized(mPRStack) { checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } } } else { // focus is abandoned by a client that's not at the top of the stack, Loading Loading @@ -582,10 +574,6 @@ public class MediaFocusControl implements OnFinished { // we removed an entry at the top of the stack: // notify the new top of the stack it gained focus. notifyTopOfAudioFocusStack(); // there's a new top of the stack, let the remote control know synchronized(mPRStack) { checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } } } Loading Loading @@ -694,10 +682,6 @@ public class MediaFocusControl implements OnFinished { 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 synchronized(mPRStack) { checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } }//synchronized(mAudioFocusLock) return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; Loading Loading @@ -1237,11 +1221,11 @@ public class MediaFocusControl implements OnFinished { /** * Helper function: * Set the new remote control receiver at the top of the RC focus stack. * Called synchronized on mAudioFocusLock, then mPRStack * Called synchronized on mPRStack * precondition: mediaIntent != null * @return true if mPRStack was changed, false otherwise */ private boolean pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, private boolean pushMediaButtonReceiver_syncPrs(PendingIntent mediaIntent, ComponentName target, IBinder token) { // already at top of stack? if (!mPRStack.empty() && mPRStack.peek().hasMatchingMediaButtonIntent(mediaIntent)) { Loading Loading @@ -1285,10 +1269,10 @@ public class MediaFocusControl implements OnFinished { /** * Helper function: * Remove the remote control receiver from the RC focus stack. * Called synchronized on mAudioFocusLock, then mPRStack * Called synchronized on mPRStack * precondition: pi != null */ private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) { private void removeMediaButtonReceiver_syncPrs(PendingIntent pi) { try { for (int index = mPRStack.size()-1; index >= 0; index--) { final PlayerRecord prse = mPRStack.elementAt(index); Loading Loading @@ -1470,7 +1454,7 @@ public class MediaFocusControl implements OnFinished { * Helper function: * Called synchronized on mPRStack */ private void clearRemoteControlDisplay_syncAfRcs() { private void clearRemoteControlDisplay_syncPrs() { synchronized(mCurrentRcLock) { mCurrentRcClient = null; } Loading @@ -1480,20 +1464,20 @@ public class MediaFocusControl implements OnFinished { /** * Helper function for code readability: only to be called from * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for * checkUpdateRemoteControlDisplay_syncPrs() which checks the preconditions for * this method. * Preconditions: * - called synchronized mAudioFocusLock then on mPRStack * - called synchronized on mPRStack * - mPRStack.isEmpty() is false */ private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { private void updateRemoteControlDisplay_syncPrs(int infoChangedFlags) { PlayerRecord prse = mPRStack.peek(); int infoFlagsAboutToBeUsed = infoChangedFlags; // this is where we enforce opt-in for information display on the remote controls // with the new AudioManager.registerRemoteControlClient() API if (prse.getRcc() == null) { //Log.w(TAG, "Can't update remote control display with null remote control client"); clearRemoteControlDisplay_syncAfRcs(); clearRemoteControlDisplay_syncPrs(); return; } synchronized(mCurrentRcLock) { Loading @@ -1511,62 +1495,25 @@ public class MediaFocusControl implements OnFinished { /** * Helper function: * Called synchronized on mAudioFocusLock, then mPRStack * Called synchronized on mPRStack * Check whether the remote control display should be updated, triggers the update if required * @param infoChangedFlags the flags corresponding to the remote control client information * that has changed, if applicable (checking for the update conditions might trigger a * clear, rather than an update event). */ private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { private void checkUpdateRemoteControlDisplay_syncPrs(int infoChangedFlags) { // determine whether the remote control display should be refreshed // if either stack is empty, there is a mismatch, so clear the RC display if (mPRStack.isEmpty() || mFocusStack.isEmpty()) { clearRemoteControlDisplay_syncAfRcs(); return; } // determine which entry in the AudioFocus stack to consider, and compare against the // top of the stack for the media button event receivers : simply using the top of the // stack would make the entry disappear from the RemoteControlDisplay in conditions such as // notifications playing during music playback. // Crawl the AudioFocus stack from the top until an entry is found with the following // characteristics: // - focus gain on STREAM_MUSIC stream // - non-transient focus gain on a stream other than music FocusRequester af = null; try { for (int index = mFocusStack.size()-1; index >= 0; index--) { FocusRequester fr = mFocusStack.elementAt(index); if ((fr.getStreamType() == AudioManager.STREAM_MUSIC) || (fr.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN)) { af = fr; break; } } } catch (ArrayIndexOutOfBoundsException e) { Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e); af = null; } if (af == null) { clearRemoteControlDisplay_syncAfRcs(); // if the player record stack is empty, there is nothing to display, so clear the RC display if (mPRStack.isEmpty()) { clearRemoteControlDisplay_syncPrs(); return; } // if the audio focus and RC owners belong to different packages, there is a mismatch, clear if (!af.hasSamePackage(mPRStack.peek().getCallingPackageName())) { 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 (!af.hasSameUid(mPRStack.peek().getCallingUid())) { clearRemoteControlDisplay_syncAfRcs(); return; } // this is where more rules for refresh go // refresh conditions were verified: update the remote controls // ok to call: synchronized mAudioFocusLock then on mPRStack, mPRStack is not empty updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); // ok to call: synchronized on mPRStack, mPRStack is not empty updateRemoteControlDisplay_syncPrs(infoChangedFlags); } /** Loading @@ -1582,7 +1529,6 @@ public class MediaFocusControl implements OnFinished { private void onPromoteRcc(int rccId) { if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); } synchronized(mAudioFocusLock) { synchronized(mPRStack) { // ignore if given RCC ID is already at top of remote control stack if (!mPRStack.isEmpty() && (mPRStack.peek().getRccId() == rccId)) { Loading @@ -1603,14 +1549,13 @@ public class MediaFocusControl implements OnFinished { final PlayerRecord prse = mPRStack.remove(indexToPromote); mPRStack.push(prse); // the RC stack changed, reevaluate the display checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL); } } catch (ArrayIndexOutOfBoundsException e) { // not expected to happen, indicates improper concurrent modification Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); } }//synchronized(mPRStack) }//synchronized(mAudioFocusLock) } /** Loading @@ -1621,12 +1566,10 @@ public class MediaFocusControl implements OnFinished { IBinder token) { Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent); synchronized(mAudioFocusLock) { synchronized(mPRStack) { if (pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token)) { if (pushMediaButtonReceiver_syncPrs(mediaIntent, eventReceiver, token)) { // new RC client, assume every type of information shall be queried checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL); } } } Loading @@ -1639,14 +1582,12 @@ public class MediaFocusControl implements OnFinished { { Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent); synchronized(mAudioFocusLock) { synchronized(mPRStack) { boolean topOfStackWillChange = isCurrentRcController(mediaIntent); removeMediaButtonReceiver_syncAfRcs(mediaIntent); removeMediaButtonReceiver_syncPrs(mediaIntent); if (topOfStackWillChange) { // current RC client will change, assume every type of info needs to be queried checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL); } } } Loading Loading @@ -1697,7 +1638,6 @@ public class MediaFocusControl implements OnFinished { IRemoteControlClient rcClient, String callingPackageName) { if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; synchronized(mAudioFocusLock) { synchronized(mPRStack) { // store the new display information try { Loading @@ -1716,7 +1656,7 @@ public class MediaFocusControl implements OnFinished { // there is a new (non-null) client: // give the new client the displays (if any) if (mRcDisplays.size() > 0) { plugRemoteControlDisplaysIntoClient_syncRcStack(prse.getRcc()); plugRemoteControlDisplaysIntoClient_syncPrs(prse.getRcc()); } break; } Loading @@ -1729,10 +1669,9 @@ public class MediaFocusControl implements OnFinished { // if the eventReceiver is at the top of the stack // then check for potential refresh of the remote controls if (isCurrentRcController(mediaIntent)) { checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL); } }//synchronized(mPRStack) }//synchronized(mAudioFocusLock) return rccId; } Loading @@ -1743,7 +1682,6 @@ public class MediaFocusControl implements OnFinished { protected void unregisterRemoteControlClient(PendingIntent mediaIntent, IRemoteControlClient rcClient) { if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient); synchronized(mAudioFocusLock) { synchronized(mPRStack) { boolean topRccChange = false; try { Loading @@ -1764,8 +1702,7 @@ public class MediaFocusControl implements OnFinished { } if (topRccChange) { // no more RCC for the RCD, check for potential refresh of the remote controls checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL); } } } Loading Loading @@ -1843,7 +1780,7 @@ public class MediaFocusControl implements OnFinished { * Plug each registered display into the specified client * @param rcc, guaranteed non null */ private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) { private void plugRemoteControlDisplaysIntoClient_syncPrs(IRemoteControlClient rcc) { final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); while (displayIterator.hasNext()) { final DisplayInfoForServer di = displayIterator.next(); Loading Loading
media/java/android/media/MediaFocusControl.java +101 −164 Original line number Diff line number Diff line Loading @@ -471,10 +471,6 @@ public class MediaFocusControl implements OnFinished { final FocusRequester exFocusOwner = mFocusStack.pop(); exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS); exFocusOwner.release(); // clear RCD synchronized(mPRStack) { clearRemoteControlDisplay_syncAfRcs(); } } } } Loading Loading @@ -535,10 +531,6 @@ public class MediaFocusControl implements OnFinished { if (signal) { // notify the new top of the stack it gained focus notifyTopOfAudioFocusStack(); // there's a new top of the stack, let the remote control know synchronized(mPRStack) { checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } } } else { // focus is abandoned by a client that's not at the top of the stack, Loading Loading @@ -582,10 +574,6 @@ public class MediaFocusControl implements OnFinished { // we removed an entry at the top of the stack: // notify the new top of the stack it gained focus. notifyTopOfAudioFocusStack(); // there's a new top of the stack, let the remote control know synchronized(mPRStack) { checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } } } Loading Loading @@ -694,10 +682,6 @@ public class MediaFocusControl implements OnFinished { 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 synchronized(mPRStack) { checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } }//synchronized(mAudioFocusLock) return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; Loading Loading @@ -1237,11 +1221,11 @@ public class MediaFocusControl implements OnFinished { /** * Helper function: * Set the new remote control receiver at the top of the RC focus stack. * Called synchronized on mAudioFocusLock, then mPRStack * Called synchronized on mPRStack * precondition: mediaIntent != null * @return true if mPRStack was changed, false otherwise */ private boolean pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, private boolean pushMediaButtonReceiver_syncPrs(PendingIntent mediaIntent, ComponentName target, IBinder token) { // already at top of stack? if (!mPRStack.empty() && mPRStack.peek().hasMatchingMediaButtonIntent(mediaIntent)) { Loading Loading @@ -1285,10 +1269,10 @@ public class MediaFocusControl implements OnFinished { /** * Helper function: * Remove the remote control receiver from the RC focus stack. * Called synchronized on mAudioFocusLock, then mPRStack * Called synchronized on mPRStack * precondition: pi != null */ private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) { private void removeMediaButtonReceiver_syncPrs(PendingIntent pi) { try { for (int index = mPRStack.size()-1; index >= 0; index--) { final PlayerRecord prse = mPRStack.elementAt(index); Loading Loading @@ -1470,7 +1454,7 @@ public class MediaFocusControl implements OnFinished { * Helper function: * Called synchronized on mPRStack */ private void clearRemoteControlDisplay_syncAfRcs() { private void clearRemoteControlDisplay_syncPrs() { synchronized(mCurrentRcLock) { mCurrentRcClient = null; } Loading @@ -1480,20 +1464,20 @@ public class MediaFocusControl implements OnFinished { /** * Helper function for code readability: only to be called from * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for * checkUpdateRemoteControlDisplay_syncPrs() which checks the preconditions for * this method. * Preconditions: * - called synchronized mAudioFocusLock then on mPRStack * - called synchronized on mPRStack * - mPRStack.isEmpty() is false */ private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { private void updateRemoteControlDisplay_syncPrs(int infoChangedFlags) { PlayerRecord prse = mPRStack.peek(); int infoFlagsAboutToBeUsed = infoChangedFlags; // this is where we enforce opt-in for information display on the remote controls // with the new AudioManager.registerRemoteControlClient() API if (prse.getRcc() == null) { //Log.w(TAG, "Can't update remote control display with null remote control client"); clearRemoteControlDisplay_syncAfRcs(); clearRemoteControlDisplay_syncPrs(); return; } synchronized(mCurrentRcLock) { Loading @@ -1511,62 +1495,25 @@ public class MediaFocusControl implements OnFinished { /** * Helper function: * Called synchronized on mAudioFocusLock, then mPRStack * Called synchronized on mPRStack * Check whether the remote control display should be updated, triggers the update if required * @param infoChangedFlags the flags corresponding to the remote control client information * that has changed, if applicable (checking for the update conditions might trigger a * clear, rather than an update event). */ private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { private void checkUpdateRemoteControlDisplay_syncPrs(int infoChangedFlags) { // determine whether the remote control display should be refreshed // if either stack is empty, there is a mismatch, so clear the RC display if (mPRStack.isEmpty() || mFocusStack.isEmpty()) { clearRemoteControlDisplay_syncAfRcs(); return; } // determine which entry in the AudioFocus stack to consider, and compare against the // top of the stack for the media button event receivers : simply using the top of the // stack would make the entry disappear from the RemoteControlDisplay in conditions such as // notifications playing during music playback. // Crawl the AudioFocus stack from the top until an entry is found with the following // characteristics: // - focus gain on STREAM_MUSIC stream // - non-transient focus gain on a stream other than music FocusRequester af = null; try { for (int index = mFocusStack.size()-1; index >= 0; index--) { FocusRequester fr = mFocusStack.elementAt(index); if ((fr.getStreamType() == AudioManager.STREAM_MUSIC) || (fr.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN)) { af = fr; break; } } } catch (ArrayIndexOutOfBoundsException e) { Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e); af = null; } if (af == null) { clearRemoteControlDisplay_syncAfRcs(); // if the player record stack is empty, there is nothing to display, so clear the RC display if (mPRStack.isEmpty()) { clearRemoteControlDisplay_syncPrs(); return; } // if the audio focus and RC owners belong to different packages, there is a mismatch, clear if (!af.hasSamePackage(mPRStack.peek().getCallingPackageName())) { 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 (!af.hasSameUid(mPRStack.peek().getCallingUid())) { clearRemoteControlDisplay_syncAfRcs(); return; } // this is where more rules for refresh go // refresh conditions were verified: update the remote controls // ok to call: synchronized mAudioFocusLock then on mPRStack, mPRStack is not empty updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); // ok to call: synchronized on mPRStack, mPRStack is not empty updateRemoteControlDisplay_syncPrs(infoChangedFlags); } /** Loading @@ -1582,7 +1529,6 @@ public class MediaFocusControl implements OnFinished { private void onPromoteRcc(int rccId) { if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); } synchronized(mAudioFocusLock) { synchronized(mPRStack) { // ignore if given RCC ID is already at top of remote control stack if (!mPRStack.isEmpty() && (mPRStack.peek().getRccId() == rccId)) { Loading @@ -1603,14 +1549,13 @@ public class MediaFocusControl implements OnFinished { final PlayerRecord prse = mPRStack.remove(indexToPromote); mPRStack.push(prse); // the RC stack changed, reevaluate the display checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL); } } catch (ArrayIndexOutOfBoundsException e) { // not expected to happen, indicates improper concurrent modification Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); } }//synchronized(mPRStack) }//synchronized(mAudioFocusLock) } /** Loading @@ -1621,12 +1566,10 @@ public class MediaFocusControl implements OnFinished { IBinder token) { Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent); synchronized(mAudioFocusLock) { synchronized(mPRStack) { if (pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token)) { if (pushMediaButtonReceiver_syncPrs(mediaIntent, eventReceiver, token)) { // new RC client, assume every type of information shall be queried checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL); } } } Loading @@ -1639,14 +1582,12 @@ public class MediaFocusControl implements OnFinished { { Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent); synchronized(mAudioFocusLock) { synchronized(mPRStack) { boolean topOfStackWillChange = isCurrentRcController(mediaIntent); removeMediaButtonReceiver_syncAfRcs(mediaIntent); removeMediaButtonReceiver_syncPrs(mediaIntent); if (topOfStackWillChange) { // current RC client will change, assume every type of info needs to be queried checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL); } } } Loading Loading @@ -1697,7 +1638,6 @@ public class MediaFocusControl implements OnFinished { IRemoteControlClient rcClient, String callingPackageName) { if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; synchronized(mAudioFocusLock) { synchronized(mPRStack) { // store the new display information try { Loading @@ -1716,7 +1656,7 @@ public class MediaFocusControl implements OnFinished { // there is a new (non-null) client: // give the new client the displays (if any) if (mRcDisplays.size() > 0) { plugRemoteControlDisplaysIntoClient_syncRcStack(prse.getRcc()); plugRemoteControlDisplaysIntoClient_syncPrs(prse.getRcc()); } break; } Loading @@ -1729,10 +1669,9 @@ public class MediaFocusControl implements OnFinished { // if the eventReceiver is at the top of the stack // then check for potential refresh of the remote controls if (isCurrentRcController(mediaIntent)) { checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL); } }//synchronized(mPRStack) }//synchronized(mAudioFocusLock) return rccId; } Loading @@ -1743,7 +1682,6 @@ public class MediaFocusControl implements OnFinished { protected void unregisterRemoteControlClient(PendingIntent mediaIntent, IRemoteControlClient rcClient) { if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient); synchronized(mAudioFocusLock) { synchronized(mPRStack) { boolean topRccChange = false; try { Loading @@ -1764,8 +1702,7 @@ public class MediaFocusControl implements OnFinished { } if (topRccChange) { // no more RCC for the RCD, check for potential refresh of the remote controls checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL); } } } Loading Loading @@ -1843,7 +1780,7 @@ public class MediaFocusControl implements OnFinished { * Plug each registered display into the specified client * @param rcc, guaranteed non null */ private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) { private void plugRemoteControlDisplaysIntoClient_syncPrs(IRemoteControlClient rcc) { final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator(); while (displayIterator.hasNext()) { final DisplayInfoForServer di = displayIterator.next(); Loading