Merge "Bring up dialog when an account is not set for the phone call" into lmp-dev
diff --git a/InCallUI/res/layout/select_account_list_item.xml b/InCallUI/res/layout/select_account_list_item.xml
new file mode 100644
index 0000000..0b24c9b
--- /dev/null
+++ b/InCallUI/res/layout/select_account_list_item.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Layout of a single item in the InCallUI Account Chooser Dialog. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="4dp" >
+
+    <ImageView android:id="@+id/icon"
+               android:layout_width="48dp"
+               android:layout_height="48dp"
+               android:scaleType="center" />
+
+    <TextView android:id="@+id/text"
+              android:textAppearance="?android:attr/textAppearanceMedium"
+              android:gravity="start|center_vertical"
+              android:layout_marginLeft="8dp"
+              android:layout_width="0dp"
+              android:layout_weight="1"
+              android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml
index 19ba8a6..78fe885 100644
--- a/InCallUI/res/values/strings.xml
+++ b/InCallUI/res/values/strings.xml
@@ -537,6 +537,9 @@
     <!-- This can be used in any application wanting to disable the text "Emergency number" -->
     <string name="emergency_call_dialog_number_for_display">Emergency number</string>
 
+    <!-- Title for Select Account Dialog [CHAR LIMIT=30] -->
+    <string name="select_account_dialog_title">Select Account</string>
+
     <!-- The digit to be displayed on the 0 key of the dialpad [CHAR LIMIT=1]-->
     <string name="dialpad_0_number">0</string>
     <!-- The digit to be displayed on the 1 key of the dialpad [CHAR LIMIT=1]-->
diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java
index 6a4ee98..f6c0391 100644
--- a/InCallUI/src/com/android/incallui/Call.java
+++ b/InCallUI/src/com/android/incallui/Call.java
@@ -45,6 +45,7 @@
         public static final int DISCONNECTING = 8;  /* A call is being ended. */
         public static final int DISCONNECTED = 9;   /* State after a call disconnects */
         public static final int CONFERENCED = 10;   /* Call part of a conference call */
+        public static final int PRE_DIAL_WAIT = 11; /* Waiting for user before outgoing call */
 
         public static boolean isConnected(int state) {
             switch(state) {
@@ -89,6 +90,8 @@
                     return "DISCONNECTED";
                 case CONFERENCED:
                     return "CONFERENCED";
+                case PRE_DIAL_WAIT:
+                    return "PRE_DIAL_WAIT";
                 default:
                     return "UNKOWN";
             }
@@ -214,6 +217,8 @@
 
     private static int translateState(int state) {
         switch (state) {
+            case android.telecomm.Call.STATE_PRE_DIAL_WAIT:
+                return Call.State.PRE_DIAL_WAIT;
             case android.telecomm.Call.STATE_DIALING:
             case android.telecomm.Call.STATE_NEW:
                 return Call.State.DIALING;
diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java
index f89d8aa..e4085f6 100644
--- a/InCallUI/src/com/android/incallui/CallList.java
+++ b/InCallUI/src/com/android/incallui/CallList.java
@@ -197,6 +197,13 @@
         return retval;
     }
 
+    /**
+     * A call that is waiting for {@link PhoneAccount} selection
+     */
+    public Call getWaitingForAccountCall() {
+        return getFirstCallWithState(Call.State.PRE_DIAL_WAIT);
+    }
+
     public Call getOutgoingCall() {
         Call call = getFirstCallWithState(Call.State.DIALING);
         if (call == null) {
diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java
index 24e5762..f609d28 100644
--- a/InCallUI/src/com/android/incallui/InCallActivity.java
+++ b/InCallUI/src/com/android/incallui/InCallActivity.java
@@ -192,6 +192,7 @@
     private boolean hasPendingErrorDialog() {
         return mDialog != null;
     }
+
     /**
      * Dismisses the in-call screen.
      *
@@ -245,6 +246,10 @@
         // BACK is also used to exit out of any "special modes" of the
         // in-call UI:
 
+        if (!mCallCardFragment.isVisible()) {
+            return;
+        }
+
         if (mDialpadFragment.isVisible()) {
             mCallButtonFragment.displayDialpad(false /* show */, true /* animate */);
             return;
@@ -256,7 +261,7 @@
         // Always disable the Back key while an incoming call is ringing
         final Call call = CallList.getInstance().getIncomingCall();
         if (call != null) {
-            Log.d(this, "Consume Back press for an inconing call");
+            Log.d(this, "Consume Back press for an incoming call");
             return;
         }
 
@@ -387,6 +392,13 @@
                 mCallCardFragment.animateForNewOutgoingCall();
             }
 
+            if (CallList.getInstance().getWaitingForAccountCall() != null) {
+                mCallCardFragment.setVisible(false);
+                SelectPhoneAccountDialogFragment.show(getFragmentManager());
+            } else {
+                mCallCardFragment.setVisible(true);
+            }
+
             return;
         }
     }
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index 5c6283e..5965a95 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.telecomm.CallCapabilities;
 import android.telecomm.Phone;
