From 89ed39f1f460ad84291182fdea39eae1e9d8b666 Mon Sep 17 00:00:00 2001 From: Santos Cordon Date: Wed, 14 Aug 2013 12:39:32 -0700 Subject: Fix NullPointerException in InCallUI with CallTimer. bug: 10325158 Change-Id: Ie7e89c2e1e3038df89387e99de6849ed12203824 --- InCallUI/src/com/android/incallui/CallCardPresenter.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java index 330957e80..60486f454 100644 --- a/InCallUI/src/com/android/incallui/CallCardPresenter.java +++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java @@ -150,13 +150,15 @@ public class CallCardPresenter extends Presenter final CallCardUi ui = getUi(); if (ui == null || mPrimary == null || mPrimary.getState() != Call.State.ACTIVE) { - ui.setPrimaryCallElapsedTime(false, null); + if (ui != null) { + ui.setPrimaryCallElapsedTime(false, null); + } mCallTimer.cancel(); + } else { + final long callStart = mPrimary.getConnectTime(); + final long duration = System.currentTimeMillis() - callStart; + ui.setPrimaryCallElapsedTime(true, DateUtils.formatElapsedTime(duration / 1000)); } - - final long callStart = mPrimary.getConnectTime(); - final long duration = System.currentTimeMillis() - callStart; - ui.setPrimaryCallElapsedTime(true, DateUtils.formatElapsedTime(duration / 1000)); } -- cgit v1.2.3 From 0334afdda39cccbb0488d2d6d32b852923c621d9 Mon Sep 17 00:00:00 2001 From: Santos Cordon Date: Mon, 19 Aug 2013 20:12:16 -0700 Subject: Support connecting and disconnecting from Phone app. Phone app now connects/disconnects from the UI when there are no active calls but UI did not previously support being disconnected. This change adds the following functionality to support dis/reconnection: - CallCommandClient now supports setting new ICallCommandService instances. - CallCommandClient now checks if mCommandService is null before executing a method. - CallHandlerService performs more careful ordered cleanup with destroyed including removing pending messages and clearing any existing calls from the call list. - InCallActivity now performs tearDown of the presenters with onDestroy instead of finish() to reduce NPE instances. - InCallActivity not notifies InCallPresenter when is finishes, and not just when it starts. - InCallPresenter tears itself down after two things happen: the UI is destroyed and the service is disconnected. - InCallPresenter now issues a full-screen restart of the UI if the UI was previously hidden (except for new outgoing calls). This allows the UI to come back to the foreground if it was in the foreground when the app went down. The above changes also now protect against the phone app crashing or the incall UI crashing. bug: 10363682 Change-Id: I9b785f906f29015827e8e53e64cd5f5c72cd7981 --- .../com/android/incallui/CallButtonPresenter.java | 1 - .../com/android/incallui/CallCommandClient.java | 60 ++++++++++++--- .../com/android/incallui/CallHandlerService.java | 39 +++++++++- InCallUI/src/com/android/incallui/CallList.java | 19 +++++ .../src/com/android/incallui/InCallActivity.java | 12 +-- .../src/com/android/incallui/InCallPresenter.java | 90 +++++++++++++++------- 6 files changed, 175 insertions(+), 46 deletions(-) diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java index 3c1ada1fc..12cc65663 100644 --- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java +++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java @@ -54,7 +54,6 @@ public class CallButtonPresenter extends Presenter LARGEST_MSG_ID) { + // If you got here, you may have added a new message and forgotten to + // update LARGEST_MSG_ID + Logger.wtf(this, "Cannot handle message larger than LARGEST_MSG_ID."); + } + Logger.d(this, "executeMessage " + msg.what); switch (msg.what) { diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java index f692bf683..a3cee5f98 100644 --- a/InCallUI/src/com/android/incallui/CallList.java +++ b/InCallUI/src/com/android/incallui/CallList.java @@ -224,6 +224,25 @@ public class CallList { return retval; } + /** + * This is called when the service disconnects, either expectedly or unexpectedly. + * For the expected case, it's because we have no calls left. For the unexpected case, + * it is likely a crash of phone and we need to clean up our calls manually. Without phone, + * there can be no active calls, so this is relatively safe thing to do. + */ + public void clearOnDisconnect() { + for (Call call : mCallMap.values()) { + final int state = call.getState(); + if (state != Call.State.IDLE && + state != Call.State.INVALID && + state != Call.State.DISCONNECTED) { + call.setState(Call.State.DISCONNECTED); + updateCallInMap(call); + } + } + notifyListenersOfChange(); + } + /** * Sends a generic notification to all listeners that something has changed. * It is up to the listeners to call back to determine what changed. diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java index e1a979693..5edfaa32a 100644 --- a/InCallUI/src/com/android/incallui/InCallActivity.java +++ b/InCallUI/src/com/android/incallui/InCallActivity.java @@ -88,6 +88,9 @@ public class InCallActivity extends Activity { @Override protected void onDestroy() { Logger.d(this, "onDestroy()... this = " + this); + + tearDownPresenters(); + super.onDestroy(); } @@ -116,13 +119,7 @@ public class InCallActivity extends Activity { @Override public void finish() { Logger.d(this, "finish()..."); - tearDownPresenters(); - super.finish(); - - // TODO(klp): Actually finish the activity for now. Revisit performance implications of - // this before launch. - // moveTaskToBack(true); } @Override @@ -299,11 +296,14 @@ public class InCallActivity extends Activity { } private void tearDownPresenters() { + Logger.d(this, "Tearing down presenters."); InCallPresenter mainPresenter = InCallPresenter.getInstance(); mainPresenter.removeListener(mCallButtonFragment.getPresenter()); mainPresenter.removeListener(mCallCardFragment.getPresenter()); mainPresenter.removeListener(mAnswerFragment.getPresenter()); + + mainPresenter.setActivity(null); } private void toast(String text) { diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java index d709ba49f..3b400ef7b 100644 --- a/InCallUI/src/com/android/incallui/InCallPresenter.java +++ b/InCallUI/src/com/android/incallui/InCallPresenter.java @@ -47,7 +47,7 @@ public class InCallPresenter implements CallList.Listener { private Context mContext; private CallList mCallList; private InCallActivity mInCallActivity; - + private boolean mServiceConnected = false; private InCallState mInCallState = InCallState.HIDDEN; public static synchronized InCallPresenter getInstance() { @@ -71,34 +71,44 @@ public class InCallPresenter implements CallList.Listener { mAudioModeProvider = audioModeProvider; + // This only gets called by the service so this is okay. + mServiceConnected = true; + Logger.d(this, "Finished InCallPresenter.setUp"); } + /** + * Called when the telephony service has disconnected from us. This will happen when there are + * no more active calls. However, we may still want to continue showing the UI for + * certain cases like showing "Call Ended". + * What we really want is to wait for the activity and the service to both disconnect before we + * tear things down. This method sets a serviceConnected boolean and calls a secondary method + * that performs the aforementioned logic. + */ public void tearDown() { - mAudioModeProvider = null; - - removeListener(mStatusBarNotifier); - mStatusBarNotifier = null; - - mCallList.removeListener(this); - mCallList = null; - - mContext = null; - mInCallActivity = null; - - mListeners.clear(); - - Logger.d(this, "Finished InCallPresenter.tearDown"); + Logger.d(this, "tearDown"); + mServiceConnected = false; + attemptCleanup(); } + /** + * Called when the UI begins or ends. Starts the callstate callbacks if the UI just began. + * Attempts to tear down everything if the UI just ended. See #tearDown for more insight on + * the tear-down process. + */ public void setActivity(InCallActivity inCallActivity) { mInCallActivity = inCallActivity; - Logger.d(this, "UI Initialized"); + if (mInCallActivity != null) { + Logger.d(this, "UI Initialized"); - // Since the UI just came up, imitate an update from the call list - // to set the proper UI state. - onCallListChange(mCallList); + // Since the UI just came up, imitate an update from the call list + // to set the proper UI state. + onCallListChange(mCallList); + } else { + Logger.d(this, "setActivity(null)"); + attemptCleanup(); + } } /** @@ -187,7 +197,9 @@ public class InCallPresenter implements CallList.Listener { public void onUiShowing(boolean showing) { // We need to update the notification bar when we leave the UI because that // could trigger it to show again. - mStatusBarNotifier.updateNotification(mInCallState, mCallList); + if (mStatusBarNotifier != null) { + mStatusBarNotifier.updateNotification(mInCallState, mCallList); + } } /** @@ -195,7 +207,7 @@ public class InCallPresenter implements CallList.Listener { * the UI needs to be started or finished depending on the new state and does it. */ private InCallState startOrFinishUi(InCallState newState) { - Logger.d(this, "startOrFInishUi: " + newState.toString()); + Logger.d(this, "startOrFinishUi: " + newState.toString()); // TODO(klp): Consider a proper state machine implementation @@ -228,8 +240,10 @@ public class InCallPresenter implements CallList.Listener { // [ 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); + // we get an incoming call or if this is the first time we are displaying (the previous + // state was HIDDEN). + final boolean startStartupSequence = (InCallState.INCOMING == newState || + InCallState.HIDDEN == 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. @@ -242,10 +256,10 @@ public class InCallPresenter implements CallList.Listener { Logger.v(this, "startStartupSequence: ", startStartupSequence); - if (startStartupSequence) { - mStatusBarNotifier.updateNotificationAndLaunchIncomingCallUi(newState, mCallList); - } else if (showCallUi) { + if (showCallUi) { showInCall(); + } else if (startStartupSequence) { + mStatusBarNotifier.updateNotificationAndLaunchIncomingCallUi(newState, mCallList); } else if (newState == InCallState.HIDDEN) { // The new state is the hidden state (no calls). Tear everything down. @@ -265,6 +279,30 @@ public class InCallPresenter implements CallList.Listener { return newState; } + /** + * Checks to see if both the UI is gone and the service is disconnected. If so, tear it all + * down. + */ + private void attemptCleanup() { + if (mInCallActivity == null && !mServiceConnected) { + Logger.d(this, "Start InCallPresenter.CleanUp"); + mAudioModeProvider = null; + + removeListener(mStatusBarNotifier); + mStatusBarNotifier = null; + + mCallList.removeListener(this); + mCallList = null; + + mContext = null; + mInCallActivity = null; + + mListeners.clear(); + + Logger.d(this, "Finished InCallPresenter.CleanUp"); + } + } + private void showInCall() { Logger.d(this, "Showing in call manually."); mContext.startActivity(getInCallIntent()); -- cgit v1.2.3 From 7b87a85abf483599c956820c06791da78c9ff5e0 Mon Sep 17 00:00:00 2001 From: Santos Cordon Date: Tue, 20 Aug 2013 15:07:51 -0700 Subject: Adding proximity sensor code to in-call UI. Many of these changes are verbatim code copies from what used to exist in services/Telephony. The rest of them are straight logic copies that should do the exact same things. New class ProximitySensor manages the proximity behavior. It receives device state from InCallPresenter, AudioModeProvider, CallButtonPresenter, and AcceleromterListener, the last of which is a transplanted class from services/Telephony. ProximitySensor listens for the following events: 1. Change in the call state 2. Change in the audio mode 3. Change in the device orientation (from AccelerometerListener) 4. Change in the dialpad visibility 5. Change in hard keyboard open/close events. 6. Change in foreground position of InCall UI app. It uses these to figure out when to enable/disable proximity sensor. CL that removes code from TeleService: I77e0d15ad1a8f5a090c1368db98edaa246dbcd72 bug: 10366512 Change-Id: I5c2ea6daa9443e7ad77c67f272bc0bafdb060e5e --- InCallUI/AndroidManifest.xml | 1 + .../android/incallui/AccelerometerListener.java | 161 ++++++++++++++ .../com/android/incallui/CallButtonPresenter.java | 6 + .../src/com/android/incallui/InCallActivity.java | 11 + .../src/com/android/incallui/InCallPresenter.java | 13 ++ .../src/com/android/incallui/ProximitySensor.java | 232 +++++++++++++++++++++ 6 files changed, 424 insertions(+) create mode 100644 InCallUI/src/com/android/incallui/AccelerometerListener.java create mode 100644 InCallUI/src/com/android/incallui/ProximitySensor.java diff --git a/InCallUI/AndroidManifest.xml b/InCallUI/AndroidManifest.xml index 3196dba60..42d8e3173 100644 --- a/InCallUI/AndroidManifest.xml +++ b/InCallUI/AndroidManifest.xml @@ -23,6 +23,7 @@ + VERTICAL_ANGLE ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL); + if (VDEBUG) Log.d(TAG, "angle: " + angle + " orientation: " + orientation); + setOrientation(orientation); + } + + SensorEventListener mSensorListener = new SensorEventListener() { + public void onSensorChanged(SensorEvent event) { + onSensorEvent(event.values[0], event.values[1], event.values[2]); + } + + public void onAccuracyChanged(Sensor sensor, int accuracy) { + // ignore + } + }; + + Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case ORIENTATION_CHANGED: + synchronized (this) { + mOrientation = mPendingOrientation; + if (DEBUG) { + Log.d(TAG, "orientation: " + + (mOrientation == ORIENTATION_HORIZONTAL ? "horizontal" + : (mOrientation == ORIENTATION_VERTICAL ? "vertical" + : "unknown"))); + } + mListener.orientationChanged(mOrientation); + } + break; + } + } + }; +} diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java index 12cc65663..233231754 100644 --- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java +++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java @@ -33,6 +33,7 @@ public class CallButtonPresenter extends Presenter