VideoCall: preview before upgrade video call is accepted.

preview myself before upgrade video call is handled by the receiver
and stop review if the receiver has reject or error occurs.

Change-Id: I4dbf5e469c725024bc8376c6a91bafda3a9f993e
CRs-Fixed: 1057509
diff --git a/InCallUI/res/values/qticonfig.xml b/InCallUI/res/values/qticonfig.xml
index f0c7342..8483d84 100644
--- a/InCallUI/res/values/qticonfig.xml
+++ b/InCallUI/res/values/qticonfig.xml
@@ -52,4 +52,6 @@
     <bool name="add_multi_participants_enabled">false</bool>
     <!-- Config to add participant only in conferencall call-->
     <bool name="add_participant_only_in_conference">false</bool>
+    <!-- Config to if show preview before the receiver accepts a show me upgrade video call -->
+    <bool name="config_enable_modify_call_preview">false</bool>
 </resources>
diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java
index 24ec7b2..b8b5185 100644
--- a/InCallUI/src/com/android/incallui/AnswerPresenter.java
+++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java
@@ -163,7 +163,7 @@
         }
     }
 
-    public void onSessionModificationStateChange(int sessionModificationState) {
+    public void onSessionModificationStateChange(Call call, int sessionModificationState) {
         boolean isUpgradePending = sessionModificationState ==
                 Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST;
 
diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
index d21cab5..7ea2f7f 100644
--- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
@@ -343,19 +343,19 @@
     }
 
     public void changeToVideo(int videoState) {
+        final Context context = getUi().getContext();
         if(mCall == null) {
             return;
         }
 
         if(VideoProfile.isVideo(videoState) &&
                 !PresenceHelper.getVTCapability(mCall.getNumber())) {
-            Context context = getUi().getContext();
             Toast.makeText(context,context.getString(R.string.video_call_cannot_upgrade),
                     Toast.LENGTH_SHORT).show();
             return;
         }
         final VideoProfile videoProfile = new VideoProfile(videoState);
-        QtiCallUtils.changeToVideoCall(mCall, videoProfile);
+        QtiCallUtils.changeToVideoCall(mCall, videoProfile, context);
     }
     /**
      * Switches the camera between the front-facing and back-facing camera.
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index 70da98a..259de79 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -380,7 +380,7 @@
      * @param sessionModificationState The new session modification state.
      */
     @Override
-    public void onSessionModificationStateChange(int sessionModificationState) {
+    public void onSessionModificationStateChange(Call call, int sessionModificationState) {
         Log.d(this, "onSessionModificationStateChange : sessionModificationState = " +
                 sessionModificationState);
 
diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java
index 14255cb..059345f 100644
--- a/InCallUI/src/com/android/incallui/CallList.java
+++ b/InCallUI/src/com/android/incallui/CallList.java
@@ -199,7 +199,7 @@
         final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getId());
         if (listeners != null) {
             for (CallUpdateListener listener : listeners) {
-                listener.onSessionModificationStateChange(sessionModificationState);
+                listener.onSessionModificationStateChange(call, sessionModificationState);
             }
         }
     }
@@ -717,7 +717,7 @@
          *
          * @param sessionModificationState The new session modification state.
          */
-        public void onSessionModificationStateChange(int sessionModificationState);
+        public void onSessionModificationStateChange(Call call, int sessionModificationState);
 
         /**
          * Notifies of a change to the last forwarded number for a call.
diff --git a/InCallUI/src/com/android/incallui/QtiCallUtils.java b/InCallUI/src/com/android/incallui/QtiCallUtils.java
index f3a88f1..234fa4d 100644
--- a/InCallUI/src/com/android/incallui/QtiCallUtils.java
+++ b/InCallUI/src/com/android/incallui/QtiCallUtils.java
@@ -182,7 +182,7 @@
                 Log.v(this, "Videocall: ModifyCall: upgrade/downgrade to "
                         + callTypeToString(selCallType));
                 VideoProfile videoProfile = new VideoProfile(selCallType);
-                changeToVideoClicked(call, videoProfile);
+                changeToVideoClicked(call, videoProfile, context);
                 dialog.dismiss();
             }
         };
@@ -193,8 +193,8 @@
         alert.show();
     }
 
-    public static void changeToVideoCall(Call call, VideoProfile videoProfile) {
-            changeToVideoClicked(call, videoProfile);
+    public static void changeToVideoCall(Call call, VideoProfile videoProfile, Context context) {
+            changeToVideoClicked(call, videoProfile, context);
     }
     /**
      * Converts the call type to string
@@ -215,11 +215,18 @@
      * Sends a session modify request to the telephony framework
      */
     private static void changeToVideoClicked(Call call, VideoProfile videoProfile) {
+        changeToVideoClicked(call, videoProfile, null);
+    }
+
+    private static void changeToVideoClicked(Call call, VideoProfile videoProfile, Context ctx) {
         VideoCall videoCall = call.getVideoCall();
         if (videoCall == null) {
             return;
         }
         videoCall.sendSessionModifyRequest(videoProfile);
+        if (shallShowPreviewWhileWaiting(ctx)) {
+            call.setRequestedVideoState(videoProfile.getVideoState());
+        }
         call.setSessionModificationState(Call.SessionModificationState.WAITING_FOR_RESPONSE);
         InCallAudioManager.getInstance().onModifyCallClicked(call, videoProfile.getVideoState());
     }
@@ -236,6 +243,19 @@
     }
 
     /**
+     * Checks the boolean flag in config file to figure out if it support preview before the accept
+     * video call or not
+     */
+    public static boolean shallShowPreviewWhileWaiting(Context context) {
+        if (context == null) {
+            Log.w(context, "Context is null...");
+            return false;
+        }
+        return context.getResources().getBoolean(
+                R.bool.config_enable_modify_call_preview);
+    }
+
+    /**
      * Returns user options for accepting an incoming video call based on Qti extension flag
      */
     public static int getIncomingCallAnswerOptions(Context context, int videoState,
diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
index 9504be1..8c09ff3 100644
--- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java
+++ b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
@@ -876,7 +876,7 @@
      * @param sessionModificationState The new session modification state.
      */
     @Override
-    public void onSessionModificationStateChange(int sessionModificationState) {
+    public void onSessionModificationStateChange(Call call, int sessionModificationState) {
         if (sessionModificationState == Call.SessionModificationState.NO_REQUEST) {
             if (mCallId != null) {
                 CallList.getInstance().removeCallUpdateListener(mCallId, this);
diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
index 28f5557..eab6ca2 100644
--- a/InCallUI/src/com/android/incallui/VideoCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/VideoCallPresenter.java
@@ -71,7 +71,8 @@
 public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi> implements
         IncomingCallListener, InCallOrientationListener, InCallStateListener,
         InCallDetailsListener, SurfaceChangeListener, VideoEventListener,
-        InCallPresenter.InCallEventListener, InCallUiStateNotifierListener {
+        InCallPresenter.InCallEventListener, InCallUiStateNotifierListener,
+        CallList.CallUpdateListener {
     public static final String TAG = "VideoCallPresenter";
 
     public static final boolean DEBUG = false;
@@ -291,6 +292,9 @@
         InCallVideoCallCallbackNotifier.getInstance().removeSurfaceChangeListener(this);
         InCallVideoCallCallbackNotifier.getInstance().removeVideoEventListener(this);
         InCallUiStateNotifier.getInstance().removeListener(this);
+        if(mPrimaryCall != null) {
+            CallList.getInstance().removeCallUpdateListener(mPrimaryCall.getId(), this);
+        }
     }
 
     /**
@@ -526,8 +530,8 @@
     }
 
     private void checkForVideoStateChange(Call call) {
-        final boolean isVideoCall = VideoUtils.isVideoCall(call);
-        final boolean hasVideoStateChanged = mCurrentVideoState != call.getVideoState();
+        boolean isVideoCall = VideoUtils.isVideoCall(call);
+        boolean hasVideoStateChanged = mCurrentVideoState != call.getVideoState();
 
         Log.d(this, "checkForVideoStateChange: isVideoCall= " + isVideoCall
                 + " hasVideoStateChanged=" + hasVideoStateChanged + " isVideoMode="
@@ -535,6 +539,11 @@
                 VideoProfile.videoStateToString(mCurrentVideoState) + " newVideoState: "
                 + VideoProfile.videoStateToString(call.getVideoState()));
 
+        if (isModifyCallPreview(mContext, call)) {
+            isVideoCall |= VideoUtils.isVideoCall(call.getRequestedVideoState());
+            hasVideoStateChanged |= mCurrentVideoState != call.getRequestedVideoState();
+         }
+
         if (!hasVideoStateChanged) {
             return;
         }
@@ -593,6 +602,7 @@
         Log.d(this, "onPrimaryCallChanged: isVideoCall=" + isVideoCall + " isVideoMode="
                 + isVideoMode);
 
+        listenToCallUpdates(newPrimaryCall);
         if (!isVideoCall && isVideoMode) {
             // Terminate video mode if new primary call is not a video call
             // and we are currently in video mode.
@@ -732,6 +742,11 @@
             Log.e(this, "Error VideoCallUi is null so returning");
             return;
         }
+        if (isModifyCallPreview(mContext, call)) {
+           Log.d(this, "modifying video state = " + newVideoState +
+                " to video state: " + call.getRequestedVideoState());
+           newVideoState = call.getRequestedVideoState();
+        }
 
         showVideoUi(newVideoState, call.getState(), call.isConferenceCall());
 
@@ -1215,7 +1230,7 @@
         return ((audioRoute & audioRouteMask) != 0);
     }
 
-    private static void updateCameraSelection(Call call) {
+    private void updateCameraSelection(Call call) {
         Log.d(TAG, "updateCameraSelection: call=" + call);
         Log.d(TAG, "updateCameraSelection: call=" + toSimpleString(call));
 
@@ -1230,6 +1245,12 @@
                     + " Setting camera direction to default value (CAMERA_DIRECTION_UNKNOWN)");
         }
 
+        // for preview scenario if it is supported
+        else if(isModifyCallPreview(mContext, call)) {
+            cameraDir = toCameraDirection(call.getRequestedVideoState());
+            call.getVideoSettings().setCameraDir(cameraDir);
+        }
+
         // Clear camera direction if this is not a video call.
         else if (VideoUtils.isAudioCall(call)) {
             cameraDir = Call.VideoSettings.CAMERA_DIRECTION_UNKNOWN;
@@ -1408,4 +1429,69 @@
         void setPreviewRotation(int orientation);
         void showOutgoingVideoView(boolean show);
     }
+
+    /**
+     * Returns true if camera preview shall be shown till remote user react on the request.
+     */
+    private static boolean isModifyCallPreview(Context ctx, Call call) {
+        if (call == null || !QtiCallUtils.shallShowPreviewWhileWaiting(ctx)) {
+            return false;
+        }
+        return (call.getSessionModificationState() ==
+                Call.SessionModificationState.WAITING_FOR_RESPONSE) &&
+                VideoProfile.isTransmissionEnabled(call.getRequestedVideoState());
+    }
+
+    private void listenToCallUpdates(Call call) {
+        if (!QtiCallUtils.shallShowPreviewWhileWaiting(mContext)) {
+            return;
+        }
+
+        if (mPrimaryCall != null) {
+            CallList.getInstance().removeCallUpdateListener(mPrimaryCall.getId(), this);
+        }
+
+        if (call != null) {
+            CallList.getInstance().addCallUpdateListener(call.getId(), this);
+        }
+    }
+
+    @Override
+    public void onSessionModificationStateChange(Call call, int sessionModificationState) {
+        Log.d(this, "onSessionModificationStateChange : sessionModificationState = " +
+                sessionModificationState + " call:" + call);
+        if (call != mPrimaryCall ||
+                (sessionModificationState == Call.SessionModificationState.NO_REQUEST)) {
+            return;
+        }
+        if (!VideoProfile.isTransmissionEnabled(call.getRequestedVideoState())) {
+           call.setRequestedVideoState(VideoProfile.STATE_AUDIO_ONLY);
+           return;
+        }
+
+        if (sessionModificationState != Call.SessionModificationState.WAITING_FOR_RESPONSE) {
+            call.setRequestedVideoState(VideoProfile.STATE_AUDIO_ONLY);
+        }
+
+        checkForVideoStateChange(call);
+
+        if (sessionModificationState == Call.SessionModificationState.REQUEST_REJECTED
+                || sessionModificationState == Call.SessionModificationState.REQUEST_FAILED
+                || sessionModificationState ==
+                Call.SessionModificationState.UPGRADE_TO_VIDEO_REQUEST_TIMED_OUT) {
+             mCurrentVideoState = call.getVideoState();
+        }
+    }
+
+    @Override
+    public void onLastForwardedNumberChange() {
+    }
+
+    @Override
+    public void onCallChanged(Call call) {
+    }
+
+    @Override
+    public void onChildNumberChange() {
+    }
 }