+import android.telecomm.PhoneAccount;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
@@ -53,6 +54,7 @@
     private InCallState mInCallState = InCallState.NO_CALLS;
     private ProximitySensor mProximitySensor;
     private boolean mServiceConnected = false;
+    private boolean mAccountSelectionCancelled = false;
 
     private final Phone.Listener mPhoneListener = new Phone.Listener() {
         @Override
@@ -172,6 +174,12 @@
 
         if (doFinish) {
             mInCallActivity.finish();
+
+            if (mAccountSelectionCancelled) {
+                // This finish is a result of account selection cancellation
+                // do not include activity ending transition
+                mInCallActivity.overridePendingTransition(0, 0);
+            }
         }
     }
 
@@ -327,6 +335,8 @@
         }
         if (callList.getIncomingCall() != null) {
             newState = InCallState.INCOMING;
+        } else if (callList.getWaitingForAccountCall() != null) {
+            newState = InCallState.WAITING_FOR_ACCOUNT;
         } else if (callList.getOutgoingCall() != null) {
             newState = InCallState.OUTGOING;
         } else if (callList.getActiveCall() != null ||
@@ -363,6 +373,23 @@
         return mProximitySensor;
     }
 
+    public void handleAccountSelection(PhoneAccount account) {
+        Call call = mCallList.getWaitingForAccountCall();
+        if (call != null) {
+            String callId = call.getId();
+            TelecommAdapter.getInstance().phoneAccountSelected(callId, account);
+        }
+    }
+
+    public void cancelAccountSelection() {
+        mAccountSelectionCancelled = true;
+        Call call = mCallList.getWaitingForAccountCall();
+        if (call != null) {
+            String callId = call.getId();
+            TelecommAdapter.getInstance().disconnectCall(callId);
+        }
+    }
+
     /**
      * Hangs up any active or outgoing calls.
      */
@@ -402,7 +429,7 @@
         Call call = mCallList.getIncomingCall();
         if (call != null) {
             TelecommAdapter.getInstance().answerCall(call.getId());
-            showInCall(false, false/* newOutgoingCall */);
+            showInCall(false, false /* newOutgoingCall */);
         }
     }
 
@@ -431,7 +458,7 @@
     }
 
     /**
-     * Returns true of the activity has been created and is running.
+     * Returns true if the activity has been created and is running.
      * Returns true as long as activity is not destroyed or finishing.  This ensures that we return
      * true even if the activity is paused (not in foreground).
      */
@@ -612,7 +639,7 @@
 
         // A new Incoming call means that the user needs to be notified of the the call (since
         // it wasn't them who initiated it).  We do this through full screen notifications and
-        // happens indirectly through {@link StatusBarListener}.
+        // happens indirectly through {@link StatusBarNotifier}.
         //
         // The process for incoming calls is as follows:
         //
@@ -636,12 +663,16 @@
         // we get an incoming call.
         final boolean startStartupSequence = (InCallState.INCOMING == newState);
 
+        // A dialog to show on top of the InCallUI to select a PhoneAccount
+        final boolean showAccountPicker = (InCallState.WAITING_FOR_ACCOUNT == newState);
+
         // A new outgoing call indicates that the user just now dialed a number and when that
-        // happens we need to display the screen immediateley.
+        // happens we need to display the screen immediately or show an account picker dialog if
+        // no default is set.
         //
         // This is different from the incoming call sequence because we do not need to shock the
         // user with a top-level notification.  Just show the call UI normally.
-        final boolean showCallUi = (InCallState.OUTGOING == newState);
+        final boolean showCallUi = (InCallState.OUTGOING == newState || showAccountPicker);
 
         // TODO: Can we be suddenly in a call without it having been in the outgoing or incoming
         // state?  I havent seen that but if it can happen, the code below should be enabled.
