From af9eefb9174cdb7a4824fc0a8ed6e85754acd0bd Mon Sep 17 00:00:00 2001 From: Nancy Chen Date: Tue, 8 Jul 2014 18:53:32 -0700 Subject: Bring up dialog when an account is not set for the phone call If an account default is not set, the incall ui will display a dialog to allow the user to select an account for that particular call. Bug: 16243703 Change-Id: Ic97c50d1116dd11ef900c4d20c6439683ed60e06 --- InCallUI/res/layout/select_account_list_item.xml | 36 ++++++ InCallUI/res/values/strings.xml | 3 + InCallUI/src/com/android/incallui/Call.java | 5 + InCallUI/src/com/android/incallui/CallList.java | 7 ++ .../src/com/android/incallui/InCallActivity.java | 14 ++- .../src/com/android/incallui/InCallPresenter.java | 46 ++++++- .../incallui/SelectPhoneAccountDialogFragment.java | 138 +++++++++++++++++++++ .../src/com/android/incallui/TelecommAdapter.java | 9 ++ 8 files changed, 251 insertions(+), 7 deletions(-) create mode 100644 InCallUI/res/layout/select_account_list_item.xml create mode 100644 InCallUI/src/com/android/incallui/SelectPhoneAccountDialogFragment.java 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 000000000..0b24c9b9f --- /dev/null +++ b/InCallUI/res/layout/select_account_list_item.xml @@ -0,0 +1,36 @@ + + + + + + + + + + diff --git a/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml index 19ba8a6c8..78fe885cd 100644 --- a/InCallUI/res/values/strings.xml +++ b/InCallUI/res/values/strings.xml @@ -537,6 +537,9 @@ Emergency number + + Select Account + 0 diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java index 6a4ee985d..f6c039138 100644 --- a/InCallUI/src/com/android/incallui/Call.java +++ b/InCallUI/src/com/android/incallui/Call.java @@ -45,6 +45,7 @@ public final class Call { 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 @@ public final class Call { return "DISCONNECTED"; case CONFERENCED: return "CONFERENCED"; + case PRE_DIAL_WAIT: + return "PRE_DIAL_WAIT"; default: return "UNKOWN"; } @@ -214,6 +217,8 @@ public final class Call { 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 f89d8aafe..e4085f610 100644 --- a/InCallUI/src/com/android/incallui/CallList.java +++ b/InCallUI/src/com/android/incallui/CallList.java @@ -197,6 +197,13 @@ public class CallList implements InCallPhoneListener { 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 24e57625e..f609d28d2 100644 --- a/InCallUI/src/com/android/incallui/InCallActivity.java +++ b/InCallUI/src/com/android/incallui/InCallActivity.java @@ -192,6 +192,7 @@ public class InCallActivity extends Activity { private boolean hasPendingErrorDialog() { return mDialog != null; } + /** * Dismisses the in-call screen. * @@ -245,6 +246,10 @@ public class InCallActivity extends Activity { // 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 @@ public class InCallActivity extends Activity { // 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 @@ public class InCallActivity extends Activity { 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 5c6283ea4..5965a950a 100644 --- a/InCallUI/src/com/android/incallui/InCallPresenter.java +++ b/InCallUI/src/com/android/incallui/InCallPresenter.java @@ -20,6 +20,7 @@ import android.content.Context; 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 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { 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 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { 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 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { } 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 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { 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 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { Call call = mCallList.getIncomingCall(); if (call != null) { TelecommAdapter.getInstance().answerCall(call.getId()); - showInCall(false, false/* newOutgoingCall */); + showInCall(false, false /* newOutgoingCall */); } } @@ -431,7 +458,7 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { } /** - * 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 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { // 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 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { // 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 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { 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 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { // 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 000000000..eb61bba0a --- /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 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 { + private Context mContext; + private int mResId; + + public SelectAccountListAdapter(Context context, int resource, List 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 6d0e0a62d..745931cfe 100644 --- a/InCallUI/src/com/android/incallui/TelecommAdapter.java +++ b/InCallUI/src/com/android/incallui/TelecommAdapter.java @@ -22,6 +22,7 @@ import android.content.Intent; 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 @@ final class TelecommAdapter implements InCallPhoneListener { 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"); + } + } } -- cgit v1.2.3