Add facility to switch to new fragments from preferences.

Change-Id: I009315b59cf81b4962e9c5a4490f0f82743ed64a
This commit is contained in:
Dianne Hackborn
2010-08-03 13:07:11 -07:00
parent 6c8687cf1e
commit b3cf10ffa8
8 changed files with 192 additions and 24 deletions

View File

@@ -133430,6 +133430,17 @@
visibility="public"
>
</method>
<method name="getFragment"
return="java.lang.String"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</method>
<method name="getIntent"
return="android.content.Intent"
abstract="false"
@@ -133992,6 +134003,19 @@
<parameter name="enabled" type="boolean">
</parameter>
</method>
<method name="setFragment"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="fragment" type="java.lang.String">
</parameter>
</method>
<method name="setIntent"
return="void"
abstract="false"
@@ -134310,6 +134334,8 @@
deprecated="not deprecated"
visibility="public"
>
<implements name="android.preference.PreferenceFragment.OnPreferenceStartFragmentCallback">
</implements>
<constructor name="PreferenceActivity"
type="android.preference.PreferenceActivity"
static="false"
@@ -134455,6 +134481,21 @@
visibility="public"
>
</method>
<method name="onPreferenceStartFragment"
return="boolean"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="caller" type="android.preference.PreferenceFragment">
</parameter>
<parameter name="pref" type="android.preference.Preference">
</parameter>
</method>
<method name="onPreferenceTreeClick"
return="boolean"
abstract="false"
@@ -134678,6 +134719,29 @@
</parameter>
</method>
</class>
<interface name="PreferenceFragment.OnPreferenceStartFragmentCallback"
abstract="true"
static="true"
final="false"
deprecated="not deprecated"
visibility="public"
>
<method name="onPreferenceStartFragment"
return="boolean"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="caller" type="android.preference.PreferenceFragment">
</parameter>
<parameter name="pref" type="android.preference.Preference">
</parameter>
</method>
</interface>
<class name="PreferenceGroup"
extends="android.preference.Preference"
abstract="true"
@@ -266144,7 +266208,7 @@
deprecated="not deprecated"
visibility="public"
>
<parameter name="fileName" type="java.lang.String">
<parameter name="filename" type="java.lang.String">
</parameter>
</method>
</interface>

View File

