Merge a3736fc1113688f44b4c55ed4ce2b076d380bfb4 on remote branch

Change-Id: I9132a9b38ee63c05a0fb55c1fc7417d6e830c150
diff --git a/InCallUI/res/values/qtistrings.xml b/InCallUI/res/values/qtistrings.xml
index 18873cc..9ef2bd8 100644
--- a/InCallUI/res/values/qtistrings.xml
+++ b/InCallUI/res/values/qtistrings.xml
@@ -143,6 +143,8 @@
     <string name="session_modify_cause_downgrade_lipsync">Call downgraded due to lipsync</string>
     <!-- Session modify cause code downgrade generic error -->
     <string name="session_modify_cause_downgrade_generic_error">Call downgraded due to generic error</string>
+    <!-- Session modify cause code downgrade generic -->
+    <string name="session_modify_cause_downgrade_generic">Video call changed to voice call</string>
 
     <!-- In-call screen: status label for an incoming conference call [CHAR LIMIT=25] -->
     <string name="card_title_incoming_conf_call">Incoming conference call</string>
diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java
index feaf5ee..c8906ed 100644
--- a/InCallUI/src/com/android/incallui/Call.java
+++ b/InCallUI/src/com/android/incallui/Call.java
@@ -395,7 +395,7 @@
     private int mRequestedVideoState = VideoProfile.STATE_AUDIO_ONLY;
 
     private InCallVideoCallCallback mVideoCallCallback;
-    private boolean mIsVideoCallCallbackRegistered;
+    private VideoCall mRegisteredVideoCall;
     private String mChildNumber;
     private String mLastForwardedNumber;
     private String mCallSubject;
@@ -489,7 +489,7 @@
                 mVideoCallCallback = new InCallVideoCallCallback(this);
             }
             mTelecomCall.getVideoCall().registerCallback(mVideoCallCallback);
-            mIsVideoCallCallbackRegistered = true;
+            mRegisteredVideoCall = mTelecomCall.getVideoCall();
         }
 
         mChildCallIds.clear();
@@ -845,7 +845,7 @@
      *      callback on the {@link VideoCall}.
      */
     public VideoCall getVideoCall() {
-        return mTelecomCall == null || !mIsVideoCallCallbackRegistered ? null
+        return mTelecomCall == null || (mRegisteredVideoCall != mTelecomCall.getVideoCall()) ? null
                 : mTelecomCall.getVideoCall();
     }
 
diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
index de49fff..91a8e0b 100644
--- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
@@ -355,9 +355,11 @@
         int currUnpausedVideoState = VideoUtils.getUnPausedVideoState(currVideoState);
         currUnpausedVideoState |= VideoProfile.STATE_BIDIRECTIONAL;
 
