am db0944de: am 60e7f819: Merge "Improve RemoteControlDisplay registration" into klp-dev

* commit 'db0944de128247e7e6016982a14513b04ac5e6f1':
  Improve RemoteControlDisplay registration
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
index 48079f2..999b8ba 100644
--- a/media/java/android/media/IRemoteControlClient.aidl
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -41,6 +41,13 @@
     void onInformationRequested(int generationId, int infoFlags);
 
     /**
+     * Notifies a remote control client that information for the given generation ID is
+     * requested for the given IRemoteControlDisplay alone.
+     * @param rcd the display to which current info should be sent
+     */
+    void informationRequestForDisplay(IRemoteControlDisplay rcd, int w, int h);
+
+    /**
      * Sets the generation counter of the current client that is displayed on the remote control.
      */
     void setCurrentClientGenerationId(int clientGeneration);
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index cf5be1b..2a7a731 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -139,6 +139,7 @@
     private static final int MSG_RCC_NEW_PLAYBACK_STATE = 7;
     private static final int MSG_RCC_SEEK_REQUEST = 8;
     private static final int MSG_RCC_UPDATE_METADATA = 9;
+    private static final int MSG_RCDISPLAY_INIT_INFO = 10;
 
     // sendMsg() flags
     /** If the msg is already queued, replace it with this one. */
@@ -214,6 +215,12 @@
                 case MSG_PROMOTE_RCC:
                     onPromoteRcc(msg.arg1);
                     break;
+
+                case MSG_RCDISPLAY_INIT_INFO:
+                    // msg.obj is guaranteed to be non null
+                    onRcDisplayInitInfo((IRemoteControlDisplay)msg.obj /*newRcd*/,
+                            msg.arg1/*w*/, msg.arg2/*h*/);
+                    break;
             }
         }
     }
@@ -852,6 +859,11 @@
      * Access protected by mCurrentRcLock.
      */
     private IRemoteControlClient mCurrentRcClient = null;
+    /**
+     * The PendingIntent associated with mCurrentRcClient. Its value is irrelevant
+     * if mCurrentRcClient is null
+     */
+    private PendingIntent mCurrentRcClientIntent = null;
 
     private final static int RC_INFO_NONE = 0;
     private final static int RC_INFO_ALL =
@@ -1446,6 +1458,7 @@
 
                     // tell the current client that it needs to send info
                     try {
+                        //TODO change name to informationRequestForAllDisplays()
                         mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
                     } catch (RemoteException e) {
                         Log.e(TAG, "Current valid remote client is dead: "+e);
@@ -1460,6 +1473,36 @@
         }
     }
 
+    /**
+     * Called when processing MSG_RCDISPLAY_INIT_INFO event
+     * Causes the current RemoteControlClient to send its info (metadata, playstate...) to
+     *   a single RemoteControlDisplay, NOT all of them, as with MSG_RCDISPLAY_UPDATE.
+     */
+    private void onRcDisplayInitInfo(IRemoteControlDisplay newRcd, int w, int h) {
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                if (mCurrentRcClient != null) {
+                    if (DEBUG_RC) { Log.i(TAG, "Init RCD with current info"); }
+                    try {
+                        // synchronously update the new RCD with the current client generation
+                        // and matching PendingIntent
+                        newRcd.setCurrentClientId(mCurrentRcClientGen, mCurrentRcClientIntent,
+                                false);
+
+                        // tell the current RCC that it needs to send info, but only to the new RCD
+                        try {
+                            mCurrentRcClient.informationRequestForDisplay(newRcd, w, h);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Current valid remote client is dead: ", e);
+                            mCurrentRcClient = null;
+                        }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Dead display in onRcDisplayInitInfo()", e);
+                    }
+                }
+            }
+        }
+    }
 
     /**
      * Helper function:
@@ -1497,6 +1540,7 @@
                 infoFlagsAboutToBeUsed = RC_INFO_ALL;
             }
             mCurrentRcClient = rcse.mRcClient;
+            mCurrentRcClientIntent = rcse.mMediaIntent;
         }
         // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
         mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
@@ -1923,8 +1967,12 @@
                     }
                 }
 
-                // we have a new display, of which all the clients are now aware: have it be updated
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                // we have a new display, of which all the clients are now aware: have it be
+                // initialized wih the current gen ID and the current client info, do not
+                // reset the information for the other (existing) displays
+                sendMsg(mEventHandler, MSG_RCDISPLAY_INIT_INFO, SENDMSG_QUEUE,
+                        w /*arg1*/, h /*arg2*/,
+                        rcd /*obj*/, 0/*delay*/);
             }
         }
     }
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 7613c89..ab6bd70 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -515,13 +515,13 @@
                 mEditorArtwork = null;
                 if (mMetadataChanged & mArtworkChanged) {
                     // send to remote control display if conditions are met
-                    sendMetadataWithArtwork_syncCacheLock();
+                    sendMetadataWithArtwork_syncCacheLock(null, 0, 0);
                 } else if (mMetadataChanged) {
                     // send to remote control display if conditions are met
-                    sendMetadata_syncCacheLock();
+                    sendMetadata_syncCacheLock(null);
                 } else if (mArtworkChanged) {
                     // send to remote control display if conditions are met
-                    sendArtwork_syncCacheLock();
+                    sendArtwork_syncCacheLock(null, 0, 0);
                 }
                 mApplied = true;
             }
