summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorke Lee <yorkelee@google.com>2015-03-06 18:10:19 -0800
committerYorke Lee <yorkelee@google.com>2015-03-09 12:06:58 -0700
commit979f38e37da9bdd4c51aceafe7bcc44b305e3d02 (patch)
tree5400938433726257765bb89a204bc47ff35734ec
parent46d62c03a8066d43a709f52ddf8aa0f57e1ddb2c (diff)
Improve InCallUI fragment management
* Load some fragments on demand * ConferenceManagerFragment * DialpadFragment * Remove ConferenceManagerFragment from incall_screen.xml so that it is no longer loaded statically * Add helper methods to InCallActivity to facilitate dynamically loading fragments * Fix some bugs with fragment visibility and activity recreation Change-Id: I475e2302fae415817f06da209dd6484c89467480
-rw-r--r--InCallUI/res/layout/conference_manager_fragment.xml4
-rw-r--r--InCallUI/res/layout/incall_screen.xml9
-rw-r--r--InCallUI/src/com/android/incallui/AnswerFragment.java2
-rw-r--r--InCallUI/src/com/android/incallui/BaseFragment.java13
-rw-r--r--InCallUI/src/com/android/incallui/CallCardFragment.java1
-rw-r--r--InCallUI/src/com/android/incallui/ConferenceManagerFragment.java32
-rw-r--r--InCallUI/src/com/android/incallui/ConferenceManagerPresenter.java1
-rw-r--r--InCallUI/src/com/android/incallui/DialpadFragment.java7
-rw-r--r--InCallUI/src/com/android/incallui/FragmentDisplayManager.java23
-rw-r--r--InCallUI/src/com/android/incallui/InCallActivity.java150
10 files changed, 172 insertions, 70 deletions
diff --git a/InCallUI/res/layout/conference_manager_fragment.xml b/InCallUI/res/layout/conference_manager_fragment.xml
index 8e55ad762..7350bee14 100644
--- a/InCallUI/res/layout/conference_manager_fragment.xml
+++ b/InCallUI/res/layout/conference_manager_fragment.xml
@@ -22,9 +22,7 @@
android:background="@color/conference_call_manager_background_color"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="@dimen/conference_call_manager_padding_top"
- android:visibility="gone">
-
+ android:paddingTop="@dimen/conference_call_manager_padding_top" >
<!-- List of conference participants. -->
<ListView
android:id="@+id/participantList"
diff --git a/InCallUI/res/layout/incall_screen.xml b/InCallUI/res/layout/incall_screen.xml
index 9f7569574..fe97e1914 100644
--- a/InCallUI/res/layout/incall_screen.xml
+++ b/InCallUI/res/layout/incall_screen.xml
@@ -27,13 +27,4 @@
android:layout_alignParentTop="true"
android:layout_alignParentStart="true" />
- <fragment android:name="com.android.incallui.ConferenceManagerFragment"
- android:id="@+id/conferenceManagerFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentTop="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentBottom="true"
- android:layout_alignParentEnd="true" />
-
</FrameLayout>
diff --git a/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java
index 29747dabd..cb09dfdcc 100644
--- a/InCallUI/src/com/android/incallui/AnswerFragment.java
+++ b/InCallUI/src/com/android/incallui/AnswerFragment.java
@@ -247,7 +247,7 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter, AnswerPresente
}
}
- public void dismissPendingDialogues() {
+ public void dismissPendingDialogs() {
if (isCannedResponsePopupShowing()) {
dismissCannedResponsePopup();
}
diff --git a/InCallUI/src/com/android/incallui/BaseFragment.java b/InCallUI/src/com/android/incallui/BaseFragment.java
index 1ef3b1513..037c2455f 100644
--- a/InCallUI/src/com/android/incallui/BaseFragment.java
+++ b/InCallUI/src/com/android/incallui/BaseFragment.java
@@ -16,6 +16,7 @@
package com.android.incallui;
+import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
@@ -24,6 +25,8 @@ import android.os.Bundle;
*/
public abstract class BaseFragment<T extends Presenter<U>, U extends Ui> extends Fragment {
+ private static final String KEY_FRAGMENT_HIDDEN = "key_fragment_hidden";
+
private T mPresenter;
abstract T createPresenter();
@@ -54,6 +57,9 @@ public abstract class BaseFragment<T extends Presenter<U>, U extends Ui> extends
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mPresenter.onRestoreInstanceState(savedInstanceState);
+ if (savedInstanceState.getBoolean(KEY_FRAGMENT_HIDDEN)) {
+ getFragmentManager().beginTransaction().hide(this).commit();
+ }
}
}
@@ -67,5 +73,12 @@ public abstract class BaseFragment<T extends Presenter<U>, U extends Ui> extends
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mPresenter.onSaveInstanceState(outState);
+ outState.putBoolean(KEY_FRAGMENT_HIDDEN, isHidden());
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ ((FragmentDisplayManager) activity).onFragmentAttached(this);
}
}
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index 00e619609..bdf39d59f 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -134,7 +134,6 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
R.dimen.end_call_floating_action_button_small_diameter);
}
-
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
diff --git a/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java b/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java
index 163954b2d..6b232c934 100644
--- a/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java
+++ b/InCallUI/src/com/android/incallui/ConferenceManagerFragment.java
@@ -29,22 +29,25 @@ import com.android.contacts.common.ContactPhotoManager;
import java.util.List;
/**
- * Fragment for call control buttons
+ * Fragment that allows the user to manage a conference call.
*/
public class ConferenceManagerFragment
extends BaseFragment<ConferenceManagerPresenter,
ConferenceManagerPresenter.ConferenceManagerUi>
implements ConferenceManagerPresenter.ConferenceManagerUi {
+ private static final String KEY_IS_VISIBLE = "key_conference_is_visible";
+
private ListView mConferenceParticipantList;
private int mActionBarElevation;
private ContactPhotoManager mContactPhotoManager;
private LayoutInflater mInflater;
private ConferenceParticipantListAdapter mConferenceParticipantListAdapter;
+ private boolean mIsVisible;
+ private boolean mIsRecreating;
@Override
ConferenceManagerPresenter createPresenter() {
- // having a singleton instance.
return new ConferenceManagerPresenter();
}
@@ -56,6 +59,10 @@ public class ConferenceManagerFragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ mIsRecreating = true;
+ mIsVisible = savedInstanceState.getBoolean(KEY_IS_VISIBLE);
+ }
}
@Override
@@ -75,15 +82,23 @@ public class ConferenceManagerFragment
}
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
+ public void onResume() {
+ super.onResume();
+ if (mIsRecreating) {
+ onVisibilityChanged(mIsVisible);
+ }
}
@Override
- public void setVisible(boolean on) {
- ActionBar actionBar = getActivity().getActionBar();
+ public void onSaveInstanceState(Bundle outState) {
+ outState.putBoolean(KEY_IS_VISIBLE, mIsVisible);
+ super.onSaveInstanceState(outState);
+ }
- if (on) {
+ public void onVisibilityChanged(boolean isVisible) {
+ mIsVisible = isVisible;
+ ActionBar actionBar = getActivity().getActionBar();
+ if (isVisible) {
actionBar.setTitle(R.string.manageConferenceLabel);
actionBar.setElevation(mActionBarElevation);
actionBar.setHideOffset(0);
@@ -91,13 +106,10 @@ public class ConferenceManagerFragment
final CallList calls = CallList.getInstance();
getPresenter().init(getActivity(), calls);
- getView().setVisibility(View.VISIBLE);
// Request focus on the list of participants for accessibility purposes. This ensures
// that once the list of participants is shown, the first participant is announced.
mConferenceParticipantList.requestFocus();
} else {
- getView().setVisibility(View.GONE);
-
actionBar.setElevation(0);
actionBar.setHideOffset(actionBar.getHeight());
}
diff --git a/InCallUI/src/com/android/incallui/ConferenceManagerPresenter.java b/InCallUI/src/com/android/incallui/ConferenceManagerPresenter.java
index 86fc18ff3..6fb6e5dda 100644
--- a/InCallUI/src/com/android/incallui/ConferenceManagerPresenter.java
+++ b/InCallUI/src/com/android/incallui/ConferenceManagerPresenter.java
@@ -137,7 +137,6 @@ public class ConferenceManagerPresenter
}
public interface ConferenceManagerUi extends Ui {
- void setVisible(boolean on);
boolean isFragmentVisible();
void update(Context context, List<Call> participants, boolean parentCanSeparate);
void refreshCall(Call call);
diff --git a/InCallUI/src/com/android/incallui/DialpadFragment.java b/InCallUI/src/com/android/incallui/DialpadFragment.java
index 611815a33..5a02b8b0e 100644
--- a/InCallUI/src/com/android/incallui/DialpadFragment.java
+++ b/InCallUI/src/com/android/incallui/DialpadFragment.java
@@ -29,13 +29,11 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
-import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
import com.android.phone.common.dialpad.DialpadKeyButton;
import com.android.phone.common.dialpad.DialpadView;
@@ -421,11 +419,6 @@ public class DialpadFragment extends BaseFragment<DialpadPresenter, DialpadPrese
}
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View parent = inflater.inflate(
diff --git a/InCallUI/src/com/android/incallui/FragmentDisplayManager.java b/InCallUI/src/com/android/incallui/FragmentDisplayManager.java
new file mode 100644
index 000000000..045d999a0
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/FragmentDisplayManager.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 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 android.app.Fragment;
+
+interface FragmentDisplayManager {
+ public void onFragmentAttached(Fragment fragment);
+}
diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java
index 9dc703a2e..1a7312707 100644
--- a/InCallUI/src/com/android/incallui/InCallActivity.java
+++ b/InCallUI/src/com/android/incallui/InCallActivity.java
@@ -19,22 +19,18 @@ package com.android.incallui;
import android.app.ActionBar;
import android.app.Activity;
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;
import android.content.Intent;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Point;
-import android.net.Uri;
import android.os.Bundle;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
-import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.view.MenuItem;
import android.view.animation.Animation;
@@ -48,8 +44,6 @@ import android.view.accessibility.AccessibilityEvent;
import com.android.phone.common.animation.AnimUtils;
import com.android.phone.common.animation.AnimationListenerAdapter;
import com.android.contacts.common.interactions.TouchPointManager;
-import com.android.contacts.common.util.MaterialColorMapUtils;
-import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener;
import com.android.incallui.Call.State;
@@ -61,12 +55,19 @@ import java.util.Locale;
/**
* Main activity that the user interacts with while in a live call.
*/
-public class InCallActivity extends Activity {
+public class InCallActivity extends Activity implements FragmentDisplayManager {
+
+ public static final String TAG = InCallActivity.class.getSimpleName();
public static final String SHOW_DIALPAD_EXTRA = "InCallActivity.show_dialpad";
public static final String DIALPAD_TEXT_EXTRA = "InCallActivity.dialpad_text";
public static final String NEW_OUTGOING_CALL_EXTRA = "InCallActivity.new_outgoing_call";
+ private static final String TAG_DIALPAD_FRAGMENT = "tag_dialpad_fragment";
+ private static final String TAG_CONFERENCE_FRAGMENT = "tag_conference_manager_fragment";
+ private static final String TAG_CALLCARD_FRAGMENT = "tag_callcard_fragment";
+ private static final String TAG_ANSWER_FRAGMENT = "tag_answer_fragment";
+
private CallButtonFragment mCallButtonFragment;
private CallCardFragment mCallCardFragment;
private AnswerFragment mAnswerFragment;
@@ -99,7 +100,7 @@ public class InCallActivity extends Activity {
AnimationListenerAdapter mSlideOutListener = new AnimationListenerAdapter() {
@Override
public void onAnimationEnd(Animation animation) {
- showDialpad(false);
+ showFragment(TAG_DIALPAD_FRAGMENT, false, true);
}
};
@@ -177,6 +178,7 @@ public class InCallActivity extends Activity {
@Override
protected void onSaveInstanceState(Bundle out) {
+ // TODO: The dialpad fragment should handle this as part of its own state
out.putBoolean(SHOW_DIALPAD_EXTRA, mCallButtonFragment.isDialpadVisible());
if (mDialpadFragment != null) {
out.putString(DIALPAD_TEXT_EXTRA, mDialpadFragment.getDtmfText());
@@ -253,6 +255,26 @@ public class InCallActivity extends Activity {
}
/**
+ * When fragments have a parent fragment, onAttachFragment is not called on the parent
+ * activity. To fix this, register our own callback instead that is always called for
+ * all fragments.
+ *
+ * @see {@link BaseFragment#onAttach(Activity)}
+ */
+ @Override
+ public void onFragmentAttached(Fragment fragment) {
+ if (fragment instanceof DialpadFragment) {
+ mDialpadFragment = (DialpadFragment) fragment;
+ } else if (fragment instanceof AnswerFragment) {
+ mAnswerFragment = (AnswerFragment) fragment;
+ } else if (fragment instanceof CallCardFragment) {
+ mCallCardFragment = (CallCardFragment) fragment;
+ } else if (fragment instanceof ConferenceManagerFragment) {
+ mConferenceManagerFragment = (ConferenceManagerFragment) fragment;
+ }
+ }
+
+ /**
* Returns true when theActivity is in foreground (between onResume and onPause).
*/
/* package */ boolean isForegroundActivity() {
@@ -268,7 +290,8 @@ public class InCallActivity extends Activity {
Log.i(this, "finish(). Dialog showing: " + (mDialog != null));
// skip finish if we are still showing a dialog.
- if (!hasPendingErrorDialog() && !mAnswerFragment.hasPendingDialogs()) {
+ if (!hasPendingErrorDialog() && mAnswerFragment != null
+ && !mAnswerFragment.hasPendingDialogs()) {
super.finish();
}
}
@@ -301,14 +324,15 @@ public class InCallActivity extends Activity {
// BACK is also used to exit out of any "special modes" of the
// in-call UI:
- if (!mConferenceManagerFragment.isVisible() && !mCallCardFragment.isVisible()) {
+ if ((mConferenceManagerFragment == null || !mConferenceManagerFragment.isVisible())
+ && !mCallCardFragment.isVisible()) {
return;
}
if (mDialpadFragment != null && mDialpadFragment.isVisible()) {
mCallButtonFragment.displayDialpad(false /* show */, true /* animate */);
return;
- } else if (mConferenceManagerFragment.isVisible()) {
+ } else if (mConferenceManagerFragment != null && mConferenceManagerFragment.isVisible()) {
showConferenceCallManager(false);
return;
}
@@ -571,12 +595,6 @@ public class InCallActivity extends Activity {
mAnswerFragment = (AnswerFragment) mChildFragmentManager
.findFragmentById(R.id.answerFragment);
}
-
- if (mConferenceManagerFragment == null) {
- mConferenceManagerFragment = (ConferenceManagerFragment) getFragmentManager()
- .findFragmentById(R.id.conferenceManagerFragment);
- mConferenceManagerFragment.getView().setVisibility(View.INVISIBLE);
- }
}
public void dismissKeyguard(boolean dismiss) {
@@ -591,26 +609,79 @@ public class InCallActivity extends Activity {
}
}
- private void showDialpad(boolean showDialpad) {
- // If the dialpad is being shown and it has not already been loaded, replace the dialpad
- // placeholder with the actual fragment before continuing.
- if (mDialpadFragment == null && showDialpad) {
- final FragmentTransaction loadTransaction = mChildFragmentManager.beginTransaction();
- View fragmentContainer = findViewById(R.id.dialpadFragmentContainer);
- mDialpadFragment = new DialpadFragment();
- loadTransaction.replace(fragmentContainer.getId(), mDialpadFragment,
- DialpadFragment.class.getName());
- loadTransaction.commitAllowingStateLoss();
- mChildFragmentManager.executePendingTransactions();
+ private void showFragment(String tag, boolean show, boolean executeImmediately) {
+ final FragmentManager fm = getFragmentManagerForTag(tag);
+
+ if (fm == null) {
+ Log.w(TAG, "Fragment manager is null for : " + tag);
+ return;
+ }
+
+ Fragment fragment = fm.findFragmentByTag(tag);
+ if (!show && fragment == null) {
+ // Nothing to show, so bail early.
+ return;
}
- final FragmentTransaction ft = mChildFragmentManager.beginTransaction();
- if (showDialpad) {
- ft.show(mDialpadFragment);
+ final FragmentTransaction transaction = fm.beginTransaction();
+ if (show) {
+ if (fragment == null) {
+ fragment = createNewFragmentForTag(tag);
+ transaction.add(getContainerIdForFragment(tag), fragment, tag);
+ } else {
+ transaction.show(fragment);
+ }
} else {
- ft.hide(mDialpadFragment);
+ transaction.hide(fragment);
}
- ft.commitAllowingStateLoss();
+
+ transaction.commitAllowingStateLoss();
+ if (executeImmediately) {
+ fm.executePendingTransactions();
+ }
+ }
+
+ private Fragment createNewFragmentForTag(String tag) {
+ if (TAG_DIALPAD_FRAGMENT.equals(tag)) {
+ mDialpadFragment = new DialpadFragment();
+ return mDialpadFragment;
+ } else if (TAG_ANSWER_FRAGMENT.equals(tag)) {
+ mAnswerFragment = new AnswerFragment();
+ return mAnswerFragment;
+ } else if (TAG_CONFERENCE_FRAGMENT.equals(tag)) {
+ mConferenceManagerFragment = new ConferenceManagerFragment();
+ return mConferenceManagerFragment;
+ } else if (TAG_CALLCARD_FRAGMENT.equals(tag)) {
+ mCallCardFragment = new CallCardFragment();
+ return mCallCardFragment;
+ }
+ throw new IllegalStateException("Unexpected fragment: " + tag);
+ }
+
+ private FragmentManager getFragmentManagerForTag(String tag) {
+ if (TAG_DIALPAD_FRAGMENT.equals(tag)) {
+ return mChildFragmentManager;
+ } else if (TAG_ANSWER_FRAGMENT.equals(tag)) {
+ return mChildFragmentManager;
+ } else if (TAG_CONFERENCE_FRAGMENT.equals(tag)) {
+ return getFragmentManager();
+ } else if (TAG_CALLCARD_FRAGMENT.equals(tag)) {
+ return getFragmentManager();
+ }
+ throw new IllegalStateException("Unexpected fragment: " + tag);
+ }
+
+ private int getContainerIdForFragment(String tag) {
+ if (TAG_DIALPAD_FRAGMENT.equals(tag)) {
+ return R.id.dialpadFragmentContainer;
+ } else if (TAG_ANSWER_FRAGMENT.equals(tag)) {
+ return R.id.dialpadFragmentContainer;
+ } else if (TAG_CONFERENCE_FRAGMENT.equals(tag)) {
+ return R.id.main;
+ } else if (TAG_CALLCARD_FRAGMENT.equals(tag)) {
+ return R.id.main;
+ }
+ throw new IllegalStateException("Unexpected fragment: " + tag);
}
public void displayDialpad(boolean showDialpad, boolean animate) {
@@ -621,10 +692,10 @@ public class InCallActivity extends Activity {
// We don't do a FragmentTransaction on the hide case because it will be dealt with when
// the listener is fired after an animation finishes.
if (!animate) {
- showDialpad(showDialpad);
+ showFragment(TAG_DIALPAD_FRAGMENT, showDialpad, true);
} else {
if (showDialpad) {
- showDialpad(true);
+ showFragment(TAG_DIALPAD_FRAGMENT, true, true);
mDialpadFragment.animateShowDialpad();
}
mCallCardFragment.onDialpadVisiblityChange(showDialpad);
@@ -645,7 +716,8 @@ public class InCallActivity extends Activity {
* should be hidden.
*/
public void showConferenceCallManager(boolean show) {
- mConferenceManagerFragment.setVisible(show);
+ showFragment(TAG_CONFERENCE_FRAGMENT, show, true);
+ mConferenceManagerFragment.onVisibilityChanged(show);
// Need to hide the call card fragment to ensure that accessibility service does not try to
// give focus to the call card when the conference manager is visible.
@@ -690,7 +762,9 @@ public class InCallActivity extends Activity {
mDialog.dismiss();
mDialog = null;
}
- mAnswerFragment.dismissPendingDialogues();
+ if (mAnswerFragment != null) {
+ mAnswerFragment.dismissPendingDialogs();
+ }
}
/**