-        VideoProfile videoProfile = new VideoProfile(currUnpausedVideoState);
-        videoCall.sendSessionModifyRequest(videoProfile);
-        mCall.setSessionModificationState(Call.SessionModificationState.WAITING_FOR_RESPONSE);
+        if (!InCallLowBatteryListener.getInstance().onChangeToVideoCall(mCall)) {
+            VideoProfile videoProfile = new VideoProfile(currUnpausedVideoState);
+            videoCall.sendSessionModifyRequest(videoProfile);
+            mCall.setSessionModificationState(Call.SessionModificationState.WAITING_FOR_RESPONSE);
+        }
 
         if (QtiCallUtils.useCustomVideoUi(context)) {
             InCallAudioManager.getInstance().onModifyCallClicked(mCall,
diff --git a/InCallUI/src/com/android/incallui/InCallLowBatteryListener.java b/InCallUI/src/com/android/incallui/InCallLowBatteryListener.java
index c413b07..d835616 100644
--- a/InCallUI/src/com/android/incallui/InCallLowBatteryListener.java
+++ b/InCallUI/src/com/android/incallui/InCallLowBatteryListener.java
@@ -38,6 +38,7 @@
 import android.content.DialogInterface.OnDismissListener;
 import android.content.DialogInterface.OnKeyListener;
 import android.os.Bundle;
+import android.telecom.InCallService.VideoCall;
 import android.telecom.VideoProfile;
 import android.view.KeyEvent;
 import android.view.WindowManager;
@@ -73,7 +74,7 @@
  * signalling that low battery indication for the call can be processed now.
  */
 public class InCallLowBatteryListener implements CallList.Listener, InCallDetailsListener,
-        InCallUiListener {
+        InCallUiListener, CallList.CallUpdateListener {
 
     private static InCallLowBatteryListener sInCallLowBatteryListener;
     private PrimaryCallTracker mPrimaryCallTracker;
@@ -168,6 +169,11 @@
             return;
         }
 
+        /* Clean up callUpdateListener in case call is terminated during MT upgrade
+           request is in progress. */
+        if (isIncomingUpgradeReq(call.getSessionModificationState())) {
+            CallList.getInstance().removeCallUpdateListener(call.getId(), this);
+        }
         mLowBatteryMap.remove(call);
     }
 
@@ -206,10 +212,108 @@
             return;
         }
 
+        /* There can be chances to miss displaying low battery dialog when user tries to
+         * accept incoming VT upgrade request from HUN due to absence of InCallActivity.
+         * In such cases, show low battery dialog when InCallActivity is visible
+         */
         maybeProcessLowBatteryIndication(call);
     }
 
     /**
+     * This method overrides onCallChanged method of {@interface CallList.CallUpdateListener}
+     * Added for completeness. No implementation yet.
+     */
+     @Override
+     public void onCallChanged(Call call) {
+     }
+
+    /**
+     * This method overrides onLastForwardedNumberChange method of
+     * {@interface CallList.CallUpdateListener}. Added for completeness.
+     *  No implementation yet.
+     */
+     @Override
+     public void onLastForwardedNumberChange() {
+     }
+
+    /**
+     * This method overrides onChildNumberChange method of {@interface CallList.CallUpdateListener}
+     * Added for completeness. No implementation yet.
+     */
+     @Override
+     public void onChildNumberChange() {
+     }
+
+    /**
+     * This method overrides onSessionModificationStateChange method of
+     * {@interface CallList.CallUpdateListener}
+     * @param call The call object for which session modify change occurred
+     * @param sessionModificationState contains the session modification state change
+     */
+     @Override
+     public void onSessionModificationStateChange(Call call, int sessionModificationState) {
+         Log.d(this, "onSessionModificationStateChange call = " + call);
+
+         if (call == null) {
+             return;
+         }
+
+         if (!isIncomingUpgradeReq(sessionModificationState)) {
+             Log.d(this, "onSessionModificationStateChange removing call update listener");
+             CallList.getInstance().removeCallUpdateListener(call.getId(), this);
+             /*
+              * Dismiss low battery dialog (if any) for eg. when incoming upgrade request
+              * times-out possibly because there is no user input on low battery dialog or
+              * when user dismisses the MT upgrade request from HUN with low battery dialog
+              * showing etc.
+              */
+             dismissPendingDialogs();
+         }
+     }
+
+     private boolean isIncomingUpgradeReq(int sessionModificationState) {
+         return (sessionModificationState ==
+                 Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST);
+     }
+
+    /**
+     * When there is user action to modify call as Video call (for eg click on upgrade
+     * button or accepting incoming upgrade request as video), this API checks to see
+     * if UE is under low battery or not and accordingly processes the callType change
+     * to video and returns TRUE if the callType change is handled by this API else FALSE
+     *
+     * @param call The call that is undergoing a change to video call
+     */
+    public boolean onChangeToVideoCall(Call call) {
+        Log.d(this, "onChangeToVideoCall call = " + call);
+        if (call == null || !mPrimaryCallTracker.isPrimaryCall(call)) {
+            return false;
+        }
+
+        if (!isLowBattery(call.getTelecomCall().getDetails())) {
+           // Do not process if the call is changing to Video when UE is NOT under low battery
+           return false;
+        }
+
+        /* If user tries to change to Video call again, then remove the call from
+         * from lowbatterymap to ensure that the dialog will be shown again
+         */
+        if (mLowBatteryMap.replace(call, PROCESS_LOW_BATTERY) == null) {
+            Log.d(this, "this call is not present in the lowbatterymap. add it.");
+            mLowBatteryMap.put(call, PROCESS_LOW_BATTERY);
+        }
+
+        /* Listen to call updates only when there is a incoming upgrade request so that
+           low battery dialog can be dismissed if MT upgrade request times out */
+        if (isIncomingUpgradeReq(call.getSessionModificationState())) {
+            CallList.getInstance().addCallUpdateListener(call.getId(), this);
+        }
+
+        maybeProcessLowBatteryIndication(call);
+        return true;
+    }
+
+    /**
      * When call is answered, this API checks to see if UE is under low battery or not
      * and accordingly processes the low battery video call and returns TRUE if
      * user action to answer the call is handled by this API else FALSE.
@@ -360,10 +464,6 @@
     }
 
     private void maybeProcessLowBatteryIndication(Call call) {
-        if (!isLowBatteryVideoCall(call)) {
-            return;
-        }
-
         if (canProcessLowBatteryIndication(call)) {
             displayLowBatteryAlert(call);
             //mark against the call that the respective low battery indication is processed
@@ -477,6 +577,68 @@
                     }
                 });
             }
+        } else if (isIncomingUpgradeReq(call.getSessionModificationState())) {
+            // Incoming upgrade request handling
+            alertDialog.setPositiveButton(R.string.low_battery_convert, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    Log.d(this, "displayLowBatteryAlert decline upgrade request");
+                    CallList.getInstance().removeCallUpdateListener(call.getId(),
+                            InCallLowBatteryListener.this);
+                    InCallPresenter.getInstance().declineUpgradeRequest();
+                }
+            });
+
+            alertDialog.setMessage(R.string.low_battery_msg);
+            alertDialog.setNegativeButton(R.string.low_battery_yes, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    Log.d(this, "displayLowBatteryAlert accept upgrade request as Video Call");
+                    /* Control reached here means upgrade req can be accepted only as
+                       bidirectional video call */
+                    VideoProfile videoProfile = new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL);
+                    call.getVideoCall().sendSessionModifyResponse(videoProfile);
+                    call.setSessionModificationState(Call.SessionModificationState.NO_REQUEST);
+                    InCallAudioManager.getInstance().onAcceptUpgradeRequest(call,
+                            VideoProfile.STATE_BIDIRECTIONAL);
+                }
+            });
+        } else {
+            // Outgoing upgrade request handling
+            alertDialog.setPositiveButton(R.string.low_battery_convert, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    Log.d(this, "displayLowBatteryAlert change to Voice Call");
+
+                    // Change the audio route to earpiece
+                    InCallAudioManager.getInstance().onModifyCallClicked(call,
+                            VideoProfile.STATE_AUDIO_ONLY);
+                }
+            });
+
+            alertDialog.setMessage(R.string.low_battery_msg);
+            alertDialog.setNegativeButton(R.string.low_battery_yes, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    Log.d(this, "displayLowBatteryAlert change to Video Call");
+
+                    VideoCall videoCall = call.getVideoCall();
+                    if (videoCall == null) {
+                        Log.w(this, "displayLowBatteryAlert videocall is null");
+                        return;
+                    }
+
+                    int currUnpausedVideoState = VideoUtils.getUnPausedVideoState(
+                            call.getVideoState());
+                    // Send bidirectional modify request
+                    currUnpausedVideoState |= VideoProfile.STATE_BIDIRECTIONAL;
+
+                    VideoProfile videoProfile = new VideoProfile(currUnpausedVideoState);
+                    videoCall.sendSessionModifyRequest(videoProfile);
+                    call.setSessionModificationState(
+                            Call.SessionModificationState.WAITING_FOR_RESPONSE);
+                }
+            });
         }
 
         mAlert = alertDialog.create();