@@ -620,7 +620,7 @@
                 mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime();
 
                 // send to remote control display if conditions are met
-                sendPlaybackState_syncCacheLock();
+                sendPlaybackState_syncCacheLock(null);
                 // update AudioService
                 sendAudioServiceNewPlaybackState_syncCacheLock();
 
@@ -705,7 +705,7 @@
             mTransportControlFlags = transportControlFlags;
 
             // send to remote control display if conditions are met
-            sendTransportControlInfo_syncCacheLock();
+            sendTransportControlInfo_syncCacheLock(null);
         }
     }
 
@@ -791,7 +791,7 @@
             mPositionUpdateListener = l;
             if (oldCapa != mPlaybackPositionCapabilities) {
                 // tell RCDs that this RCC's playback position capabilities have changed
-                sendTransportControlInfo_syncCacheLock();
+                sendTransportControlInfo_syncCacheLock(null);
             }
         }
     }
@@ -813,7 +813,7 @@
             mPositionProvider = l;
             if (oldCapa != mPlaybackPositionCapabilities) {
                 // tell RCDs that this RCC's playback position capabilities have changed
-                sendTransportControlInfo_syncCacheLock();
+                sendTransportControlInfo_syncCacheLock(null);
             }
             if ((mPositionProvider != null) && (mEventHandler != null)
                     && playbackPositionShouldMove(mPlaybackState)) {
@@ -1083,6 +1083,7 @@
      */
     private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
 
+        //TODO change name to informationRequestForAllDisplays()
         public void onInformationRequested(int generationId, int infoFlags) {
             // only post messages, we can't block here
             if (mEventHandler != null) {
@@ -1096,12 +1097,30 @@
                 mEventHandler.removeMessages(MSG_REQUEST_METADATA);
                 mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
                 mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
+                mEventHandler.removeMessages(MSG_REQUEST_METADATA_ARTWORK);
                 mEventHandler.sendMessage(
-                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE));
+                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, null));
                 mEventHandler.sendMessage(
-                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL));
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
-                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
+                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL, null));
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA_ARTWORK,
+                        0, 0, null));
+            }
+        }
+
+        public void informationRequestForDisplay(IRemoteControlDisplay rcd, int w, int h) {
+            // only post messages, we can't block here
+            if (mEventHandler != null) {
+                mEventHandler.sendMessage(
+                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL, rcd));
+                mEventHandler.sendMessage(
+                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, rcd));
+                if ((w > 0) && (h > 0)) {
+                    mEventHandler.sendMessage(
+                            mEventHandler.obtainMessage(MSG_REQUEST_METADATA_ARTWORK, w, h, rcd));
+                } else {
+                    mEventHandler.sendMessage(
+                            mEventHandler.obtainMessage(MSG_REQUEST_METADATA, rcd));
+                }
             }
         }
 
@@ -1207,6 +1226,7 @@
     private final static int MSG_POSITION_DRIFT_CHECK = 11;
     private final static int MSG_DISPLAY_WANTS_POS_SYNC = 12;
     private final static int MSG_UPDATE_METADATA = 13;
