Change sendSessionModifyRequest VideoProvider API signature.

Including a fromProfile in addition to the requestedProfile.

- Changed VideoCallImpl to generate the fromVideoProfile based on the
call's current videoState.  This ensures the InCall UI only needs to
pass in the new video profile; the VideoCall Impl already has enough
knowledge to generate the fromProfile.
  - Changed VideoCallImpl to track the current videoQuality, which forms
a part of the fromVideoProfile.

Bug: 20704229
Change-Id: I89f293f03a2b13fc8c1dcfd8a07ab8640d3950e0
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index fee6495..adab00b 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1000,9 +1000,9 @@
         }
 
         boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
-                !Objects.equals(mVideoCall, parcelableCall.getVideoCall());
+                !Objects.equals(mVideoCall, parcelableCall.getVideoCall(this));
         if (videoCallChanged) {
-            mVideoCall = parcelableCall.getVideoCall();
+            mVideoCall = parcelableCall.getVideoCall(this);
         }
 
         int state = parcelableCall.getState();
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 3060f40..4bc639b 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import com.android.internal.os.SomeArgs;
 import com.android.internal.telecom.IVideoCallback;
 import com.android.internal.telecom.IVideoProvider;
 
@@ -471,9 +472,16 @@
                     case MSG_SET_ZOOM:
                         onSetZoom((Float) msg.obj);
                         break;
-                    case MSG_SEND_SESSION_MODIFY_REQUEST:
-                        onSendSessionModifyRequest((VideoProfile) msg.obj);
+                    case MSG_SEND_SESSION_MODIFY_REQUEST: {
+                        SomeArgs args = (SomeArgs) msg.obj;
+                        try {
+                            onSendSessionModifyRequest((VideoProfile) args.arg1,
+                                    (VideoProfile) args.arg2);
+                        } finally {
+                            args.recycle();
+                        }
                         break;
+                    }
                     case MSG_SEND_SESSION_MODIFY_RESPONSE:
                         onSendSessionModifyResponse((VideoProfile) msg.obj);
                         break;
@@ -527,9 +535,11 @@
                 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
             }
 
-            public void sendSessionModifyRequest(VideoProfile requestProfile) {
-                mMessageHandler.obtainMessage(
-                        MSG_SEND_SESSION_MODIFY_REQUEST, requestProfile).sendToTarget();
+            public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = fromProfile;
+                args.arg2 = toProfile;
+                mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
             }
 
             public void sendSessionModifyResponse(VideoProfile responseProfile) {
@@ -606,9 +616,11 @@
          * Some examples of session modification requests: upgrade connection from audio to video,
          * downgrade connection from video to audio, pause video.
          *
-         * @param requestProfile The requested connection video properties.
+         * @param fromProfile The video properties prior to the request.
+         * @param toProfile The video properties with the requested changes made.
          */
-        public abstract void onSendSessionModifyRequest(VideoProfile requestProfile);
+        public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
+                VideoProfile toProfile);
 
         /**te
          * Provides a response to a request to change the current connection session video
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 1a30910..bb65ce9a 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -178,10 +178,10 @@
      * Returns an object for remotely communicating through the video call provider's binder.
      * @return The video call.
      */
-    public InCallService.VideoCall getVideoCall() {
+    public InCallService.VideoCall getVideoCall(Call call) {
         if (mVideoCall == null && mVideoCallProvider != null) {
             try {
-                mVideoCall = new VideoCallImpl(mVideoCallProvider);
+                mVideoCall = new VideoCallImpl(mVideoCallProvider, call);
             } catch (RemoteException ignored) {
                 // Ignore RemoteException.
             }
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 1493b20..9ca9f316 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -350,9 +350,9 @@
             }
         }
 
-        public void sendSessionModifyRequest(VideoProfile reqProfile) {
+        public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
             try {
-                mVideoProviderBinder.sendSessionModifyRequest(reqProfile);
+                mVideoProviderBinder.sendSessionModifyRequest(fromProfile, toProfile);
             } catch (RemoteException e) {
             }
         }
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index 7a82c1b..331f57e 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -40,6 +40,8 @@
     private final IVideoProvider mVideoProvider;
     private final VideoCallListenerBinder mBinder;
     private VideoCall.Callback mCallback;
+    private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
+    private Call mCall;
 
     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
         @Override
@@ -161,6 +163,7 @@
                             (CameraCapabilities) msg.obj);
                     break;
                 case MSG_CHANGE_VIDEO_QUALITY:
+                    mVideoQuality = msg.arg1;
                     mCallback.onVideoQualityChanged(msg.arg1);
                     break;
                 default:
@@ -171,12 +174,13 @@
 
     private Handler mHandler;
 
-    VideoCallImpl(IVideoProvider videoProvider) throws RemoteException {
+    VideoCallImpl(IVideoProvider videoProvider, Call call) throws RemoteException {
         mVideoProvider = videoProvider;
         mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
 
         mBinder = new VideoCallListenerBinder();
         mVideoProvider.addVideoCallback(mBinder);
+        mCall = call;
     }
 
     public void destroy() {
@@ -251,10 +255,24 @@
         }
     }
 
-    /** {@inheritDoc} */
+    /**
+     * Sends a session modification request to the video provider.
+     * <p>
+     * The {@link InCallService} will create the {@code requestProfile} based on the current
+     * video state (i.e. {@link Call.Details#getVideoState()}).  It is, however, possible that the
+     * video state maintained by the {@link InCallService} could get out of sync with what is known
+     * by the {@link android.telecom.Connection.VideoProvider}.  To remove ambiguity, the
+     * {@link VideoCallImpl} passes along the pre-modify video profile to the {@code VideoProvider}
+     * to ensure it has full context of the requested change.
+     *
+     * @param requestProfile The requested video profile.
+     */
     public void sendSessionModifyRequest(VideoProfile requestProfile) {
         try {
-            mVideoProvider.sendSessionModifyRequest(requestProfile);
+            VideoProfile originalProfile = new VideoProfile(mCall.getDetails().getVideoState(),
+                    mVideoQuality);
+
+            mVideoProvider.sendSessionModifyRequest(originalProfile, requestProfile);
         } catch (RemoteException e) {
         }
     }