diff --git a/InCallUI/src/com/android/incallui/InCallMessageController.java b/InCallUI/src/com/android/incallui/InCallMessageController.java
index aa5a57e..d7b7614 100644
--- a/InCallUI/src/com/android/incallui/InCallMessageController.java
+++ b/InCallUI/src/com/android/incallui/InCallMessageController.java
@@ -366,8 +366,14 @@
             return;
         }
 
-        QtiCallUtils.displayToast(mContext,
-                getSessionModificationCauseResourceId(sessionModificationCause));
+        if (sessionModificationCause ==
+                    QtiCallConstants.CAUSE_CODE_SESSION_MODIFY_DOWNGRADE_GENERIC) {
+            QtiCallUtils.displayLongToast(mContext,
+                    getSessionModificationCauseResourceId(sessionModificationCause));
+        } else {
+            QtiCallUtils.displayToast(mContext,
+                    getSessionModificationCauseResourceId(sessionModificationCause));
+        }
     }
 
     /**
@@ -398,6 +404,8 @@
                 return R.string.session_modify_cause_downgrade_thermal_mitigation;
             case QtiCallConstants.CAUSE_CODE_SESSION_MODIFY_DOWNGRADE_LIPSYNC:
                 return R.string.session_modify_cause_downgrade_lipsync;
+            case QtiCallConstants.CAUSE_CODE_SESSION_MODIFY_DOWNGRADE_GENERIC:
+                return R.string.session_modify_cause_downgrade_generic;
             case QtiCallConstants.CAUSE_CODE_SESSION_MODIFY_DOWNGRADE_GENERIC_ERROR:
             default:
                 return R.string.session_modify_cause_downgrade_generic_error;
diff --git a/InCallUI/src/com/android/incallui/InCallOrientationEventListener.java b/InCallUI/src/com/android/incallui/InCallOrientationEventListener.java
index ed10b73..1069189 100644
--- a/InCallUI/src/com/android/incallui/InCallOrientationEventListener.java
+++ b/InCallUI/src/com/android/incallui/InCallOrientationEventListener.java
@@ -108,6 +108,12 @@
             return;
         }
 
+        // Start with current UI orientation.
+        sCurrentOrientation = getCurrentUiOrientation();
+        if (sCurrentOrientation == SCREEN_ORIENTATION_UNKNOWN) {
+            sCurrentOrientation = SCREEN_ORIENTATION_0;
+        }
+
         super.enable();
         mEnabled = true;
         if (notify) {
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index 2a1ecab..fa8ddb5 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -1058,7 +1058,7 @@
         }
 
         Call call = mCallList.getVideoUpgradeRequestCall();
-        if (call != null) {
+        if (call != null && !InCallLowBatteryListener.getInstance().onChangeToVideoCall(call)) {
             VideoProfile videoProfile = new VideoProfile(videoState);
             call.getVideoCall().sendSessionModifyResponse(videoProfile);
             call.setSessionModificationState(Call.SessionModificationState.NO_REQUEST);
diff --git a/InCallUI/src/com/android/incallui/InCallServiceImpl.java b/InCallUI/src/com/android/incallui/InCallServiceImpl.java
index 8f011e3..54bd571 100644
--- a/InCallUI/src/com/android/incallui/InCallServiceImpl.java
+++ b/InCallUI/src/com/android/incallui/InCallServiceImpl.java
@@ -90,6 +90,7 @@
 
         InCallPresenter.getInstance().onServiceUnbind();
         tearDown();
+        StatusBarNotifier.clearAllCallNotifications(getApplicationContext());
 
         return false;
     }
diff --git a/InCallUI/src/com/android/incallui/NotificationBroadcastReceiver.java b/InCallUI/src/com/android/incallui/NotificationBroadcastReceiver.java
index 94a852b..08389ef 100644
--- a/InCallUI/src/com/android/incallui/NotificationBroadcastReceiver.java
+++ b/InCallUI/src/com/android/incallui/NotificationBroadcastReceiver.java
@@ -69,6 +69,7 @@
             InCallPresenter.getInstance().hangUpOngoingCall(context);
         } else if (action.equals(ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST)) {
             InCallPresenter.getInstance().acceptUpgradeRequest(context);
+            InCallPresenter.getInstance().bringToForeground(false);
         } else if (action.equals(ACTION_DECLINE_VIDEO_UPGRADE_REQUEST)) {
             InCallPresenter.getInstance().declineUpgradeRequest(context);
         } else if (action.equals(ACTION_PULL_EXTERNAL_CALL)) {
diff --git a/InCallUI/src/com/android/incallui/QtiCallUtils.java b/InCallUI/src/com/android/incallui/QtiCallUtils.java
index 395fdfe..faf518c 100644
--- a/InCallUI/src/com/android/incallui/QtiCallUtils.java
+++ b/InCallUI/src/com/android/incallui/QtiCallUtils.java
@@ -164,6 +164,20 @@
     }
 
     /**
+     * Displays the message as a long Toast on the UI
+     */
+    public static void displayLongToast(Context context, String msg) {
+        Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
+    }
+
+    /**
+     * Displays the string corresponding to the resourceId as a long Toast on the UI
+     */
+    public static void displayLongToast(Context context, int resourceId) {
+        displayLongToast(context, context.getResources().getString(resourceId));
+    }
+
+    /**
      * The function is called when Modify Call button gets pressed. The function creates and
      * displays modify call options.
      */