diff options
author | Yorke Lee <yorkelee@google.com> | 2015-03-09 19:22:12 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-03-09 19:22:13 +0000 |
commit | 6a1fc98fde55f951eaf25face7d9ff315755b8f0 (patch) | |
tree | faaf9431bbb026b45b2184edc4af77bd4527c2ba | |
parent | 5de2a2fed96440ef04e84d24018708a975ad605c (diff) | |
parent | 979f38e37da9bdd4c51aceafe7bcc44b305e3d02 (diff) |
Merge "Improve InCallUI fragment management"
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(); + } } /** |