@@ -659,7 +690,7 @@
 
         if (showCallUi) {
             Log.i(this, "Start in call UI");
-            showInCall(false /* showDialpad */, true /* newOutgoingCall */);
+            showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */);
         } else if (startStartupSequence) {
             Log.i(this, "Start Full Screen in call UI");
 
@@ -783,6 +814,9 @@
         // In-call experience is showing
         INCALL,
 
+        // Waiting for user input before placing outgoing call
+        WAITING_FOR_ACCOUNT,
+
         // User is dialing out
         OUTGOING;
 
diff --git a/InCallUI/src/com/android/incallui/SelectPhoneAccountDialogFragment.java b/InCallUI/src/com/android/incallui/SelectPhoneAccountDialogFragment.java
new file mode 100644
index 0000000..eb61bba
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/SelectPhoneAccountDialogFragment.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui;
+
+import com.google.android.collect.Lists;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.telecomm.PhoneAccount;
+import android.telecomm.PhoneAccountMetadata;
+import android.telecomm.TelecommManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import com.android.contacts.common.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Dialog that allows the user to switch between default SIM cards
+ */
+public class SelectPhoneAccountDialogFragment extends DialogFragment {
+    private List<PhoneAccount> mAccounts;
+    private boolean mIsSelected;
+    private TelecommManager mTelecommManager;
+
+    /* Preferred way to show this dialog */
+    public static void show(FragmentManager fragmentManager) {
+        SelectPhoneAccountDialogFragment fragment = new SelectPhoneAccountDialogFragment();
+        fragment.show(fragmentManager, "selectAccount");
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mIsSelected = false;
+        mTelecommManager = TelecommManager.from(getActivity());
+        mAccounts = mTelecommManager.getEnabledPhoneAccounts();
+
+        final DialogInterface.OnClickListener selectionListener =
+                new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                mIsSelected = true;
+                PhoneAccount selectedAccount = mAccounts.get(which);
+                InCallPresenter.getInstance().handleAccountSelection(selectedAccount);
+            }
+        };
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+        ListAdapter selectAccountListAdapter = new SelectAccountListAdapter(
+                builder.getContext(),
+                R.layout.select_account_list_item,
+                mAccounts);
+
+        return builder.setTitle(R.string.select_account_dialog_title)
+                .setAdapter(selectAccountListAdapter, selectionListener)
+                .create();
+    }
+
+    private class SelectAccountListAdapter extends ArrayAdapter<PhoneAccount> {
+        private Context mContext;
+        private int mResId;
+
+        public SelectAccountListAdapter(Context context, int resource, List<PhoneAccount> objects) {
+            super(context, resource, objects);
+            mContext = context;
+            mResId = resource;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            LayoutInflater inflater = (LayoutInflater)
+                    mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+            View rowView;
+            final ViewHolder holder;
+
+            if (convertView == null) {
+                // Cache views for faster scrolling
+                rowView = inflater.inflate(mResId, null);
+                holder = new ViewHolder();
+                holder.textView = (TextView) rowView.findViewById(R.id.text);
+                holder.imageView = (ImageView) rowView.findViewById(R.id.icon);
+                rowView.setTag(holder);
+            }
+            else {
+                rowView = convertView;
+                holder = (ViewHolder) rowView.getTag();
+            }
+
+            PhoneAccount item = getItem(position);
+            PhoneAccountMetadata itemMetadata = mTelecommManager.getPhoneAccountMetadata(item);
+            holder.textView.setText(itemMetadata.getLabel());
+            holder.imageView.setImageDrawable(itemMetadata.getIcon(mContext));
+            return rowView;
+        }
+
+        private class ViewHolder {
+            TextView textView;
+            ImageView imageView;
+        }
+    }
+
+    @Override
+    public void onPause() {
+        if (!mIsSelected) {
+            InCallPresenter.getInstance().cancelAccountSelection();
+        }
+        super.onPause();
+    }
+}
\ No newline at end of file
diff --git a/InCallUI/src/com/android/incallui/TelecommAdapter.java b/InCallUI/src/com/android/incallui/TelecommAdapter.java
index 6d0e0a6..745931c 100644
--- a/InCallUI/src/com/android/incallui/TelecommAdapter.java
+++ b/InCallUI/src/com/android/incallui/TelecommAdapter.java
@@ -22,6 +22,7 @@
 import android.os.Looper;
 import android.telecomm.InCallAdapter;
 import android.telecomm.Phone;
+import android.telecomm.PhoneAccount;
 
 import com.google.common.base.Preconditions;
 
@@ -194,4 +195,12 @@
             Log.e(this, "error phoneAccountClicked, mPhone is null");
         }
     }
+
+    void phoneAccountSelected(String callId, PhoneAccount account) {
+        if (mPhone != null) {
+            getTelecommCallById(callId).phoneAccountSelected(account);
+        }  else {
+            Log.e(this, "error phoneAccountSelected, mAdapter is null");
+        }
+    }
 }