Merge "Adds support for texting after phone disconnects." into klp-dev
diff --git a/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java
index 29a4586..1b249f2 100644
--- a/InCallUI/src/com/android/incallui/AnswerFragment.java
+++ b/InCallUI/src/com/android/incallui/AnswerFragment.java
@@ -51,6 +51,11 @@
      */
     private Dialog mCannedResponsePopup = null;
 
+    /**
+     * The popup showing a text field for users to type in their custom message.
+     */
+    private AlertDialog mCustomMessagePopup = null;
+
     private ArrayAdapter<String> mTextResponsesAdapter = null;
 
     private GlowPadWrapper mGlowpad;
@@ -125,13 +130,27 @@
         mCannedResponsePopup.show();
     }
 
+    private boolean isCannedResponsePopupShowing() {
+        if (mCannedResponsePopup != null) {
+            return mCannedResponsePopup.isShowing();
+        }
+        return false;
+    }
+
+    private boolean isCustomMessagePopupShowing() {
+        if (mCustomMessagePopup != null) {
+            return mCustomMessagePopup.isShowing();
+        }
+        return false;
+    }
+
     /**
-     * Dismiss currently visible popups.
+     * Dismiss the canned response list popup.
      *
      * This is safe to call even if the popup is already dismissed, and even if you never called
      * showRespondViaSmsPopup() in the first place.
      */
-    private void dismissPopup() {
+    private void dismissCannedResponsePopup() {
         if (mCannedResponsePopup != null) {
             mCannedResponsePopup.dismiss();  // safe even if already dismissed
             mCannedResponsePopup = null;
@@ -139,6 +158,30 @@
     }
 
     /**
+     * Dismiss the custom compose message popup.
+     */
+    private void dismissCustomMessagePopup() {
+       if (mCustomMessagePopup != null) {
+           mCustomMessagePopup.dismiss();
+           mCustomMessagePopup = null;
+       }
+    }
+
+    public void dismissPendingDialogues() {
+        if (isCannedResponsePopupShowing()) {
+            dismissCannedResponsePopup();
+        }
+
+        if (isCustomMessagePopupShowing()) {
+            dismissCustomMessagePopup();
+        }
+    }
+
+    public boolean hasPendingDialogs() {
+        return !(mCannedResponsePopup == null && mCustomMessagePopup == null);
+    }
+
+    /**
      * Shows the custom message entry dialog.
      */
     public void showCustomMessageDialog() {
@@ -150,41 +193,49 @@
                         new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
-                        getPresenter().rejectCallWithMessage(et.getText().toString().trim());
+                        // The order is arranged in a way that the popup will be destroyed when the
+                        // InCallActivity is about to finish.
+                        final String textMessage = et.getText().toString().trim();
+                        dismissCustomMessagePopup();
+                        getPresenter().rejectCallWithMessage(textMessage);
                     }
                 })
                 .setNegativeButton(R.string.custom_message_cancel,
                         new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
+                        dismissCustomMessagePopup();
+                        getPresenter().onDismissDialog();
                     }
                 })
                 .setTitle(R.string.respond_via_sms_custom_message);
