summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
authorSantos Cordon <santoscordon@google.com>2013-07-31 16:36:29 -0700
committerSantos Cordon <santoscordon@google.com>2013-08-01 10:28:54 -0700
commit150a5c58c67f230c8fd7293b180bbf50aa761480 (patch)
treec37d6cfe313c0666e7cacf02bdbde958c7534baf /src/com/android
parenta012c22dfbfedffe2e751f9b1ab776baa325a26f (diff)
downloadpackages_apps_InCallUI-150a5c58c67f230c8fd7293b180bbf50aa761480.tar.gz
packages_apps_InCallUI-150a5c58c67f230c8fd7293b180bbf50aa761480.tar.bz2
packages_apps_InCallUI-150a5c58c67f230c8fd7293b180bbf50aa761480.zip
Adding multi-call support.
Before this change, the UI came up when we were notified that a new call came in, but we did not actually look at the call state, etc. This seemingly worked while we only supported single calls but did not scale. This change does two main things: a) Plugs in CallList into the presenters so that they can perform their logic based on the actual state of the calls (necessary for multi-call support) b) Adds Secondary CallInfo UI to the Call Card so that we can display information foreground and background calls. As a result of (a) from above, a lot of changes you see will be to Presenters, which now take their cues from CallList and update their Ui's accordingly. A problem with this approach is that the presenters (callcard/buttons/answer-widget) perform their changes independently. A subsequent change will consolidate interactions with CallList to a Presenter-Manager class and away from the presenters. Change-Id: I89d1926fa1eef6f10d897d2ce360f666c8f341f8
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/incallui/AnswerFragment.java59
-rw-r--r--src/com/android/incallui/AnswerPresenter.java45
-rw-r--r--src/com/android/incallui/CallButtonPresenter.java29
-rw-r--r--src/com/android/incallui/CallCardFragment.java29
-rw-r--r--src/com/android/incallui/CallCardPresenter.java22
-rw-r--r--src/com/android/incallui/CallHandlerService.java2
-rw-r--r--src/com/android/incallui/CallList.java38
-rw-r--r--src/com/android/incallui/InCallActivity.java65
8 files changed, 202 insertions, 87 deletions
diff --git a/src/com/android/incallui/AnswerFragment.java b/src/com/android/incallui/AnswerFragment.java
index 90bc4360..76c92516 100644
--- a/src/com/android/incallui/AnswerFragment.java
+++ b/src/com/android/incallui/AnswerFragment.java
@@ -16,6 +16,9 @@
package com.android.incallui;
+import com.google.common.base.Preconditions;
+
+import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
@@ -26,16 +29,22 @@ import android.view.ViewGroup;
*
*/
public class AnswerFragment extends BaseFragment<AnswerPresenter> implements
- GlowPadWrapper.AnswerListener {
+ GlowPadWrapper.AnswerListener, AnswerPresenter.AnswerUi {
+ final private IFragmentHost mFragmentHost;
+
+ public AnswerFragment(IFragmentHost fragmentHost) {
+ mFragmentHost = fragmentHost;
+
+ // Normally called with onCreateView, however, AnswerPresenter's interaction
+ // begins before any UI is displayed.
+ // Order matters with this call because mFragmentHost mustn't be null when the presenter
+ // asks AnswerFragment to display itself (see showAnswerWidget).
+ getPresenter().onUiReady(this);
+ }
@Override
public AnswerPresenter createPresenter() {
- return new AnswerPresenter(new AnswerPresenter.Listener() {
- @Override
- public void onClose() {
- close();
- }
- });
+ return new AnswerPresenter();
}
@Override
@@ -47,12 +56,6 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter> implements
return glowPad;
}
- private void close() {
- final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
- fragmentTransaction.remove(this);
- fragmentTransaction.commit();
- }
-
@Override
public void onAnswer() {
getPresenter().onAnswer();
@@ -67,4 +70,34 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter> implements
public void onText() {
getPresenter().onText();
}
+
+ @Override
+ public void showAnswerWidget(boolean show) {
+ Preconditions.checkNotNull(mFragmentHost);
+
+ if (show) {
+ mFragmentHost.addFragment(this);
+ } else {
+ close();
+ }
+ }
+
+ private void close() {
+ // TODO(klp): With a proper main presenter, we will not need to check for isAdded.
+ if (isAdded()) {
+ final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
+ fragmentTransaction.remove(this);
+ fragmentTransaction.commit();
+ }
+ }
+
+ // Stop gap until we can consolidate presenters and make InCallActivity a UI Class that relies
+ // on it's the consolidated presenter.
+ //
+ // TODO(klp): Remove individual presenters for button/answer/callcard and have a single
+ // presenter that interacts directly with this activity. This will allow us to remove
+ // this unnecessary interface.
+ static interface IFragmentHost {
+ public void addFragment(Fragment fragment);
+ }
}
diff --git a/src/com/android/incallui/AnswerPresenter.java b/src/com/android/incallui/AnswerPresenter.java
index d6f87c74..a406b0a2 100644
--- a/src/com/android/incallui/AnswerPresenter.java
+++ b/src/com/android/incallui/AnswerPresenter.java
@@ -16,46 +16,45 @@
package com.android.incallui;
-import com.google.android.collect.Lists;
-
-import java.util.ArrayList;
-
/**
- *
+ * Presenter for the Incoming call widget.
*/
-public class AnswerPresenter extends Presenter<Ui> {
+public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
+ implements CallList.Listener {
- private ArrayList<Listener> mListeners = Lists.newArrayList();
-
- public AnswerPresenter(Listener listener) {
- this.mListeners.add(listener);
+ @Override
+ public void onUiReady(AnswerUi ui) {
+ super.onUiReady(ui);
+ CallList.getInstance().addListener(this);
}
- public void addCloseListener(Listener listener) {
- mListeners.add(listener);
+ @Override
+ public void onCallListChange(CallList callList) {
+ // TODO(klp): The answer widget and call cards are independently managing their behavior
+ // from CallList events. We need to create a class to manage the behavior of all the
+ // Presenters from a single place.
+ final boolean showWidget = (callList.getIncomingCall() != null);
+
+ final AnswerUi ui = getUi();
+ if (ui != null) {
+ ui.showAnswerWidget(showWidget);
+ }
}
public void onAnswer() {
// TODO(klp): hook in call id.
CallCommandClient.getInstance().answerCall(1);
- notifyListeners();
}
public void onDecline() {
- notifyListeners();
+ // TODO(klp): hook in call id.
+ CallCommandClient.getInstance().disconnectCall(1);
}
public void onText() {
- notifyListeners();
- }
-
- private void notifyListeners() {
- for (Listener listener : mListeners) {
- listener.onClose();
- }
}
- public interface Listener {
- void onClose();
+ interface AnswerUi extends Ui {
+ public void showAnswerWidget(boolean show);
}
}
diff --git a/src/com/android/incallui/CallButtonPresenter.java b/src/com/android/incallui/CallButtonPresenter.java
index be76f2d2..10d4f723 100644
--- a/src/com/android/incallui/CallButtonPresenter.java
+++ b/src/com/android/incallui/CallButtonPresenter.java
@@ -21,10 +21,10 @@ import android.media.AudioManager;
/**
* Logic for call buttons.
*/
-public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButtonUi> {
+public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButtonUi>
+ implements CallList.Listener {
private AudioManager mAudioManager;
- private EndCallListener mEndCallListener;
public void init(AudioManager audioManager) {
mAudioManager = audioManager;
@@ -35,19 +35,26 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto
super.onUiReady(ui);
getUi().setMute(mAudioManager.isMicrophoneMute());
getUi().setSpeaker(mAudioManager.isSpeakerphoneOn());
+
+ CallList.getInstance().addListener(this);
}
- public void show() {
- getUi().setVisible(true);
+ @Override
+ public void onCallListChange(CallList callList) {
+ // show the buttons if there is a live call AND there is no
+ // incoming call.
+ final boolean showButtons = callList.existsLiveCall() &&
+ callList.getIncomingCall() == null;
+ getUi().setVisible(showButtons);
}
public void endCallClicked() {
// TODO(klp): hook up call id.
CallCommandClient.getInstance().disconnectCall(1);
- mEndCallListener.onCallEnd();
-
- // TODO(klp): These states should come from Call objects from the CallList.
+ // TODO(klp): Remove once all state is gathered from CallList.
+ // This will be wrong when you disconnect from a call if
+ // the user has another call on hold.
reset();
}
@@ -74,18 +81,10 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto
getUi().setHold(checked);
}
- public void setEndCallListener(EndCallListener endCallListener) {
- mEndCallListener = endCallListener;
- }
-
public interface CallButtonUi extends Ui {
void setVisible(boolean on);
void setMute(boolean on);
void setSpeaker(boolean on);
void setHold(boolean on);
}
-
- public interface EndCallListener {
- void onCallEnd();
- }
}
diff --git a/src/com/android/incallui/CallCardFragment.java b/src/com/android/incallui/CallCardFragment.java
index 2fb31722..3f46bb56 100644
--- a/src/com/android/incallui/CallCardFragment.java
+++ b/src/com/android/incallui/CallCardFragment.java
@@ -20,6 +20,7 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStub;
import android.widget.TextView;
/**
@@ -30,6 +31,9 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
private TextView mPhoneNumber;
+ private ViewStub mSecondaryCallInfo;
+ private TextView mSecondaryCallName;
+
@Override
CallCardPresenter createPresenter() {
return new CallCardPresenter();
@@ -38,12 +42,13 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- return inflater.inflate(R.layout.call_card_fragment, container, false);
+ return inflater.inflate(R.layout.call_card, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mPhoneNumber = (TextView) view.findViewById(R.id.phoneNumber);
+ mSecondaryCallInfo = (ViewStub) view.findViewById(R.id.secondary_call_info);
// This method call will begin the callbacks on CallCardUi. We need to ensure
// everything needed for the callbacks is set up before this is called.
@@ -51,6 +56,18 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
}
@Override
+ public void setSecondaryCallInfo(boolean show, String number) {
+ if (show) {
+ showAndInitializeSecondaryCallInfo();
+
+ // Until we have the name source, use the number as the main text for secondary calls.
+ mSecondaryCallName.setText(number);
+ } else {
+ mSecondaryCallInfo.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
public void setNumber(String number) {
mPhoneNumber.setText(number);
}
@@ -59,4 +76,14 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
public void setName(String name) {
}
+ private void showAndInitializeSecondaryCallInfo() {
+ mSecondaryCallInfo.setVisibility(View.VISIBLE);
+
+ // mSecondaryCallName is initialized here (vs. onViewCreated) because it is inaccesible
+ // until mSecondaryCallInfo is inflated in the call above.
+ if (mSecondaryCallName == null) {
+ mSecondaryCallName = (TextView) getView().findViewById(R.id.secondaryCallName);
+ }
+ }
+
}
diff --git a/src/com/android/incallui/CallCardPresenter.java b/src/com/android/incallui/CallCardPresenter.java
index 85f05341..0ba4176c 100644
--- a/src/com/android/incallui/CallCardPresenter.java
+++ b/src/com/android/incallui/CallCardPresenter.java
@@ -30,26 +30,36 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
super.onUiReady(ui);
CallList.getInstance().addListener(this);
-
- // When UI is ready, manually trigger a change
- onCallListChange(CallList.getInstance());
}
@Override
public void onCallListChange(CallList callList) {
- Call call = callList.getIncomingOrActive();
+ final CallCardUi ui = getUi();
+ // Populate the primary call card based on the incoming call or the active call.
+ final Call call = callList.getIncomingOrActive();
if (call != null) {
- getUi().setNumber(call.getNumber());
+ ui.setNumber(call.getNumber());
} else {
// When there is no longer an incoming/active call, we need to reset everything
// so that no data survives for the next call.
- getUi().setNumber("");
+ ui.setNumber("");
+ }
+
+ // secondary call card info only comes from the background call (if any exist)
+ final Call backgroundCall = callList.getBackgroundCall();
+ if (backgroundCall != null) {
+ ui.setSecondaryCallInfo(true, backgroundCall.getNumber());
+ } else {
+ ui.setSecondaryCallInfo(false, null);
}
}
public interface CallCardUi extends Ui {
+ // TODO(klp): Consider passing in the Call object directly in these methods.
+
public void setNumber(String number);
public void setName(String name);
+ public void setSecondaryCallInfo(boolean show, String number);
}
}
diff --git a/src/com/android/incallui/CallHandlerService.java b/src/com/android/incallui/CallHandlerService.java
index 4a14dab8..a9516e8a 100644
--- a/src/com/android/incallui/CallHandlerService.java
+++ b/src/com/android/incallui/CallHandlerService.java
@@ -70,6 +70,8 @@ public class CallHandlerService extends Service {
@Override
public void onIncomingCall(Call call) {
+ // TODO(klp): New presenter manager should launch this task...not this service.
+ // TODO(klp): Update the flags to match the only activity
final Intent intent = new Intent(getApplication(), InCallActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
diff --git a/src/com/android/incallui/CallList.java b/src/com/android/incallui/CallList.java
index ac3e3bfd..f41af930 100644
--- a/src/com/android/incallui/CallList.java
+++ b/src/com/android/incallui/CallList.java
@@ -82,7 +82,11 @@ public class CallList {
public void addListener(Listener listener) {
Preconditions.checkNotNull(listener);
+
mListeners.add(listener);
+
+ // Let the listener know about the active calls immediately.
+ listener.onCallListChange(this);
}
public void removeListener(Listener listener) {
@@ -96,15 +100,39 @@ public class CallList {
* update the Call object when the active call changes.
*/
public Call getIncomingOrActive() {
- Call retval = null;
+ Call retval = getIncomingCall();
+ if (retval == null) {
+ retval = getFirstCallWithState(Call.State.ACTIVE);
+ }
+ return retval;
+ }
+
+ public Call getBackgroundCall() {
+ return getFirstCallWithState(Call.State.ONHOLD);
+ }
+
+ public Call getIncomingCall() {
+ return getFirstCallWithState(Call.State.INCOMING);
+ }
+ public boolean existsLiveCall() {
for (Call call : mCallMap.values()) {
- if (call.getState() == Call.State.INCOMING) {
+ if (!isCallDead(call)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns first call found in the call map with the specified state.
+ */
+ public Call getFirstCallWithState(int state) {
+ Call retval = null;
+ for (Call call : mCallMap.values()) {
+ if (call.getState() == state) {
retval = call;
- // incoming call takes precedence, cut out early.
break;
- } else if (retval == null && call.getState() == Call.State.ACTIVE) {
- retval = call;
}
}
diff --git a/src/com/android/incallui/InCallActivity.java b/src/com/android/incallui/InCallActivity.java
index 04f1f09b..9732203b 100644
--- a/src/com/android/incallui/InCallActivity.java
+++ b/src/com/android/incallui/InCallActivity.java
@@ -17,6 +17,7 @@
package com.android.incallui;
import android.app.Activity;
+import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
@@ -30,15 +31,17 @@ import android.widget.Toast;
/**
* Phone app "in call" screen.
*/
-public class InCallActivity extends Activity implements CallButtonPresenter.EndCallListener {
+public class InCallActivity extends Activity implements AnswerFragment.IFragmentHost,
+ CallList.Listener {
private static final String TAG = InCallActivity.class.getSimpleName();
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
- private CallButtonPresenter mCallButtonPresenter;
- private CallCardPresenter mCallCardPresenter;
+ private CallButtonFragment mCallButtonFragment;
+ private CallCardFragment mCallCardFragment;
+ private AnswerFragment mAnswerFragment;
@Override
protected void onCreate(Bundle icicle) {
@@ -68,19 +71,6 @@ public class InCallActivity extends Activity implements CallButtonPresenter.EndC
protected void onResume() {
logD("onResume()...");
- // TODO(klp): create once and reset when needed.
- final AnswerFragment answerFragment = new AnswerFragment();
- final AnswerPresenter presenter = answerFragment.getPresenter();
- presenter.addCloseListener(new AnswerPresenter.Listener() {
- @Override
- public void onClose() {
- mCallButtonPresenter.show();
- }
- });
-
- final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
- fragmentTransaction.add(R.id.main, answerFragment);
- fragmentTransaction.commit();
super.onResume();
}
@@ -207,13 +197,23 @@ public class InCallActivity extends Activity implements CallButtonPresenter.EndC
private void initializeInCall() {
- final CallButtonFragment callButtonFragment = (CallButtonFragment) getFragmentManager()
- .findFragmentById(R.id.callButtonFragment);
- mCallButtonPresenter = callButtonFragment.getPresenter();
- mCallButtonPresenter.setEndCallListener(this);
+ // TODO(klp): Make sure that this doesn't need to move back to onResume() since they are
+ // statically added fragments.
+ if (mCallButtonFragment == null) {
+ mCallButtonFragment = (CallButtonFragment) getFragmentManager()
+ .findFragmentById(R.id.callButtonFragment);
+ }
+
+ if (mCallCardFragment == null) {
+ mCallCardFragment = (CallCardFragment) getFragmentManager()
+ .findFragmentById(R.id.callCardFragment);
+ }
+
+ if (mAnswerFragment == null) {
+ mAnswerFragment = new AnswerFragment(this);
+ }
- final CallCardFragment callCardFragment = (CallCardFragment) getFragmentManager()
- .findFragmentById(R.id.callCardFragment);
+ CallList.getInstance().addListener(this);
}
private void toast(String text) {
@@ -229,7 +229,24 @@ public class InCallActivity extends Activity implements CallButtonPresenter.EndC
}
@Override
- public void onCallEnd() {
- finish();
+ public void addFragment(Fragment fragment) {
+ Log.d(TAG, "AddFragment");
+
+ // TODO(klp): Do a check to make sure the fragment isn't already added before trying to
+ // add it again.
+ // TODO(klp): IsResumed check only required because CallList notifications are coming in
+ // an indeterminate order. This should no longer be required with a main Presenter class.
+ if (this.isResumed()) {
+ final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
+ fragmentTransaction.add(R.id.main, fragment);
+ fragmentTransaction.commit();
+ }
+ }
+
+ @Override
+ public void onCallListChange(CallList callList) {
+ if (!callList.existsLiveCall()) {
+ finish();
+ }
}
}