@@ -2055,9 +2055,10 @@ public class Activity extends ContextThemeWrapper
/**
* Flag for {@link #popBackStack(String, int)}
* and {@link #popBackStack(int, int)}: If set, and the name or ID of
* a back stack entry has been supplied, then that entry will also be
* removed. Otherwise, all entries up to but not including that entry
* will be removed
* a back stack entry has been supplied, then all matching entries will
* be consumed until one that doesn't match is found or the bottom of
* the stack is reached. Otherwise, all entries up to but not including that entry
* will be removed.
*/
public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
@@ -2066,7 +2067,7 @@ public class Activity extends ContextThemeWrapper
* to pop, else false.
*/
public boolean popBackStack() {
return popBackStack(null, 0);
return popBackStack(null, -1);
}
/**

View File

@@ -629,7 +629,7 @@ public class FragmentManager {
if (mBackStack == null) {
return false;
}
if (name == null && id < 0) {
if (name == null && id < 0 && (flags&Activity.POP_BACK_STACK_INCLUSIVE) == 0) {
int last = mBackStack.size()-1;
if (last < 0) {
return false;
@@ -644,22 +644,37 @@ public class FragmentManager {
}
});
} else {
int index = mBackStack.size()-1;
while (index >= 0) {
BackStackEntry bss = mBackStack.get(index);
if (name != null && name.equals(bss.getName())) {
break;
int index = -1;
if (name != null || id >= 0) {
// If a name or ID is specified, look for that place in
// the stack.
index = mBackStack.size()-1;
while (index >= 0) {
BackStackEntry bss = mBackStack.get(index);
if (name != null && name.equals(bss.getName())) {
break;
}
if (id >= 0 && id == bss.mIndex) {
break;
}
index--;
}
if (id >= 0 && id == bss.mIndex) {
break;
if (index < 0) {
return false;
}
if ((flags&Activity.POP_BACK_STACK_INCLUSIVE) != 0) {
index--;
// Consume all following entries that match.
while (index >= 0) {
BackStackEntry bss = mBackStack.get(index);
if ((name != null && name.equals(bss.getName()))
|| (id >= 0 && id == bss.mIndex)) {
index--;
continue;
}
break;
}
}
index--;
}
if (index < 0) {
return false;
}
if ((flags&Activity.POP_BACK_STACK_INCLUSIVE) != 0) {
index--;
}
if (index == mBackStack.size()-1) {
return false;

View File

@@ -56,6 +56,7 @@ import java.util.Set;
* @attr ref android.R.styleable#Preference_title
* @attr ref android.R.styleable#Preference_summary
* @attr ref android.R.styleable#Preference_order
* @attr ref android.R.styleable#Preference_fragment
* @attr ref android.R.styleable#Preference_layout
* @attr ref android.R.styleable#Preference_widgetLayout
* @attr ref android.R.styleable#Preference_enabled
@@ -88,6 +89,7 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
private CharSequence mSummary;
private String mKey;
private Intent mIntent;
private String mFragment;
private boolean mEnabled = true;
private boolean mSelectable = true;
private boolean mRequiresKey;
@@ -210,6 +212,10 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
mOrder = a.getInt(attr, mOrder);
break;
case com.android.internal.R.styleable.Preference_fragment:
mFragment = a.getString(attr);
break;
case com.android.internal.R.styleable.Preference_layout:
mLayoutResId = a.getResourceId(attr, mLayoutResId);
break;
@@ -314,6 +320,24 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
return mIntent;
}
/**
* Sets the class name of a fragment to be shown when this Preference is clicked.
*
* @param fragment The class name of the fragment associated with this Preference.
*/
public void setFragment(String fragment) {
mFragment = fragment;
}
/**
* Return the fragment class name associated with this Preference.
*
* @return The fragment class name last set via {@link #setFragment} or XML.
*/
public String getFragment() {
return mFragment;
}
/**
* Sets the layout resource that is inflated as the {@link View} to be shown
* for this Preference. In most cases, the default layout is sufficient for

View File

@@ -93,11 +93,22 @@ import java.util.List;
*
* {@sample development/samples/ApiDemos/res/xml/preference_headers.xml headers}
*
* See {@link PreferenceFragment} for information on implementing the
* <p>The first header is shown by Prefs1Fragment, which populates itself
* from the following XML resource:</p>
*
* {@sample development/samples/ApiDemos/res/xml/fragmented_preferences.xml preferences}
*
* <p>Note that this XML resource contains a preference screen holding another
* fragment, the Prefs1FragmentInner implemented here. This allows the user
* to traverse down a hierarchy of preferences; pressing back will pop each
* fragment off the stack to return to the previous preferences.
*
* <p>See {@link PreferenceFragment} for information on implementing the
* fragments themselves.
*/
public abstract class PreferenceActivity extends ListActivity implements
PreferenceManager.OnPreferenceTreeClickListener {
PreferenceManager.OnPreferenceTreeClickListener,
PreferenceFragment.OnPreferenceStartFragmentCallback {
private static final String TAG = "PreferenceActivity";
private static final String PREFERENCES_TAG = "android:preferences";
@@ -106,6 +117,8 @@ public abstract class PreferenceActivity extends ListActivity implements
private static final String EXTRA_PREFS_NO_HEADERS = ":android:no_headers";
private static final String BACK_STACK_PREFS = ":android:prefs";
// extras that allow any preference activity to be launched as part of a wizard
// show Back and Next buttons? takes boolean parameter
@@ -206,16 +219,19 @@ public abstract class PreferenceActivity extends ListActivity implements
public static class Header {
/**
* Title of the header that is shown to the user.
* @attr ref android.R.styleable#PreferenceHeader_title
*/
CharSequence title;
/**
* Optional summary describing what this header controls.
* @attr ref android.R.styleable#PreferenceHeader_summary
*/
CharSequence summary;
/**
* Optional icon resource to show for this header.
* @attr ref android.R.styleable#PreferenceHeader_icon
*/
int iconRes;
@@ -228,6 +244,7 @@ public abstract class PreferenceActivity extends ListActivity implements
/**
* Full class name of the fragment to display when this header is
* selected.
* @attr ref android.R.styleable#PreferenceHeader_fragment
*/
String fragment;
}
@@ -551,6 +568,8 @@ public abstract class PreferenceActivity extends ListActivity implements
* @param fragmentName The name of the fragment to display.
*/
public void switchToHeader(String fragmentName) {
popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
Fragment f;
try {
f = Fragment.instantiate(this, fragmentName);
@@ -561,6 +580,20 @@ public abstract class PreferenceActivity extends ListActivity implements
openFragmentTransaction().replace(com.android.internal.R.id.prefs, f).commit();
}
@Override
public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
Fragment f;
try {
f = Fragment.instantiate(this, pref.getFragment());
} catch (Exception e) {
Log.w(TAG, "Failure instantiating fragment " + pref.getFragment(), e);
return false;
}
openFragmentTransaction().replace(com.android.internal.R.id.prefs, f)
.addToBackStack(BACK_STACK_PREFS).commit();
return true;
}
/**
* Posts a message to bind the preferences to the list view.
* <p>

View File

@@ -125,6 +125,21 @@ public abstract class PreferenceFragment extends Fragment implements
}
};
/**
* Interface that PreferenceFragment's containing activity should
* implement to be able to process preference items that wish to
* switch to a new fragment.
*/
public interface OnPreferenceStartFragmentCallback {
/**
* Called when the user has clicked on a Preference that has
* a fragment class name associated with it. The implementation
* to should instantiate and switch to an instance of the given
* fragment.
*/
boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -167,6 +182,13 @@ public abstract class PreferenceFragment extends Fragment implements
mPreferenceManager.dispatchActivityStop();
}
@Override
public void onDestroyView() {
mList = null;
mHandler.removeCallbacks(mRequestFocus);
super.onDestroyView();
}
@Override
public void onDestroy() {
super.onDestroy();
@@ -251,7 +273,13 @@ public abstract class PreferenceFragment extends Fragment implements
/**
* {@inheritDoc}
*/
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
if (preference.getFragment() != null &&
getActivity() instanceof OnPreferenceStartFragmentCallback) {
return ((OnPreferenceStartFragmentCallback)getActivity()).onPreferenceStartFragment(
this, preference);
}
return false;
}

View File

@@ -136,7 +136,7 @@ public final class PreferenceScreen extends PreferenceGroup implements AdapterVi
@Override
protected void onClick() {
if (getIntent() != null || getPreferenceCount() == 0) {
if (getIntent() != null || getFragment() != null || getPreferenceCount() == 0) {
return;
}

View File

@@ -3457,6 +3457,9 @@
<!-- The order for the Preference (lower values are to be ordered first). If this is not
specified, the default orderin will be alphabetic. -->
<attr name="order" format="integer" />
<!-- When used inside of a modern PreferenceActivity, this declares
a new PreferenceFragment to be shown when the user selects this item. -->
<attr name="fragment" />
<!-- The layout for the Preference in a PreferenceActivity screen. This should
rarely need to be changed, look at widgetLayout instead. -->
<attr name="layout" />