From e067a78c4c0817e9e81c41327460aedce7f1091d Mon Sep 17 00:00:00 2001 From: Santos Cordon Date: Thu, 8 Aug 2013 02:07:10 -0700 Subject: Improve outgoing call sequence Changes: - When we get a new outgoing call, fire up the UI (without the notification) by sending it an ACTION_MAIN intent. - Fix up the InCallState-setting code in InCallPresenter to be a little cleaner and accomodate new OUTGOING code. - Add missing call to set HOLD Ui button - Fix an occassional NullPointerException in CallCardPresenter.java Change-Id: I557a777287d9ab25ef1447be63b5da080f1b2532 (cherry picked from commit 4d5c29af103c13e78568dc772d26eb56a3e6d3e1) --- .../com/android/incallui/CallButtonPresenter.java | 2 + .../com/android/incallui/CallCardPresenter.java | 10 +- .../src/com/android/incallui/InCallActivity.java | 42 +++++++- .../src/com/android/incallui/InCallPresenter.java | 110 ++++++++++++++++++--- 4 files changed, 143 insertions(+), 21 deletions(-) (limited to 'InCallUI') diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java index 7b6649704..a307009f9 100644 --- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java +++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java @@ -182,6 +182,8 @@ public class CallButtonPresenter extends Presenter i Logger.d(this, "Primary call: " + primary); Logger.d(this, "Secondary call: " + secondary); - // Set primary call data - final CallerInfo primaryCallInfo = CallerInfoUtils.getCallerInfoForCall(mContext, primary, - null, this); - updateDisplayByCallerInfo(primary, primaryCallInfo, primary.getNumberPresentation(), true); if (primary != null) { + // Set primary call data + final CallerInfo primaryCallInfo = CallerInfoUtils.getCallerInfoForCall(mContext, + primary, null, this); + updateDisplayByCallerInfo(primary, primaryCallInfo, primary.getNumberPresentation(), + true); + ui.setNumber(primary.getNumber()); ui.setCallState(primary.getState(), primary.getDisconnectCause()); } else { diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java index 28e02b3b3..8ff43d5a1 100644 --- a/InCallUI/src/com/android/incallui/InCallActivity.java +++ b/InCallUI/src/com/android/incallui/InCallActivity.java @@ -129,7 +129,7 @@ public class InCallActivity extends Activity { // we can count on our onResume() method being called next. // Just like in onCreate(), handle the intent. - //TODO(klp): handle intent + internalResolveIntent(intent); } @Override @@ -199,6 +199,46 @@ public class InCallActivity extends Activity { return super.onKeyDown(keyCode, event); } + private void internalResolveIntent(Intent intent) { + final String action = intent.getAction(); + + if (action.equals(intent.ACTION_MAIN)) { + // This action is the normal way to bring up the in-call UI. + // + // But we do check here for one extra that can come along with the + // ACTION_MAIN intent: + + // TODO(klp): Enable this for klp + /* + if (intent.hasExtra(SHOW_DIALPAD_EXTRA)) { + // SHOW_DIALPAD_EXTRA can be used here to specify whether the DTMF + // dialpad should be initially visible. If the extra isn't + // present at all, we just leave the dialpad in its previous state. + + boolean showDialpad = intent.getBooleanExtra(SHOW_DIALPAD_EXTRA, false); + if (VDBG) log("- internalResolveIntent: SHOW_DIALPAD_EXTRA: " + showDialpad); + + // If SHOW_DIALPAD_EXTRA is specified, that overrides whatever + // the previous state of inCallUiState.showDialpad was. + mApp.inCallUiState.showDialpad = showDialpad; + + final boolean hasActiveCall = mCM.hasActiveFgCall(); + final boolean hasHoldingCall = mCM.hasActiveBgCall(); + + // There's only one line in use, AND it's on hold, at which we're sure the user + // wants to use the dialpad toward the exact line, so un-hold the holding line. + if (showDialpad && !hasActiveCall && hasHoldingCall) { + PhoneUtils.switchHoldingAndActive(mCM.getFirstActiveBgCall()); + } + } + */ + // ...and in onResume() we'll update the onscreen dialpad state to + // match the InCallUiState. + + return; + } + } + private void initializeInCall() { // TODO(klp): Make sure that this doesn't need to move back to onResume() since they are // statically added fragments. diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java index 63f0aa524..83d520c59 100644 --- a/InCallUI/src/com/android/incallui/InCallPresenter.java +++ b/InCallUI/src/com/android/incallui/InCallPresenter.java @@ -41,6 +41,7 @@ public class InCallPresenter implements CallList.Listener { private final StatusBarNotifier mStatusBarNotifier; private final Set mListeners = Sets.newHashSet(); + private final Context mContext; private InCallState mInCallState = InCallState.HIDDEN; private InCallActivity mInCallActivity; @@ -76,6 +77,10 @@ public class InCallPresenter implements CallList.Listener { @Override public void onCallListChange(CallList callList) { // fast fail if we are still starting up + // TODO(klp): If the Activity crashes unexpectedly during start-up, we may never + // get out of STARTING_UP state and thus never attempt to recreate the activity a + // subsequent time. Test to see if this is the case and add a timeout for + // STARTING_UP phase. if (mInCallState == InCallState.STARTING_UP) { Logger.d(this, "Already on STARTING_UP, ignoring until ready"); return; @@ -133,35 +138,108 @@ public class InCallPresenter implements CallList.Listener { // TODO(klp): Consider a proper state machine implementation - // if we need to show something, we need to start the Ui... - if (!newState.isHidden()) { + // If the state isn't changing, we have already done any starting/stopping of + // activities in a previous pass...so lets cut out early + if (newState == mInCallState) { + return newState; + } - // When we attempt to go to any state from HIDDEN, it means that we need to create the - // entire UI. However, the StatusBarNotifier is in charge of starting up the Ui because - // it has special behavior in case we have to deal with an immersive foreground app. - // We set the STARTING_UP state to let StatusBarNotifier know it needs to start the - // the Ui. - if (mInCallState.isHidden()) { - return InCallState.STARTING_UP; + // 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}. + // + // The process for incoming calls is as follows: + // + // 1) CallList - Announces existence of new INCOMING call + // 2) InCallPresenter - Gets announcement and calculates that the new InCallState + // - should be set to INCOMING. + // 3) InCallPresenter - This method is called to see if we need to start or finish + // the app given the new state. Because the previous state was + // not INCOMING (and you can't have two incoming calls at once), + // we start the start-up sequence by setting + // InCallState = STARTING_UP (this is the code that you see + // below). During the STARTING_UP phase, InCallPresenter will + // ignore all new call changes that come in. + // 4) StatusBarNotifier - Listens to InCallState changes. When it sees STARTING_UP, it + // will issue a FullScreen Notification that will either start + // the InCallActivity or show the user a top-level notification + // dialog if the user is in an immersive app. That notification + // can also start the InCallActivity. + // 5) InCallActivity - Main activity starts up and at the end of its onCreate will + // call InCallPresenter::setActivity() to let the presenter + // know that start-up is complete. + // 6) InCallPresenter - Sets STARTED as the new InCallState and issues a manual update + // of the call list so that it catches any changes that it + // previously ignored during STARTING_UP. That will result + // in a recalculated InCallState and throw us back into this + // method again. + // 7) InCallPresenter - 99% of the time we end up back here with the current + // state at STARTED and newState as INCOMING (again). We do not + // want to do the start-up sequence again if we see that it has + // already STARTED so we just fall through in that case and let + // normal code flow occur (newState <= INCOMING). + // + // [ AND NOW YOU'RE IN THE CALL. voila! ] + // + // Our app is started using a fullScreen notification. We need to do this whenever + // we get an incoming call. + final boolean startStartupSequence = (InCallState.INCOMING == newState && + InCallState.STARTED != mInCallState); + + // A new outgoing call indicates that the user just now dialed a number and when that + // happens we need to display the screen immediateley. + // + // 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); + + Logger.v(this, "showCallUi: ", showCallUi); + Logger.v(this, "startStartupSequence: ", startStartupSequence); + + + if (startStartupSequence) { + return InCallState.STARTING_UP; + } else if (showCallUi) { + showInCall(); + } else if (newState == InCallState.HIDDEN) { + + // The new state is the hidden state (no calls). Tear everything down. + + if (mInCallActivity != null) { + // Null out reference before we start end sequence + InCallActivity temp = mInCallActivity; + mInCallActivity = null; + + temp.finish(); } - - } else if (mInCallActivity != null) { - // Null out reference before we start end sequence - InCallActivity temp = mInCallActivity; - mInCallActivity = null; - - temp.finish(); } return newState; } + private void showInCall() { + Logger.d(this, "Showing in call manually."); + mContext.startActivity(getInCallIntent()); + } + + private Intent getInCallIntent() { + final Intent intent = new Intent(Intent.ACTION_MAIN, null); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_NO_USER_ACTION); + intent.setClass(mContext, InCallActivity.class); + + return intent; + } + /** * Private constructor. Must use getInstance() to get this singleton. */ private InCallPresenter(Context context) { Preconditions.checkNotNull(context); + mContext = context; + mStatusBarNotifier = new StatusBarNotifier(context); addListener(mStatusBarNotifier); -- cgit v1.2.3