+    private final static int MSG_REQUEST_METADATA_ARTWORK = 14;
 
     private class EventHandler extends Handler {
         public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1218,22 +1238,29 @@
             switch(msg.what) {
                 case MSG_REQUEST_PLAYBACK_STATE:
                     synchronized (mCacheLock) {
-                        sendPlaybackState_syncCacheLock();
+                        sendPlaybackState_syncCacheLock((IRemoteControlDisplay)msg.obj);
                     }
                     break;
                 case MSG_REQUEST_METADATA:
                     synchronized (mCacheLock) {
-                        sendMetadata_syncCacheLock();
+                        sendMetadata_syncCacheLock((IRemoteControlDisplay)msg.obj);
                     }
                     break;
                 case MSG_REQUEST_TRANSPORTCONTROL:
                     synchronized (mCacheLock) {
-                        sendTransportControlInfo_syncCacheLock();
+                        sendTransportControlInfo_syncCacheLock((IRemoteControlDisplay)msg.obj);
                     }
                     break;
                 case MSG_REQUEST_ARTWORK:
                     synchronized (mCacheLock) {
-                        sendArtwork_syncCacheLock();
+                        sendArtwork_syncCacheLock((IRemoteControlDisplay)msg.obj,
+                                msg.arg1, msg.arg2);
+                    }
+                    break;
+                case MSG_REQUEST_METADATA_ARTWORK:
+                    synchronized (mCacheLock) {
+                        sendMetadataWithArtwork_syncCacheLock((IRemoteControlDisplay)msg.obj,
+                                msg.arg1, msg.arg2);
                     }
                     break;
                 case MSG_NEW_INTERNAL_CLIENT_GEN:
@@ -1272,8 +1299,19 @@
     //===========================================================
     // Communication with the IRemoteControlDisplay (the displays known to the system)
 
-    private void sendPlaybackState_syncCacheLock() {
+    private void sendPlaybackState_syncCacheLock(IRemoteControlDisplay target) {
         if (mCurrentClientGenId == mInternalClientGenId) {
+            if (target != null) {
+                try {
+                    target.setPlaybackState(mInternalClientGenId,
+                            mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs,
+                            mPlaybackSpeed);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error in setPlaybackState() for dead display " + target, e);
+                }
+                return;
+            }
+            // target == null implies all displays must be updated
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
                 final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
@@ -1289,8 +1327,17 @@
         }
     }
 
-    private void sendMetadata_syncCacheLock() {
+    private void sendMetadata_syncCacheLock(IRemoteControlDisplay target) {
         if (mCurrentClientGenId == mInternalClientGenId) {
+            if (target != null) {
+                try {
+                    target.setMetadata(mInternalClientGenId, mMetadata);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error in setMetadata() for dead display " + target, e);
+                }
+                return;
+            }
+            // target == null implies all displays must be updated
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
                 final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
@@ -1304,8 +1351,19 @@
         }
     }
 
-    private void sendTransportControlInfo_syncCacheLock() {
+    private void sendTransportControlInfo_syncCacheLock(IRemoteControlDisplay target) {
         if (mCurrentClientGenId == mInternalClientGenId) {
+            if (target != null) {
+                try {
+                    target.setTransportControlInfo(mInternalClientGenId,
+                            mTransportControlFlags, mPlaybackPositionCapabilities);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error in setTransportControlFlags() for dead display " + target,
+                            e);
+                }
+                return;
+            }
+            // target == null implies all displays must be updated
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
                 final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
@@ -1321,9 +1379,15 @@
         }
     }
 
-    private void sendArtwork_syncCacheLock() {
+    private void sendArtwork_syncCacheLock(IRemoteControlDisplay target, int w, int h) {
         // FIXME modify to cache all requested sizes?
         if (mCurrentClientGenId == mInternalClientGenId) {
+            if (target != null) {
+                final DisplayInfoForClient di = new DisplayInfoForClient(target, w, h);
+                sendArtworkToDisplay(di);
+                return;
+            }
+            // target == null implies all displays must be updated
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
                 if (!sendArtworkToDisplay((DisplayInfoForClient) displayIterator.next())) {
@@ -1353,9 +1417,23 @@
         return true;
     }
 
-    private void sendMetadataWithArtwork_syncCacheLock() {
+    private void sendMetadataWithArtwork_syncCacheLock(IRemoteControlDisplay target, int w, int h) {
         // FIXME modify to cache all requested sizes?
         if (mCurrentClientGenId == mInternalClientGenId) {
+            if (target != null) {
+                try {
+                    if ((w > 0) && (h > 0)) {
+                        Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork, w, h);
+                        target.setAllMetadata(mInternalClientGenId, mMetadata, artwork);
+                    } else {
+                        target.setMetadata(mInternalClientGenId, mMetadata);
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error in set(All)Metadata() for dead display " + target, e);
+                }
+                return;
+            }
+            // target == null implies all displays must be updated
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
                 final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();