b/15729204 Pipe sessions through to VolumePanel

When remote volume is changed via volume buttons we need to notify
the system UI so it can show the slider. This also passes it the
controller to use so adjustments to the slider are sent back to
the correct session.

Change-Id: If5847bcd5db16c56e0e9904b88c94e5b28954c41
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index c0b7d68..873ed71 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -27,8 +27,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.media.AudioManager;
 import android.media.IAudioService;
+import android.media.IRemoteVolumeController;
 import android.media.routeprovider.RouteRequest;
 import android.media.session.IActiveSessionsListener;
 import android.media.session.ISession;
@@ -98,6 +98,10 @@
     // session so we drop late callbacks properly.
     private int mShowRoutesRequestId = 0;
 
+    // Used to notify system UI when remote volume was changed. TODO find a
+    // better way to handle this.
+    private IRemoteVolumeController mRvc;
+
     // TODO refactor to have per user state for providers. See
     // MediaRouterService for an example
 
@@ -225,6 +229,16 @@
         }
     }
 
+    public void onSessionPlaybackTypeChanged(MediaSessionRecord record) {
+        synchronized (mLock) {
+            if (!mAllSessions.contains(record)) {
+                Log.d(TAG, "Unknown session changed playback type. Ignoring.");
+                return;
+            }
+            pushRemoteVolumeUpdateLocked(record.getUserId());
+        }
+    }
+
     @Override
     public void onStartUser(int userHandle) {
         updateUser();
@@ -367,6 +381,13 @@
         }
     }
 
+    private void enforceStatusBarPermission(String action, int pid, int uid) {
+        if (getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+                pid, uid) != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Only system ui may " + action);
+        }
+    }
+
     /**
      * This checks if the component is an enabled notification listener for the
      * specified user. Enabled components may only operate on behalf of the user
@@ -497,6 +518,7 @@
             for (int i = 0; i < size; i++) {
                 tokens.add(new MediaSessionToken(records.get(i).getControllerBinder()));
             }
+            pushRemoteVolumeUpdateLocked(userId);
             for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
                 SessionsListenerRecord record = mSessionsListeners.get(i);
                 if (record.mUserId == UserHandle.USER_ALL || record.mUserId == userId) {
@@ -512,6 +534,17 @@
         }
     }
 
+    private void pushRemoteVolumeUpdateLocked(int userId) {
+        if (mRvc != null) {
+            try {
+                MediaSessionRecord record = mPriorityStack.getDefaultRemoteSession(userId);
+                mRvc.updateRemoteController(record == null ? null : record.getControllerBinder());
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error sending default remote volume to sys ui.", e);
+            }
+        }
+    }
+
     private void persistMediaButtonReceiverLocked(MediaSessionRecord record) {
         ComponentName receiver = record.getMediaButtonReceiver();
         if (receiver != null) {
@@ -844,6 +877,19 @@
         }
 
         @Override
+        public void setRemoteVolumeController(IRemoteVolumeController rvc) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                enforceStatusBarPermission("listen for volume changes", pid, uid);
+                mRvc = rvc;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
             if (getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -929,6 +975,13 @@
                 }
             } else {
                 session.adjustVolumeBy(delta, flags);
+                if (mRvc != null) {
+                    try {
+                        mRvc.remoteVolumeChanged(session.getControllerBinder(), flags);
+                    } catch (Exception e) {
+                        Log.wtf(TAG, "Error sending volume change to system UI.", e);
+                    }
+                }
             }
         }