-        final AlertDialog customResponseDialog = builder.create();
+        mCustomMessagePopup = builder.create();
 
         // Enable/disable the send button based on whether there is a message in the EditText
         et.addTextChangedListener(new TextWatcher() {
             @Override
             public void beforeTextChanged(CharSequence s, int start, int count, int after) {
             }
+
             @Override
             public void onTextChanged(CharSequence s, int start, int before, int count) {
             }
+
             @Override
             public void afterTextChanged(Editable s) {
-                final Button sendButton = customResponseDialog.getButton(
+                final Button sendButton = mCustomMessagePopup.getButton(
                         DialogInterface.BUTTON_POSITIVE);
                 sendButton.setEnabled(s != null && s.toString().trim().length() != 0);
             }
         });
 
         // Keyboard up, show the dialog
-        customResponseDialog.getWindow().setSoftInputMode(
+        mCustomMessagePopup.getWindow().setSoftInputMode(
                 WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
-        customResponseDialog.show();
+        mCustomMessagePopup.show();
 
         // Send button starts out disabled
-        final Button sendButton = customResponseDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+        final Button sendButton = mCustomMessagePopup.getButton(DialogInterface.BUTTON_POSITIVE);
         sendButton.setEnabled(false);
     }
 
@@ -228,7 +279,7 @@
             Log.d(this, "RespondViaSmsItemClickListener.onItemClick(" + position + ")...");
             final String message = (String) parent.getItemAtPosition(position);
             Log.v(this, "- message: '" + message + "'");
-            dismissPopup();
+            dismissCannedResponsePopup();
 
             // The "Custom" choice is a special case.
             // (For now, it's guaranteed to be the last item.)
diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java
index 6d70f81..bfe8405 100644
--- a/InCallUI/src/com/android/incallui/AnswerPresenter.java
+++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java
@@ -29,6 +29,7 @@
     private static final String TAG = AnswerPresenter.class.getSimpleName();
 
     private int mCallId = Call.INVALID_CALL_ID;
+    private Call mCall = null;
 
     @Override
     public void onUiReady(AnswerUi ui) {
@@ -82,6 +83,7 @@
 
     private void processIncomingCall(Call call) {
         mCallId = call.getCallId();
+        mCall = call;
 
         // Listen for call updates for the current call.
         CallList.getInstance().addCallUpdateListener(mCallId, this);
@@ -108,6 +110,9 @@
             CallList.getInstance().removeCallUpdateListener(mCallId, this);
 
             getUi().showAnswerUi(false);
+
+            // mCallId will hold the state of the call. We don't clear the mCall variable here as
+            // it may be useful for sending text messages after phone disconnects.
             mCallId = Call.INVALID_CALL_ID;
         }
     }
@@ -123,13 +128,9 @@
     }
 
     public void onDecline() {
-        if (mCallId == Call.INVALID_CALL_ID) {
-            return;
-        }
-
         Log.d(this, "onDecline " + mCallId);
 
-        CallCommandClient.getInstance().rejectCall(mCallId, false, null);
+        CallCommandClient.getInstance().rejectCall(mCall, false, null);
     }
 
     public void onText() {
@@ -140,7 +141,14 @@
 
     public void rejectCallWithMessage(String message) {
         Log.d(this, "sendTextToDefaultActivity()...");
-        CallCommandClient.getInstance().rejectCall(mCallId, true, message);
+
+        CallCommandClient.getInstance().rejectCall(mCall, true, message);
+
+        onDismissDialog();
+    }
+
+    public void onDismissDialog() {
+        InCallPresenter.getInstance().onDismissDialog();
     }
 
     interface AnswerUi extends Ui {
diff --git a/InCallUI/src/com/android/incallui/CallCommandClient.java b/InCallUI/src/com/android/incallui/CallCommandClient.java
index 3f4ee77..52d2100 100644
--- a/InCallUI/src/com/android/incallui/CallCommandClient.java
+++ b/InCallUI/src/com/android/incallui/CallCommandClient.java
@@ -18,8 +18,10 @@
 
 import android.os.RemoteException;
 
+
 import com.android.services.telephony.common.AudioMode;
 import com.android.services.telephony.common.ICallCommandService;
+import com.android.services.telephony.common.Call;
 
 /**
  * Main interface for phone related commands.
@@ -57,14 +59,15 @@
         }
     }
 
-    public void rejectCall(int callId, boolean rejectWithMessage, String message) {
-        Log.i(this, "rejectCall: " + callId + ", with rejectMessage? " + rejectWithMessage);
+    public void rejectCall(Call call, boolean rejectWithMessage, String message) {
+        Log.i(this, "rejectCall: " + call.getCallId() +
+                ", with rejectMessage? " + rejectWithMessage);
         if (mCommandService == null) {
             Log.e(this, "Cannot reject call; CallCommandService == null");
             return;
         }
         try {
-            mCommandService.rejectCall(callId, rejectWithMessage, message);
+            mCommandService.rejectCall(call, rejectWithMessage, message);
         } catch (RemoteException e) {
             Log.e(this, "Error rejecting call.", e);
         }
diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java
index 32d1f55..ac21d52 100644
--- a/InCallUI/src/com/android/incallui/InCallActivity.java
+++ b/InCallUI/src/com/android/incallui/InCallActivity.java
@@ -138,6 +138,9 @@
         return mIsForegroundActivity;
     }
 
+    private boolean hasPendingErrorDialog() {
+        return mDialog != null;
+    }
     /**
      * Dismisses the in-call screen.
      *
@@ -158,7 +161,7 @@
         Log.i(this, "finish().  Dialog showing: " + (mDialog != null));
 
         // skip finish if we are still showing a dialog.
-        if (mDialog == null) {
+        if (!hasPendingErrorDialog() && !mAnswerFragment.hasPendingDialogs()) {
             super.finish();
         }
     }
@@ -427,6 +430,7 @@
             mDialog.dismiss();
             mDialog = null;
         }
+        mAnswerFragment.dismissPendingDialogues();
     }
 
     /**