From 8eb3f0fbf2ced7291167755fe74ce50164eb3a9e Mon Sep 17 00:00:00 2001 From: Fabrice Di Meglio Date: Thu, 27 Feb 2014 15:51:46 -0800 Subject: [PATCH] Fix Fragment BackStack and Titles Related to bug #12939786 and bug #13223838 - first use Fragment BreadCrumb for managing Titles and Back - consider the first fragment as the initial one (both in the normal case and in the shortcut one) - fix usage of the Fragment BackStack so that in all cases we are returning to the initial Fragment before exiting the App. Change-Id: I96989d14f4e88688747b93ab9fadd96aea214a2c --- .../android/settings/SettingsActivity.java | 164 ++++++------------ 1 file changed, 57 insertions(+), 107 deletions(-) diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 443013899f4..b7d29fa7b35 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -62,10 +62,8 @@ import android.support.v4.widget.DrawerLayout; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; -import android.util.Pair; import android.util.TypedValue; import android.util.Xml; -import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -200,6 +198,8 @@ public class SettingsActivity extends Activity private Header mSelectedHeader; private Header mCurrentHeader; + private CharSequence mInitialTitle; + // Show only these settings for restricted users private int[] SETTINGS_FOR_RESTRICTED = { R.id.wireless_section, @@ -313,39 +313,6 @@ public class SettingsActivity extends Activity private final ArrayList
mHeaders = new ArrayList
(); private HeaderAdapter mHeaderAdapter; - static private class TitlePair extends Pair implements Parcelable { - - public TitlePair(Integer first, CharSequence second) { - super(first, second); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(first); - TextUtils.writeToParcel(second, dest, flags); - } - - TitlePair(Parcel in) { - super(in.readInt(), TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in)); - } - - public static final Creator CREATOR = new Creator() { - public TitlePair createFromParcel(Parcel source) { - return new TitlePair(source); - } - public TitlePair[] newArray(int size) { - return new TitlePair[size]; - } - }; - } - - private final ArrayList mTitleStack = new ArrayList(); - private DrawerLayout mDrawerLayout; private ListView mDrawer; private ActionBarDrawerToggle mDrawerToggle; @@ -408,7 +375,7 @@ public class SettingsActivity extends Activity if (isFinishing() || mSelectedHeader == null) { return; } - switchToHeader(mSelectedHeader, false); + switchToHeader(mSelectedHeader, false, false); mSelectedHeader = null; } @@ -556,17 +523,8 @@ public class SettingsActivity extends Activity if (savedInstanceState != null) { // We are restarting from a previous saved state; used that to // initialize, instead of starting fresh. - - ArrayList titles = - savedInstanceState.getParcelableArrayList(SAVE_KEY_TITLES_TAG); - if (titles != null) { - mTitleStack.addAll(titles); - } - final int lastTitle = mTitleStack.size() - 1; - if (lastTitle >= 0) { - final TitlePair last = mTitleStack.get(lastTitle); - setTitleFromPair(last); - } + mInitialTitle = getTitle(); + setTitleFromBackStack(); ArrayList
headers = savedInstanceState.getParcelableArrayList(SAVE_KEY_HEADERS_TAG); @@ -578,18 +536,15 @@ public class SettingsActivity extends Activity setSelectedHeader(mHeaders.get(curHeader)); } } - } else { if (initialFragment != null) { // If we are just showing a fragment, we want to run in // new fragment mode, but don't need to compute and show // the headers. - switchToHeader(initialFragment, initialArguments, true); + final int initialTitleResId = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0); + mInitialTitle = (initialTitleResId > 0) ? getText(initialTitleResId) : getTitle(); - final int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0); - if (initialTitle != 0) { - setTitle(getText(initialTitle)); - } + switchToHeader(initialFragment, initialArguments, true, mInitialTitle); } else { // We need to try to build the headers. onBuildHeaders(mHeaders); @@ -599,7 +554,8 @@ public class SettingsActivity extends Activity // the currently selected preference fragment. if (mHeaders.size() > 0) { Header h = onGetInitialHeader(); - switchToHeader(h, false); + mInitialTitle = getHeaderTitle(h); + switchToHeader(h, false, true); } } } @@ -666,32 +622,30 @@ public class SettingsActivity extends Activity @Override public void onBackStackChanged() { - final int count = getFragmentManager().getBackStackEntryCount() + 1; - TitlePair pair = null; - int last; - while (mTitleStack.size() > count) { - last = mTitleStack.size() - 1; - pair = mTitleStack.remove(last); - } - // Check if we go back - if (pair != null) { - int size = mTitleStack.size(); - if (size > 0) { - last = mTitleStack.size() - 1; - pair = mTitleStack.get(last); - setTitleFromPair(pair); - } - } + setTitleFromBackStack(); } - private void setTitleFromPair(TitlePair pair) { - final CharSequence title; - if (pair.first > 0) { - title = getText(pair.first); - } else { - title = pair.second; + private void setTitleFromBackStack() { + final int count = getFragmentManager().getBackStackEntryCount(); + if (count == 0) { + setTitle(mInitialTitle); + return; + } + FragmentManager.BackStackEntry bse = getFragmentManager().getBackStackEntryAt(count - 1); + setTitleFromBackStackEntry(bse); + } + + private void setTitleFromBackStackEntry(FragmentManager.BackStackEntry bse) { + final CharSequence title; + final int titleRes = bse.getBreadCrumbTitleRes(); + if (titleRes > 0) { + title = getText(titleRes); + } else { + title = bse.getBreadCrumbTitle(); + } + if (title != null) { + setTitle(title); } - setTitle(title); } /** @@ -714,10 +668,6 @@ public class SettingsActivity extends Activity } } } - - if (mTitleStack.size() > 0) { - outState.putParcelableList(SAVE_KEY_TITLES_TAG, mTitleStack); - } } @Override @@ -782,9 +732,10 @@ public class SettingsActivity extends Activity * preference fragment. * * @param header The new header to display. - * @param validate true means that the fragment's Header needs to be validated + * @param validate true means that the fragment's Header needs to be validated. + * @param initial true means that it is the initial Header. */ - private void switchToHeader(Header header, boolean validate) { + private void switchToHeader(Header header, boolean validate, boolean initial) { if (header == null) { return; } @@ -798,15 +749,11 @@ public class SettingsActivity extends Activity FragmentManager.POP_BACK_STACK_INCLUSIVE); } else { if (header.fragment != null) { - mTitleStack.clear(); - switchToHeaderInner(header.fragment, header.fragmentArguments, validate); + switchToHeaderInner(header.fragment, header.fragmentArguments, validate, !initial, + getHeaderTitle(header)); setSelectedHeader(header); - final TitlePair pair = new TitlePair(0, getHeaderTitle(header)); - mTitleStack.add(pair); - setTitle(pair.second); } else if (header.intent != null) { setSelectedHeader(header); - mTitleStack.clear(); startActivity(header.intent); } else { throw new IllegalStateException( @@ -860,19 +807,20 @@ public class SettingsActivity extends Activity } /** - * When in two-pane mode, switch the fragment pane to show the given - * preference fragment. + * Switch the fragment pane to show the given preference fragment. * * @param fragmentName The name of the fragment to display. * @param args Optional arguments to supply to the fragment. * @param validate true means that the fragment's Header needs to be validated */ - private void switchToHeader(String fragmentName, Bundle args, boolean validate) { + private void switchToHeader(String fragmentName, Bundle args, boolean validate, + CharSequence title) { setSelectedHeader(null); - switchToHeaderInner(fragmentName, args, validate); + switchToHeaderInner(fragmentName, args, validate, false, title); } - private void switchToHeaderInner(String fragmentName, Bundle args, boolean validate) { + private void switchToHeaderInner(String fragmentName, Bundle args, boolean validate, + boolean addToBackStack, CharSequence title) { getFragmentManager().popBackStack(BACK_STACK_PREFS, FragmentManager.POP_BACK_STACK_INCLUSIVE); if (validate && !isValidFragment(fragmentName)) { @@ -881,8 +829,14 @@ public class SettingsActivity extends Activity } Fragment f = Fragment.instantiate(this, fragmentName, args); FragmentTransaction transaction = getFragmentManager().beginTransaction(); - transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); transaction.replace(R.id.prefs, f); + transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); + if (addToBackStack) { + transaction.addToBackStack(BACK_STACK_PREFS); + } + if (title != null) { + transaction.setBreadCrumbTitle(title); + } transaction.commitAllowingStateLoss(); } @@ -1036,6 +990,13 @@ public class SettingsActivity extends Activity */ private void startWithFragment(String fragmentName, Bundle args, Fragment resultTo, int resultRequestCode, int titleRes, CharSequence titleText) { + final CharSequence cs; + if (titleRes != 0) { + cs = getText(titleRes); + } else { + cs = titleText; + } + Fragment f = Fragment.instantiate(this, fragmentName, args); if (resultTo != null) { f.setTargetFragment(resultTo, resultRequestCode); @@ -1044,19 +1005,8 @@ public class SettingsActivity extends Activity transaction.replace(R.id.prefs, f); transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); transaction.addToBackStack(BACK_STACK_PREFS); + transaction.setBreadCrumbTitle(cs); transaction.commitAllowingStateLoss(); - - final TitlePair pair; - final CharSequence cs; - if (titleRes != 0) { - pair = new TitlePair(titleRes, null); - cs = getText(titleRes); - } else { - pair = new TitlePair(0, titleText); - cs = titleText; - } - setTitle(cs); - mTitleStack.add(pair); } /**