Dynamically add AnswerFragment
AnswerPresenter is a little tricky because it is in charge of
responding to incoming calls, so we want it to be alive and getting
onIncomingCall callbacks, but we don't want to create an instance
of AnswerFragment, which it is dependent on.
Move some dependencies around so that AnswerPresenter is created
by InCallPresenter instead. It registers for callbacks via InCallPresenter
instead of directly to CallList, and shows/hides the AnswerFragment via
InCallActivity.
Change-Id: I7026150988bf3cda762dda8a319f48e1af132361
diff --git a/InCallUI/res/layout-land/call_card_content.xml b/InCallUI/res/layout-land/call_card_fragment.xml
similarity index 90%
rename from InCallUI/res/layout-land/call_card_content.xml
rename to InCallUI/res/layout-land/call_card_fragment.xml
index 496b6b3..4c76b95 100644
--- a/InCallUI/res/layout-land/call_card_content.xml
+++ b/InCallUI/res/layout-land/call_card_fragment.xml
@@ -93,23 +93,13 @@
<!-- Placeholder for the dialpad which is replaced with the dialpad fragment when shown. -->
<FrameLayout
- android:id="@+id/dialpadFragmentContainer"
+ android:id="@+id/answer_and_dialpad_container"
android:layout_toEndOf="@id/primary_call_info_container"
android:layout_gravity="end|center_vertical"
android:layout_alignParentEnd="true"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- <fragment android:name="com.android.incallui.AnswerFragment"
- android:id="@+id/answerFragment"
- android:layout_toEndOf="@id/primary_call_info_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="start"
- android:layout_gravity="end|center_vertical"
- android:layout_marginBottom="@dimen/glowpadview_margin_bottom"
- android:visibility="gone" />
-
<FrameLayout
android:id="@+id/floating_end_call_action_button_container"
android:layout_width="@dimen/end_call_floating_action_button_diameter"
diff --git a/InCallUI/res/layout/answer_fragment.xml b/InCallUI/res/layout/answer_fragment.xml
index d663b83..ec6ef30 100644
--- a/InCallUI/res/layout/answer_fragment.xml
+++ b/InCallUI/res/layout/answer_fragment.xml
@@ -19,13 +19,13 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dc="http://schemas.android.com/apk/res-auto"
android:id="@+id/glow_pad_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:focusable="true"
android:layout_centerHorizontal="true"
android:gravity="center"
android:background="@color/glowpad_background_color"
- android:visibility="gone"
+ android:layout_marginBottom="@dimen/glowpadview_margin_bottom"
dc:targetDrawables="@array/incoming_call_widget_audio_with_sms_targets"
dc:targetDescriptions="@array/incoming_call_widget_audio_with_sms_target_descriptions"
diff --git a/InCallUI/res/layout/call_card_content.xml b/InCallUI/res/layout/call_card_fragment.xml
similarity index 90%
rename from InCallUI/res/layout/call_card_content.xml
rename to InCallUI/res/layout/call_card_fragment.xml
index 7a42586..920f8cb 100644
--- a/InCallUI/res/layout/call_card_content.xml
+++ b/InCallUI/res/layout/call_card_fragment.xml
@@ -98,9 +98,9 @@
android:layout_height="wrap_content"
android:layout_alignTop="@id/photo" />
- <!-- Placeholder for the dialpad which is replaced with the dialpad fragment when shown. -->
+ <!-- Placeholder for various fragments that are added dynamically underneath the caller info -->
<FrameLayout
- android:id="@+id/dialpadFragmentContainer"
+ android:id="@+id/answer_and_dialpad_container"
android:layout_below="@id/primary_call_info_container"
android:layout_gravity="bottom|center_horizontal"
android:layout_alignParentBottom="true"
@@ -108,15 +108,6 @@
android:layout_height="match_parent"
android:elevation="@dimen/dialpad_elevation" />
- <fragment android:name="com.android.incallui.AnswerFragment"
- android:id="@+id/answerFragment"
- android:layout_below="@id/primary_call_info_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="bottom|center_horizontal"
- android:layout_marginBottom="@dimen/glowpadview_margin_bottom"
- android:visibility="gone" />
-
<FrameLayout
android:id="@+id/floating_end_call_action_button_container"
android:layout_width="@dimen/end_call_floating_action_button_diameter"
diff --git a/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java
index cb09dfd..8cbce10 100644
--- a/InCallUI/src/com/android/incallui/AnswerFragment.java
+++ b/InCallUI/src/com/android/incallui/AnswerFragment.java
@@ -76,7 +76,7 @@
@Override
public AnswerPresenter createPresenter() {
- return new AnswerPresenter();
+ return InCallPresenter.getInstance().getAnswerPresenter();
}
@Override
@@ -108,11 +108,9 @@
}
@Override
- public void showAnswerUi(boolean show) {
- getView().setVisibility(show ? View.VISIBLE : View.GONE);
-
- Log.d(this, "Show answer UI: " + show);
- if (show) {
+ public void onShowAnswerUi(boolean shown) {
+ Log.d(this, "Show answer UI: " + shown);
+ if (shown) {
mGlowpad.startPing();
} else {
mGlowpad.stopPing();
diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java
index e579d64..cc95e01 100644
--- a/InCallUI/src/com/android/incallui/AnswerPresenter.java
+++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java
@@ -17,15 +17,23 @@
package com.android.incallui;
import android.content.Context;
-import android.telecom.TelecomManager;
+
+import com.android.incallui.InCallPresenter.InCallState;
import java.util.List;
/**
- * Presenter for the Incoming call widget.
+ * Presenter for the Incoming call widget. The {@link AnswerPresenter} handles the logic during
+ * incoming calls. It is also in charge of responding to incoming calls, so there needs to be
+ * an instance alive so that it can receive onIncomingCall callbacks.
+ *
+ * An instance of {@link AnswerPresenter} is created by InCallPresenter at startup, registers
+ * for callbacks via InCallPresenter, and shows/hides the {@link AnswerFragment} via IncallActivity.
+ *
*/
public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
- implements CallList.CallUpdateListener, CallList.Listener {
+ implements CallList.CallUpdateListener, InCallPresenter.InCallUiListener,
+ InCallPresenter.IncomingCallListener {
private static final String TAG = AnswerPresenter.class.getSimpleName();
@@ -34,57 +42,33 @@
private boolean mHasTextMessages = false;
@Override
- public void onUiReady(AnswerUi ui) {
- super.onUiReady(ui);
-
- final CallList calls = CallList.getInstance();
- Call call;
- call = calls.getIncomingCall();
- if (call != null) {
- processIncomingCall(call);
- }
- call = calls.getVideoUpgradeRequestCall();
- if (call != null) {
- processVideoUpgradeRequestCall(call);
- }
-
- // Listen for incoming calls.
- calls.addListener(this);
- }
-
- @Override
- public void onUiUnready(AnswerUi ui) {
- super.onUiUnready(ui);
-
- CallList.getInstance().removeListener(this);
-
- // This is necessary because the activity can be destroyed while an incoming call exists.
- // This happens when back button is pressed while incoming call is still being shown.
- if (mCallId != null) {
- CallList.getInstance().removeCallUpdateListener(mCallId, this);
- }
- }
-
- @Override
- public void onCallListChange(CallList callList) {
- // no-op
- }
-
- @Override
- public void onDisconnect(Call call) {
- // no-op
- }
-
- @Override
- public void onIncomingCall(Call call) {
- // TODO: Ui is being destroyed when the fragment detaches. Need clean up step to stop
- // getting updates here.
- Log.d(this, "onIncomingCall: " + this);
- if (getUi() != null) {
- if (!call.getId().equals(mCallId)) {
- // A new call is coming in.
+ public void onUiShowing(boolean showing) {
+ if (showing) {
+ final CallList calls = CallList.getInstance();
+ Call call;
+ call = calls.getIncomingCall();
+ if (call != null) {
processIncomingCall(call);
}
+ call = calls.getVideoUpgradeRequestCall();
+ if (call != null) {
+ processVideoUpgradeRequestCall(call);
+ }
+ } else {
+ // This is necessary because the activity can be destroyed while an incoming call exists.
+ // This happens when back button is pressed while incoming call is still being shown.
+ if (mCallId != null) {
+ CallList.getInstance().removeCallUpdateListener(mCallId, this);
+ }
+ }
+ }
+
+ @Override
+ public void onIncomingCall(InCallState oldState, InCallState newState, Call call) {
+ Log.d(this, "onIncomingCall: " + this);
+ if (!call.getId().equals(mCallId)) {
+ // A new call is coming in.
+ processIncomingCall(call);
}
}
@@ -96,9 +80,20 @@
CallList.getInstance().addCallUpdateListener(mCallId, this);
Log.d(TAG, "Showing incoming for call id: " + mCallId + " " + this);
- final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId());
- getUi().showAnswerUi(true);
- configureAnswerTargetsForSms(call, textMsgs);
+ if (showAnswerUi(true)) {
+ final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId());
+ configureAnswerTargetsForSms(call, textMsgs);
+ }
+ }
+
+ private boolean showAnswerUi(boolean show) {
+ final InCallActivity activity = InCallPresenter.getInstance().getActivity();
+ if (activity != null) {
+ activity.showAnswerFragment(show);
+ return true;
+ } else {
+ return false;
+ }
}
private void processVideoUpgradeRequestCall(Call call) {
@@ -107,7 +102,7 @@
// Listen for call updates for the current call.
CallList.getInstance().addCallUpdateListener(mCallId, this);
- getUi().showAnswerUi(true);
+ showAnswerUi(true);
getUi().showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_UPGRADE_REQUEST);
}
@@ -119,7 +114,7 @@
// Stop listening for updates.
CallList.getInstance().removeCallUpdateListener(mCallId, this);
- getUi().showAnswerUi(false);
+ showAnswerUi(false);
// mCallId will hold the state of the call. We don't clear the mCall variable here as
// it may be useful for sending text messages after phone disconnects.
@@ -175,6 +170,10 @@
}
private void configureAnswerTargetsForSms(Call call, List<String> textMsgs) {
+ if (getUi() == null) {
+ return;
+ }
+
final Context context = getUi().getContext();
mHasTextMessages = textMsgs != null;
@@ -199,7 +198,7 @@
}
interface AnswerUi extends Ui {
- public void showAnswerUi(boolean show);
+ public void onShowAnswerUi(boolean shown);
public void showTargets(int targetSet);
public void showMessageDialog();
public void configureMessageDialog(List<String> textResponses);
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index 1b17d35..6d7e1d5 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -149,7 +149,7 @@
mTranslationOffset =
getResources().getDimensionPixelSize(R.dimen.call_card_anim_translate_y_offset);
- return inflater.inflate(R.layout.call_card_content, container, false);
+ return inflater.inflate(R.layout.call_card_fragment, container, false);
}
@Override
diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java
index a6b3a41..da3d692 100644
--- a/InCallUI/src/com/android/incallui/InCallActivity.java
+++ b/InCallUI/src/com/android/incallui/InCallActivity.java
@@ -18,10 +18,12 @@
import android.app.ActionBar;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnCancelListener;
@@ -29,6 +31,7 @@
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Bundle;
+import android.os.Trace;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
@@ -281,8 +284,8 @@
return mIsForegroundActivity;
}
- private boolean hasPendingErrorDialog() {
- return mDialog != null;
+ private boolean hasPendingDialogs() {
+ return mDialog != null || (mAnswerFragment != null && mAnswerFragment.hasPendingDialogs());
}
@Override
@@ -290,8 +293,7 @@
Log.i(this, "finish(). Dialog showing: " + (mDialog != null));
// skip finish if we are still showing a dialog.
- if (!hasPendingErrorDialog() && mAnswerFragment != null
- && !mAnswerFragment.hasPendingDialogs()) {
+ if (!hasPendingDialogs()) {
super.finish();
}
}
@@ -465,6 +467,10 @@
return mCallCardFragment;
}
+ public AnswerFragment getAnswerFragment() {
+ return mAnswerFragment;
+ }
+
private void internalResolveIntent(Intent intent) {
final String action = intent.getAction();
@@ -590,11 +596,6 @@
.findFragmentById(R.id.callButtonFragment);
mCallButtonFragment.getView().setVisibility(View.INVISIBLE);
}
-
- if (mAnswerFragment == null) {
- mAnswerFragment = (AnswerFragment) mChildFragmentManager
- .findFragmentById(R.id.answerFragment);
- }
}
public void dismissKeyguard(boolean dismiss) {
@@ -610,6 +611,7 @@
}
private void showFragment(String tag, boolean show, boolean executeImmediately) {
+ Trace.beginSection("showFragment - " + tag);
final FragmentManager fm = getFragmentManagerForTag(tag);
if (fm == null) {
@@ -639,6 +641,7 @@
if (executeImmediately) {
fm.executePendingTransactions();
}
+ Trace.endSection();
}
private Fragment createNewFragmentForTag(String tag) {
@@ -673,9 +676,9 @@
private int getContainerIdForFragment(String tag) {
if (TAG_DIALPAD_FRAGMENT.equals(tag)) {
- return R.id.dialpadFragmentContainer;
+ return R.id.answer_and_dialpad_container;
} else if (TAG_ANSWER_FRAGMENT.equals(tag)) {
- return R.id.dialpadFragmentContainer;
+ return R.id.answer_and_dialpad_container;
} else if (TAG_CONFERENCE_FRAGMENT.equals(tag)) {
return R.id.main;
} else if (TAG_CALLCARD_FRAGMENT.equals(tag)) {
@@ -724,6 +727,10 @@
mCallCardFragment.getView().setVisibility(show ? View.GONE : View.VISIBLE);
}
+ public void showAnswerFragment(boolean show) {
+ showFragment(TAG_ANSWER_FRAGMENT, show, true);
+ }
+
public void showPostCharWaitDialog(String callId, String chars) {
if (isForegroundActivity()) {
final PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index f2aaea1..6a1295e 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -97,6 +97,7 @@
private boolean mServiceConnected = false;
private boolean mAccountSelectionCancelled = false;
private InCallCameraManager mInCallCameraManager = null;
+ private AnswerPresenter mAnswerPresenter = new AnswerPresenter();
/**
* Whether or not we are currently bound and waiting for Telecom to send us a new call.
@@ -1372,10 +1373,20 @@
return mTelecomManager;
}
+ InCallActivity getActivity() {
+ return mInCallActivity;
+ }
+
+ AnswerPresenter getAnswerPresenter() {
+ return mAnswerPresenter;
+ }
+
/**
* Private constructor. Must use getInstance() to get this singleton.
*/
private InCallPresenter() {
+ addIncomingCallListener(mAnswerPresenter);
+ addInCallUiListener(mAnswerPresenter);
}
/**