diff options
| author | Dianne Hackborn <hackbod@google.com> | 2010-09-16 01:33:24 -0700 |
|---|---|---|
| committer | Dianne Hackborn <hackbod@google.com> | 2010-09-16 18:36:04 -0700 |
| commit | c6669ca63299219d815464129dac051ab2404286 (patch) | |
| tree | 88eb6d56bb3070db2eaad9e6ed94f233e91d4e73 | |
| parent | 10a96daf7fefb2c1e6381ea233f2aac3fae2869c (diff) | |
| download | frameworks_base-c6669ca63299219d815464129dac051ab2404286.zip frameworks_base-c6669ca63299219d815464129dac051ab2404286.tar.gz frameworks_base-c6669ca63299219d815464129dac051ab2404286.tar.bz2 | |
Add API for showing breadcrumbs of fragment back stack.
This adds a simple API to have your back stack automatically
shown as bread crumbs in the action bar. Introduces some APIs
to retrieve the current back stack.
Also fix a little bug in the "activated" state where it was
being propagated down the hierarchy as "selected". :p And from
that, fix the standard colors to be reasonable when in the
activated state.
Finally PreferenceActivity is updated to take advantage of
bread crumbs to show your place in the preferences.
Change-Id: I9d633bedf8d7c6e4ed9b25cb9698faa66c7dd9a4
26 files changed, 1038 insertions, 86 deletions
diff --git a/api/current.xml b/api/current.xml index 279744e..ccd1724 100644 --- a/api/current.xml +++ b/api/current.xml @@ -2792,6 +2792,28 @@ visibility="public" > </field> +<field name="breadCrumbShortTitle" + type="int" + transient="false" + volatile="false" + value="16843589" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="breadCrumbTitle" + type="int" + transient="false" + volatile="false" + value="16843588" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="bufferType" type="int" transient="false" @@ -17384,6 +17406,17 @@ visibility="public" > </field> +<field name="Widget_FragmentBreadCrumbs" + type="int" + transient="false" + volatile="false" + value="16973986" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Widget_Gallery" type="int" transient="false" @@ -29343,6 +29376,113 @@ </parameter> </constructor> </class> +<class name="FragmentBreadCrumbs" + extends="android.view.ViewGroup" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.app.FragmentManager.OnBackStackChangedListener"> +</implements> +<constructor name="FragmentBreadCrumbs" + type="android.app.FragmentBreadCrumbs" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="context" type="android.content.Context"> +</parameter> +</constructor> +<constructor name="FragmentBreadCrumbs" + type="android.app.FragmentBreadCrumbs" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="context" type="android.content.Context"> +</parameter> +<parameter name="attrs" type="android.util.AttributeSet"> +</parameter> +</constructor> +<constructor name="FragmentBreadCrumbs" + type="android.app.FragmentBreadCrumbs" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="context" type="android.content.Context"> +</parameter> +<parameter name="attrs" type="android.util.AttributeSet"> +</parameter> +<parameter name="defStyle" type="int"> +</parameter> +</constructor> +<method name="onBackStackChanged" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="onLayout" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="protected" +> +<parameter name="changed" type="boolean"> +</parameter> +<parameter name="l" type="int"> +</parameter> +<parameter name="t" type="int"> +</parameter> +<parameter name="r" type="int"> +</parameter> +<parameter name="b" type="int"> +</parameter> +</method> +<method name="setActivity" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="a" type="android.app.Activity"> +</parameter> +</method> +<method name="setTitle" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="title" type="java.lang.CharSequence"> +</parameter> +<parameter name="shortTitle" type="java.lang.CharSequence"> +</parameter> +</method> +</class> <interface name="FragmentManager" abstract="true" static="false" @@ -29350,6 +29490,30 @@ deprecated="not deprecated" visibility="public" > +<method name="addOnBackStackChangedListener" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="listener" type="android.app.FragmentManager.OnBackStackChangedListener"> +</parameter> +</method> +<method name="countBackStackEntries" + return="int" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="findFragmentById" return="android.app.Fragment" abstract="true" @@ -29376,6 +29540,19 @@ <parameter name="tag" type="java.lang.String"> </parameter> </method> +<method name="getBackStackEntry" + return="android.app.FragmentManager.BackStackEntry" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="index" type="int"> +</parameter> +</method> <method name="getFragment" return="android.app.Fragment" abstract="true" @@ -29460,6 +29637,19 @@ <parameter name="fragment" type="android.app.Fragment"> </parameter> </method> +<method name="removeOnBackStackChangedListener" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="listener" type="android.app.FragmentManager.OnBackStackChangedListener"> +</parameter> +</method> <field name="POP_BACK_STACK_INCLUSIVE" type="int" transient="false" @@ -29472,6 +29662,66 @@ > </field> </interface> +<interface name="FragmentManager.BackStackEntry" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="getBreadCrumbShortTitle" + return="java.lang.CharSequence" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getBreadCrumbTitle" + return="java.lang.CharSequence" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getId" + return="int" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +</interface> +<interface name="FragmentManager.OnBackStackChangedListener" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="onBackStackChanged" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +</interface> <interface name="FragmentTransaction" abstract="true" static="false" @@ -29619,6 +29869,58 @@ <parameter name="tag" type="java.lang.String"> </parameter> </method> +<method name="setBreadCrumbShortTitle" + return="android.app.FragmentTransaction" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="res" type="int"> +</parameter> +</method> +<method name="setBreadCrumbShortTitle" + return="android.app.FragmentTransaction" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="text" type="java.lang.CharSequence"> +</parameter> +</method> +<method name="setBreadCrumbTitle" + return="android.app.FragmentTransaction" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="res" type="int"> +</parameter> +</method> +<method name="setBreadCrumbTitle" + return="android.app.FragmentTransaction" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="text" type="java.lang.CharSequence"> +</parameter> +</method> <method name="setCustomAnimations" return="android.app.FragmentTransaction" abstract="true" @@ -142369,6 +142671,21 @@ <parameter name="preferenceScreen" type="android.preference.PreferenceScreen"> </parameter> </method> +<method name="showBreadCrumbs" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="title" type="java.lang.CharSequence"> +</parameter> +<parameter name="shortTitle" type="java.lang.CharSequence"> +</parameter> +</method> <method name="startPreferenceFragment" return="void" abstract="false" @@ -142384,6 +142701,21 @@ <parameter name="push" type="boolean"> </parameter> </method> +<method name="startPreferenceFragment" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fragment" type="android.app.Fragment"> +</parameter> +<parameter name="ft" type="android.app.FragmentTransaction"> +</parameter> +</method> <method name="startWithFragment" return="void" abstract="false" @@ -142427,6 +142759,21 @@ <parameter name="header" type="android.preference.PreferenceActivity.Header"> </parameter> </method> +<method name="switchToHeaderInner" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fragmentName" type="java.lang.String"> +</parameter> +<parameter name="args" type="android.os.Bundle"> +</parameter> +</method> <field name="EXTRA_NO_HEADERS" type="java.lang.String" transient="false" @@ -142539,6 +142886,26 @@ visibility="public" > </field> +<field name="breadCrumbShortTitle" + type="java.lang.CharSequence" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="breadCrumbTitle" + type="java.lang.CharSequence" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="extras" type="android.os.Bundle" transient="false" diff --git a/core/java/android/app/BackStackEntry.java b/core/java/android/app/BackStackRecord.java index 296b495..e6cc0f9 100644 --- a/core/java/android/app/BackStackEntry.java +++ b/core/java/android/app/BackStackRecord.java @@ -18,6 +18,7 @@ package android.app; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import android.util.Log; import java.util.ArrayList; @@ -28,16 +29,20 @@ final class BackStackState implements Parcelable { final int mTransitionStyle; final String mName; final int mIndex; - - public BackStackState(FragmentManagerImpl fm, BackStackEntry bse) { + final int mBreadCrumbTitleRes; + final CharSequence mBreadCrumbTitleText; + final int mBreadCrumbShortTitleRes; + final CharSequence mBreadCrumbShortTitleText; + + public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) { int numRemoved = 0; - BackStackEntry.Op op = bse.mHead; + BackStackRecord.Op op = bse.mHead; while (op != null) { if (op.removed != null) numRemoved += op.removed.size(); op = op.next; } mOps = new int[bse.mNumOp*5 + numRemoved]; - + if (!bse.mAddToBackStack) { throw new IllegalStateException("Not on back stack"); } @@ -64,21 +69,29 @@ final class BackStackState implements Parcelable { mTransitionStyle = bse.mTransitionStyle; mName = bse.mName; mIndex = bse.mIndex; + mBreadCrumbTitleRes = bse.mBreadCrumbTitleRes; + mBreadCrumbTitleText = bse.mBreadCrumbTitleText; + mBreadCrumbShortTitleRes = bse.mBreadCrumbShortTitleRes; + mBreadCrumbShortTitleText = bse.mBreadCrumbShortTitleText; } - + public BackStackState(Parcel in) { mOps = in.createIntArray(); mTransition = in.readInt(); mTransitionStyle = in.readInt(); mName = in.readString(); mIndex = in.readInt(); + mBreadCrumbTitleRes = in.readInt(); + mBreadCrumbTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mBreadCrumbShortTitleRes = in.readInt(); + mBreadCrumbShortTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); } - - public BackStackEntry instantiate(FragmentManagerImpl fm) { - BackStackEntry bse = new BackStackEntry(fm); + + public BackStackRecord instantiate(FragmentManagerImpl fm) { + BackStackRecord bse = new BackStackRecord(fm); int pos = 0; while (pos < mOps.length) { - BackStackEntry.Op op = new BackStackEntry.Op(); + BackStackRecord.Op op = new BackStackRecord.Op(); op.cmd = mOps[pos++]; if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG, "BSE " + bse + " set base fragment #" + mOps[pos]); @@ -103,10 +116,14 @@ final class BackStackState implements Parcelable { bse.mName = mName; bse.mIndex = mIndex; bse.mAddToBackStack = true; + bse.mBreadCrumbTitleRes = mBreadCrumbTitleRes; + bse.mBreadCrumbTitleText = mBreadCrumbTitleText; + bse.mBreadCrumbShortTitleRes = mBreadCrumbShortTitleRes; + bse.mBreadCrumbShortTitleText = mBreadCrumbShortTitleText; bse.bumpBackStackNesting(1); return bse; } - + public int describeContents() { return 0; } @@ -117,14 +134,18 @@ final class BackStackState implements Parcelable { dest.writeInt(mTransitionStyle); dest.writeString(mName); dest.writeInt(mIndex); + dest.writeInt(mBreadCrumbTitleRes); + TextUtils.writeToParcel(mBreadCrumbTitleText, dest, 0); + dest.writeInt(mBreadCrumbShortTitleRes); + TextUtils.writeToParcel(mBreadCrumbShortTitleText, dest, 0); } - + public static final Parcelable.Creator<BackStackState> CREATOR = new Parcelable.Creator<BackStackState>() { public BackStackState createFromParcel(Parcel in) { return new BackStackState(in); } - + public BackStackState[] newArray(int size) { return new BackStackState[size]; } @@ -134,18 +155,19 @@ final class BackStackState implements Parcelable { /** * @hide Entry of an operation on the fragment back stack. */ -final class BackStackEntry implements FragmentTransaction, Runnable { +final class BackStackRecord implements FragmentTransaction, + FragmentManager.BackStackEntry, Runnable { static final String TAG = "BackStackEntry"; - + final FragmentManagerImpl mManager; - + static final int OP_NULL = 0; static final int OP_ADD = 1; static final int OP_REPLACE = 2; static final int OP_REMOVE = 3; static final int OP_HIDE = 4; static final int OP_SHOW = 5; - + static final class Op { Op next; Op prev; @@ -155,7 +177,7 @@ final class BackStackEntry implements FragmentTransaction, Runnable { int exitAnim; ArrayList<Fragment> removed; } - + Op mHead; Op mTail; int mNumOp; @@ -167,11 +189,34 @@ final class BackStackEntry implements FragmentTransaction, Runnable { String mName; boolean mCommitted; int mIndex; - - public BackStackEntry(FragmentManagerImpl manager) { + + int mBreadCrumbTitleRes; + CharSequence mBreadCrumbTitleText; + int mBreadCrumbShortTitleRes; + CharSequence mBreadCrumbShortTitleText; + + public BackStackRecord(FragmentManagerImpl manager) { mManager = manager; } - + + public int getId() { + return mIndex; + } + + public CharSequence getBreadCrumbTitle() { + if (mBreadCrumbTitleRes != 0) { + return mManager.mActivity.getText(mBreadCrumbTitleRes); + } + return mBreadCrumbTitleText; + } + + public CharSequence getBreadCrumbShortTitle() { + if (mBreadCrumbShortTitleRes != 0) { + return mManager.mActivity.getText(mBreadCrumbShortTitleRes); + } + return mBreadCrumbShortTitleText; + } + void addOp(Op op) { if (mHead == null) { mHead = mTail = op; @@ -184,7 +229,7 @@ final class BackStackEntry implements FragmentTransaction, Runnable { op.exitAnim = mExitAnim; mNumOp++; } - + public FragmentTransaction add(Fragment fragment, String tag) { doAddOp(0, fragment, tag, OP_ADD); return this; @@ -206,7 +251,7 @@ final class BackStackEntry implements FragmentTransaction, Runnable { } fragment.mImmediateActivity = mManager.mActivity; fragment.mFragmentManager = mManager; - + if (tag != null) { if (fragment.mTag != null && !tag.equals(fragment.mTag)) { throw new IllegalStateException("Can't change tag of fragment " @@ -215,7 +260,7 @@ final class BackStackEntry implements FragmentTransaction, Runnable { } fragment.mTag = tag; } - + if (containerViewId != 0) { if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) { throw new IllegalStateException("Can't change container ID of fragment " @@ -224,7 +269,7 @@ final class BackStackEntry implements FragmentTransaction, Runnable { } fragment.mContainerId = fragment.mFragmentId = containerViewId; } - + Op op = new Op(); op.cmd = opcmd; op.fragment = fragment; @@ -234,27 +279,27 @@ final class BackStackEntry implements FragmentTransaction, Runnable { public FragmentTransaction replace(int containerViewId, Fragment fragment) { return replace(containerViewId, fragment, null); } - + public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) { if (containerViewId == 0) { throw new IllegalArgumentException("Must use non-zero containerViewId"); } - + doAddOp(containerViewId, fragment, tag, OP_REPLACE); return this; } - + public FragmentTransaction remove(Fragment fragment) { if (fragment.mImmediateActivity == null) { throw new IllegalStateException("Fragment not added: " + fragment); } fragment.mImmediateActivity = null; - + Op op = new Op(); op.cmd = OP_REMOVE; op.fragment = fragment; addOp(op); - + return this; } @@ -262,50 +307,74 @@ final class BackStackEntry implements FragmentTransaction, Runnable { if (fragment.mImmediateActivity == null) { throw new IllegalStateException("Fragment not added: " + fragment); } - + Op op = new Op(); op.cmd = OP_HIDE; op.fragment = fragment; addOp(op); - + return this; } - + public FragmentTransaction show(Fragment fragment) { if (fragment.mImmediateActivity == null) { throw new IllegalStateException("Fragment not added: " + fragment); } - + Op op = new Op(); op.cmd = OP_SHOW; op.fragment = fragment; addOp(op); - + return this; } - + public FragmentTransaction setCustomAnimations(int enter, int exit) { mEnterAnim = enter; mExitAnim = exit; return this; } - + public FragmentTransaction setTransition(int transition) { mTransition = transition; return this; } - + public FragmentTransaction setTransitionStyle(int styleRes) { mTransitionStyle = styleRes; return this; } - + public FragmentTransaction addToBackStack(String name) { mAddToBackStack = true; mName = name; return this; } + public FragmentTransaction setBreadCrumbTitle(int res) { + mBreadCrumbTitleRes = res; + mBreadCrumbTitleText = null; + return this; + } + + public FragmentTransaction setBreadCrumbTitle(CharSequence text) { + mBreadCrumbTitleRes = 0; + mBreadCrumbTitleText = text; + return this; + } + + public FragmentTransaction setBreadCrumbShortTitle(int res) { + mBreadCrumbShortTitleRes = res; + mBreadCrumbShortTitleText = null; + return this; + } + + public FragmentTransaction setBreadCrumbShortTitle(CharSequence text) { + mBreadCrumbShortTitleRes = 0; + mBreadCrumbShortTitleText = text; + return this; + } + void bumpBackStackNesting(int amt) { if (!mAddToBackStack) { return; @@ -341,10 +410,10 @@ final class BackStackEntry implements FragmentTransaction, Runnable { mManager.enqueueAction(this); return mIndex; } - + public void run() { if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this); - + if (mAddToBackStack) { if (mIndex < 0) { throw new IllegalStateException("addToBackStack() called after commit()"); @@ -405,23 +474,23 @@ final class BackStackEntry implements FragmentTransaction, Runnable { throw new IllegalArgumentException("Unknown cmd: " + op.cmd); } } - + op = op.next; } - + mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true); - + if (mAddToBackStack) { mManager.addBackStackState(this); } } - + public void popFromBackStack(boolean doStateMove) { if (FragmentManagerImpl.DEBUG) Log.v(TAG, "popFromBackStack: " + this); bumpBackStackNesting(-1); - + Op op = mTail; while (op != null) { switch (op.cmd) { @@ -465,10 +534,10 @@ final class BackStackEntry implements FragmentTransaction, Runnable { throw new IllegalArgumentException("Unknown cmd: " + op.cmd); } } - + op = op.prev; } - + if (doStateMove) { mManager.moveToState(mManager.mCurState, FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true); @@ -479,15 +548,15 @@ final class BackStackEntry implements FragmentTransaction, Runnable { mIndex = -1; } } - + public String getName() { return mName; } - + public int getTransition() { return mTransition; } - + public int getTransitionStyle() { return mTransitionStyle; } diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java new file mode 100644 index 0000000..0d39d0b --- /dev/null +++ b/core/java/android/app/FragmentBreadCrumbs.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2010 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 android.app; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; + +/** + * Helper class for showing "bread crumbs" representing the fragment + * stack in an activity. This is intended to be used with + * {@link ActionBar#setCustomNavigationMode(View) + * ActionBar.setCustomNavigationMode(View)} to place the bread crumbs in + * the navigation area of the action bar. + * + * <p>The default style for this view is + * {@link android.R.style#Widget_FragmentBreadCrumbs}. + */ +public class FragmentBreadCrumbs extends ViewGroup + implements FragmentManager.OnBackStackChangedListener { + Activity mActivity; + LayoutInflater mInflater; + LinearLayout mContainer; + + // Hahah + BackStackRecord mTopEntry; + + public FragmentBreadCrumbs(Context context) { + this(context, null); + } + + public FragmentBreadCrumbs(Context context, AttributeSet attrs) { + this(context, attrs, android.R.style.Widget_FragmentBreadCrumbs); + } + + public FragmentBreadCrumbs(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Attach the bread crumbs to their activity. This must be called once + * when creating the bread crumbs. + */ + public void setActivity(Activity a) { + mActivity = a; + mInflater = (LayoutInflater)a.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mContainer = (LinearLayout)mInflater.inflate( + com.android.internal.R.layout.fragment_bread_crumbs, + this, false); + addView(mContainer); + a.getFragmentManager().addOnBackStackChangedListener(this); + updateCrumbs(); + } + + /** + * Set a custom title for the bread crumbs. This will be the first entry + * shown at the left, representing the root of the bread crumbs. If the + * title is null, it will not be shown. + */ + public void setTitle(CharSequence title, CharSequence shortTitle) { + if (title == null) { + mTopEntry = null; + } else { + mTopEntry = new BackStackRecord((FragmentManagerImpl) + mActivity.getFragmentManager()); + mTopEntry.setBreadCrumbTitle(title); + mTopEntry.setBreadCrumbShortTitle(shortTitle); + } + updateCrumbs(); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + // Eventually we should implement our own layout of the views, + // rather than relying on a linear layout. + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + + int childRight = mPaddingLeft + child.getMeasuredWidth() - mPaddingRight; + int childBottom = mPaddingTop + child.getMeasuredHeight() - mPaddingBottom; + child.layout(mPaddingLeft, mPaddingTop, childRight, childBottom); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int count = getChildCount(); + + int maxHeight = 0; + int maxWidth = 0; + + // Find rightmost and bottom-most child + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + measureChild(child, widthMeasureSpec, heightMeasureSpec); + maxWidth = Math.max(maxWidth, child.getMeasuredWidth()); + maxHeight = Math.max(maxHeight, child.getMeasuredHeight()); + } + } + + // Account for padding too + maxWidth += mPaddingLeft + mPaddingRight; + maxHeight += mPaddingTop + mPaddingBottom; + + // Check against our minimum height and width + maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); + maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); + + setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), + resolveSize(maxHeight, heightMeasureSpec)); + } + + @Override + public void onBackStackChanged() { + updateCrumbs(); + } + + void updateCrumbs() { + FragmentManager fm = mActivity.getFragmentManager(); + int numEntries = fm.countBackStackEntries(); + int numViews = mContainer.getChildCount(); + for (int i=mTopEntry != null ? -1 : 0; i<numEntries; i++) { + FragmentManager.BackStackEntry bse = i == -1 ? mTopEntry : fm.getBackStackEntry(i); + int viewI = mTopEntry != null ? i+1 : i; + if (viewI < numViews) { + View v = mContainer.getChildAt(viewI); + Object tag = v.getTag(); + if (tag != bse) { + for (int j=viewI; j<numViews; j++) { + mContainer.removeViewAt(viewI); + } + numViews = viewI; + } + } + if (viewI >= numViews) { + View item = mInflater.inflate( + com.android.internal.R.layout.fragment_bread_crumb_item, + this, false); + TextView text = (TextView)item.findViewById(com.android.internal.R.id.title); + text.setText(bse.getBreadCrumbTitle()); + item.setTag(bse); + if (viewI == 0) { + text.setCompoundDrawables(null, null, null, null); + } + mContainer.addView(item); + } + } + int viewI = mTopEntry != null ? numEntries+1 : numEntries; + numViews = mContainer.getChildCount(); + while (numViews > viewI) { + mContainer.removeViewAt(numViews-1); + numViews--; + } + } +} diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index a704ec8..9f95824 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -40,6 +40,48 @@ import java.util.ArrayList; */ public interface FragmentManager { /** + * Representation of an entry on the fragment back stack, as created + * with {@link FragmentTransaction#addToBackStack(String) + * FragmentTransaction.addToBackStack()}. Entries can later be + * retrieved with {@link FragmentManager#getBackStackEntry(int) + * FragmentManager.getBackStackEntry()}. + * + * <p>Note that you should never hold on to a BackStackEntry object; + * the identifier as returned by {@link #getId} is the only thing that + * will be persisted across activity instances. + */ + public interface BackStackEntry { + /** + * Return the unique identifier for the entry. This is the only + * representation of the entry that will persist across activity + * instances. + */ + public int getId(); + + /** + * Return the full bread crumb title for the entry, or null if it + * does not have one. + */ + public CharSequence getBreadCrumbTitle(); + + /** + * Return the short bread crumb title for the entry, or null if it + * does not have one. + */ + public CharSequence getBreadCrumbShortTitle(); + } + + /** + * Interface to watch for changes to the back stack. + */ + public interface OnBackStackChangedListener { + /** + * Called whenever the contents of the back stack change. + */ + public void onBackStackChanged(); + } + + /** * Start a series of edit operations on the Fragments associated with * this FragmentManager. */ @@ -105,6 +147,28 @@ public interface FragmentManager { public boolean popBackStack(int id, int flags); /** + * Return the number of entries currently in the back stack. + */ + public int countBackStackEntries(); + + /** + * Return the BackStackEntry at index <var>index</var> in the back stack; + * entries start index 0 being the bottom of the stack. + */ + public BackStackEntry getBackStackEntry(int index); + + /** + * Add a new listener for changes to the fragment back stack. + */ + public void addOnBackStackChangedListener(OnBackStackChangedListener listener); + + /** + * Remove a listener that was previously added with + * {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}. + */ + public void removeOnBackStackChangedListener(OnBackStackChangedListener listener); + + /** * Put a reference to a fragment in a Bundle. This Bundle can be * persisted as saved state, and when later restoring * {@link #getFragment(Bundle, String)} will return the current @@ -182,12 +246,14 @@ final class FragmentManagerImpl implements FragmentManager { ArrayList<Fragment> mActive; ArrayList<Fragment> mAdded; ArrayList<Integer> mAvailIndices; - ArrayList<BackStackEntry> mBackStack; + ArrayList<BackStackRecord> mBackStack; // Must be accessed while locked. - ArrayList<BackStackEntry> mBackStackIndices; + ArrayList<BackStackRecord> mBackStackIndices; ArrayList<Integer> mAvailBackStackIndices; + ArrayList<OnBackStackChangedListener> mBackStackChangeListeners; + int mCurState = Fragment.INITIALIZING; Activity mActivity; @@ -205,7 +271,7 @@ final class FragmentManagerImpl implements FragmentManager { } }; public FragmentTransaction openTransaction() { - return new BackStackEntry(this); + return new BackStackRecord(this); } public boolean popBackStack() { @@ -223,6 +289,27 @@ final class FragmentManagerImpl implements FragmentManager { return popBackStackState(mActivity.mHandler, null, id, flags); } + public int countBackStackEntries() { + return mBackStack != null ? mBackStack.size() : 0; + } + + public BackStackEntry getBackStackEntry(int index) { + return mBackStack.get(index); + } + + public void addOnBackStackChangedListener(OnBackStackChangedListener listener) { + if (mBackStackChangeListeners == null) { + mBackStackChangeListeners = new ArrayList<OnBackStackChangedListener>(); + } + mBackStackChangeListeners.add(listener); + } + + public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) { + if (mBackStackChangeListeners != null) { + mBackStackChangeListeners.remove(listener); + } + } + public void putFragment(Bundle bundle, String key, Fragment fragment) { if (fragment.mIndex < 0) { throw new IllegalStateException("Fragment " + fragment @@ -696,11 +783,11 @@ final class FragmentManagerImpl implements FragmentManager { } } - public int allocBackStackIndex(BackStackEntry bse) { + public int allocBackStackIndex(BackStackRecord bse) { synchronized (this) { if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) { if (mBackStackIndices == null) { - mBackStackIndices = new ArrayList<BackStackEntry>(); + mBackStackIndices = new ArrayList<BackStackRecord>(); } int index = mBackStackIndices.size(); if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse); @@ -716,10 +803,10 @@ final class FragmentManagerImpl implements FragmentManager { } } - public void setBackStackIndex(int index, BackStackEntry bse) { + public void setBackStackIndex(int index, BackStackRecord bse) { synchronized (this) { if (mBackStackIndices == null) { - mBackStackIndices = new ArrayList<BackStackEntry>(); + mBackStackIndices = new ArrayList<BackStackRecord>(); } int N = mBackStackIndices.size(); if (index < N) { @@ -785,11 +872,20 @@ final class FragmentManagerImpl implements FragmentManager { } } - public void addBackStackState(BackStackEntry state) { + void reportBackStackChanged() { + if (mBackStackChangeListeners != null) { + for (int i=0; i<mBackStackChangeListeners.size(); i++) { + mBackStackChangeListeners.get(i).onBackStackChanged(); + } + } + } + + void addBackStackState(BackStackRecord state) { if (mBackStack == null) { - mBackStack = new ArrayList<BackStackEntry>(); + mBackStack = new ArrayList<BackStackRecord>(); } mBackStack.add(state); + reportBackStackChanged(); } boolean popBackStackState(Handler handler, String name, int id, int flags) { @@ -801,11 +897,12 @@ final class FragmentManagerImpl implements FragmentManager { if (last < 0) { return false; } - final BackStackEntry bss = mBackStack.remove(last); + final BackStackRecord bss = mBackStack.remove(last); enqueueAction(new Runnable() { public void run() { if (DEBUG) Log.v(TAG, "Popping back stack state: " + bss); bss.popFromBackStack(true); + reportBackStackChanged(); } }); } else { @@ -815,7 +912,7 @@ final class FragmentManagerImpl implements FragmentManager { // the stack. index = mBackStack.size()-1; while (index >= 0) { - BackStackEntry bss = mBackStack.get(index); + BackStackRecord bss = mBackStack.get(index); if (name != null && name.equals(bss.getName())) { break; } @@ -831,7 +928,7 @@ final class FragmentManagerImpl implements FragmentManager { index--; // Consume all following entries that match. while (index >= 0) { - BackStackEntry bss = mBackStack.get(index); + BackStackRecord bss = mBackStack.get(index); if ((name != null && name.equals(bss.getName())) || (id >= 0 && id == bss.mIndex)) { index--; @@ -844,8 +941,8 @@ final class FragmentManagerImpl implements FragmentManager { if (index == mBackStack.size()-1) { return false; } - final ArrayList<BackStackEntry> states - = new ArrayList<BackStackEntry>(); + final ArrayList<BackStackRecord> states + = new ArrayList<BackStackRecord>(); for (int i=mBackStack.size()-1; i>index; i--) { states.add(mBackStack.remove(i)); } @@ -856,6 +953,7 @@ final class FragmentManagerImpl implements FragmentManager { if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i)); states.get(i).popFromBackStack(i == LAST); } + reportBackStackChanged(); } }); } @@ -1073,9 +1171,9 @@ final class FragmentManagerImpl implements FragmentManager { // Build the back stack. if (fms.mBackStack != null) { - mBackStack = new ArrayList<BackStackEntry>(fms.mBackStack.length); + mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length); for (int i=0; i<fms.mBackStack.length; i++) { - BackStackEntry bse = fms.mBackStack[i].instantiate(this); + BackStackRecord bse = fms.mBackStack[i].instantiate(this); if (DEBUG) Log.v(TAG, "restoreAllState: adding bse #" + i + " (index " + bse.mIndex + "): " + bse); mBackStack.add(bse); diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java index 9d44106..09d8d26 100644 --- a/core/java/android/app/FragmentTransaction.java +++ b/core/java/android/app/FragmentTransaction.java @@ -88,7 +88,7 @@ public interface FragmentTransaction { /** * @return <code>true</code> if this transaction contains no operations, - * <code>false</code> otherwise. + * <code>false</code> otherwise. */ public boolean isEmpty(); @@ -111,14 +111,65 @@ public interface FragmentTransaction { /** Fragment is being removed */ public final int TRANSIT_FRAGMENT_CLOSE = 2 | TRANSIT_EXIT_MASK; + /** + * Set specific animation resources to run for the fragments that are + * entering and exiting in this transaction. + */ public FragmentTransaction setCustomAnimations(int enter, int exit); + /** + * Select a standard transition animation for this transaction. May be + * one of {@link #TRANSIT_NONE}, {@link #TRANSIT_FRAGMENT_OPEN}, + * or {@link #TRANSIT_FRAGMENT_CLOSE} + */ public FragmentTransaction setTransition(int transit); + + /** + * Set a custom style resource that will be used for resolving transit + * animations. + */ public FragmentTransaction setTransitionStyle(int styleRes); + /** + * Add this transaction to the back stack. This means that the transaction + * will be remembered after it is committed, and will reverse its operation + * when later popped off the stack. + * + * @param name An optional name for this back stack state, or null. + */ public FragmentTransaction addToBackStack(String name); /** + * Set the full title to show as a bread crumb when this transaction + * is on the back stack, as used by {@link FragmentBreadCrumbs}. + * + * @param res A string resource containing the title. + */ + public FragmentTransaction setBreadCrumbTitle(int res); + + /** + * Like {@link #setBreadCrumbTitle(int)} but taking a raw string; this + * method is <em>not</em> recommended, as the string can not be changed + * later if the locale changes. + */ + public FragmentTransaction setBreadCrumbTitle(CharSequence text); + + /** + * Set the short title to show as a bread crumb when this transaction + * is on the back stack, as used by {@link FragmentBreadCrumbs}. + * + * @param res A string resource containing the title. + */ + public FragmentTransaction setBreadCrumbShortTitle(int res); + + /** + * Like {@link #setBreadCrumbShortTitle(int)} but taking a raw string; this + * method is <em>not</em> recommended, as the string can not be changed + * later if the locale changes. + */ + public FragmentTransaction setBreadCrumbShortTitle(CharSequence text); + + /** * Schedules a commit of this transaction. Note that the commit does * not happen immediately; it will be scheduled as work on the main thread * to be done the next time that thread is ready. diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 4247ae5..e78d2af 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -22,6 +22,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.app.Fragment; +import android.app.FragmentBreadCrumbs; import android.app.FragmentTransaction; import android.app.ListActivity; import android.content.Context; @@ -117,7 +118,6 @@ public abstract class PreferenceActivity extends ListActivity implements // Constants for state save/restore private static final String HEADERS_TAG = ":android:headers"; private static final String CUR_HEADER_TAG = ":android:cur_header"; - private static final String SINGLE_PANE_TAG = ":android:single_pane"; private static final String PREFERENCES_TAG = ":android:preferences"; /** @@ -169,6 +169,8 @@ public abstract class PreferenceActivity extends ListActivity implements private View mPrefsContainer; + private FragmentBreadCrumbs mFragmentBreadCrumbs; + private boolean mSinglePane; private Header mCurHeader; @@ -300,6 +302,18 @@ public abstract class PreferenceActivity extends ListActivity implements public CharSequence summary; /** + * Optional text to show as the title in the bread crumb. + * @attr ref android.R.styleable#PreferenceHeader_breadCrumbTitle + */ + public CharSequence breadCrumbTitle; + + /** + * Optional text to show as the short title in the bread crumb. + * @attr ref android.R.styleable#PreferenceHeader_breadCrumbShortTitle + */ + public CharSequence breadCrumbShortTitle; + + /** * Optional icon resource to show for this header. * @attr ref android.R.styleable#PreferenceHeader_icon */ @@ -341,6 +355,8 @@ public abstract class PreferenceActivity extends ListActivity implements dest.writeLong(id); TextUtils.writeToParcel(title, dest, flags); TextUtils.writeToParcel(summary, dest, flags); + TextUtils.writeToParcel(breadCrumbTitle, dest, flags); + TextUtils.writeToParcel(breadCrumbShortTitle, dest, flags); dest.writeInt(iconRes); dest.writeString(fragment); dest.writeBundle(fragmentArguments); @@ -357,6 +373,8 @@ public abstract class PreferenceActivity extends ListActivity implements id = in.readLong(); title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); summary = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + breadCrumbTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + breadCrumbShortTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); iconRes = in.readInt(); fragment = in.readString(); fragmentArguments = in.readBundle(); @@ -405,7 +423,6 @@ public abstract class PreferenceActivity extends ListActivity implements setSelectedHeader(mHeaders.get(curHeader)); } } - mSinglePane = savedInstanceState.getBoolean(SINGLE_PANE_TAG); } else { if (initialFragment != null && mSinglePane) { @@ -537,7 +554,11 @@ public abstract class PreferenceActivity extends ListActivity implements public boolean onIsMultiPane() { Configuration config = getResources().getConfiguration(); if ((config.screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) - == Configuration.SCREENLAYOUT_SIZE_XLARGE + == Configuration.SCREENLAYOUT_SIZE_XLARGE) { + return true; + } + if ((config.screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) + == Configuration.SCREENLAYOUT_SIZE_LARGE && config.orientation == Configuration.ORIENTATION_LANDSCAPE) { return true; } @@ -649,6 +670,10 @@ public abstract class PreferenceActivity extends ListActivity implements com.android.internal.R.styleable.PreferenceHeader_title); header.summary = sa.getText( com.android.internal.R.styleable.PreferenceHeader_summary); + header.breadCrumbTitle = sa.getText( + com.android.internal.R.styleable.PreferenceHeader_breadCrumbTitle); + header.breadCrumbShortTitle = sa.getText( + com.android.internal.R.styleable.PreferenceHeader_breadCrumbShortTitle); header.iconRes = sa.getResourceId( com.android.internal.R.styleable.PreferenceHeader_icon, 0); header.fragment = sa.getString( @@ -741,7 +766,6 @@ public abstract class PreferenceActivity extends ListActivity implements } } } - outState.putBoolean(SINGLE_PANE_TAG, mSinglePane); if (mPreferenceManager != null) { final PreferenceScreen preferenceScreen = getPreferenceScreen(); @@ -837,6 +861,20 @@ public abstract class PreferenceActivity extends ListActivity implements startActivity(intent); } + /** + * Change the base title of the bread crumbs for the current preferences. + * This will normally be called for you. See + * {@link android.app.FragmentBreadCrumbs} for more information. + */ + public void showBreadCrumbs(CharSequence title, CharSequence shortTitle) { + if (mFragmentBreadCrumbs == null) { + mFragmentBreadCrumbs = new FragmentBreadCrumbs(this); + mFragmentBreadCrumbs.setActivity(this); + getActionBar().setCustomNavigationMode(mFragmentBreadCrumbs); + } + mFragmentBreadCrumbs.setTitle(title, shortTitle); + } + void setSelectedHeader(Header header) { mCurHeader = header; int index = mHeaders.indexOf(header); @@ -845,6 +883,21 @@ public abstract class PreferenceActivity extends ListActivity implements } else { getListView().clearChoices(); } + if (header != null) { + CharSequence title = header.breadCrumbTitle; + if (title == null) title = header.title; + if (title == null) title = getTitle(); + showBreadCrumbs(title, header.breadCrumbShortTitle); + } else { + showBreadCrumbs(getTitle(), null); + } + } + + public void switchToHeaderInner(String fragmentName, Bundle args) { + getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE); + Fragment f = Fragment.instantiate(this, fragmentName, args); + getFragmentManager().openTransaction().replace( + com.android.internal.R.id.prefs, f).commit(); } /** @@ -856,12 +909,7 @@ public abstract class PreferenceActivity extends ListActivity implements */ public void switchToHeader(String fragmentName, Bundle args) { setSelectedHeader(null); - - getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE); - - Fragment f = Fragment.instantiate(this, fragmentName, args); - getFragmentManager().openTransaction().replace( - com.android.internal.R.id.prefs, f).commit(); + switchToHeaderInner(fragmentName, args); } /** @@ -871,8 +919,7 @@ public abstract class PreferenceActivity extends ListActivity implements * @param header The new header to display. */ public void switchToHeader(Header header) { - switchToHeader(header.fragment, header.fragmentArguments); - mCurHeader = header; + switchToHeaderInner(header.fragment, header.fragmentArguments); setSelectedHeader(header); } @@ -930,17 +977,32 @@ public abstract class PreferenceActivity extends ListActivity implements */ public void startPreferenceFragment(Fragment fragment, boolean push) { FragmentTransaction transaction = getFragmentManager().openTransaction(); - transaction.replace(com.android.internal.R.id.prefs, fragment); + startPreferenceFragment(fragment, transaction); if (push) { transaction.addToBackStack(BACK_STACK_PREFS); } transaction.commit(); } + /** + * Start a new fragment. + * + * @param fragment The fragment to start + * @param ft The FragmentTransaction in which to perform this operation. + * Will not be added to the back stack or committed for you; you use do that. + */ + public void startPreferenceFragment(Fragment fragment, FragmentTransaction ft) { + ft.replace(com.android.internal.R.id.prefs, fragment); + } + @Override public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) { Fragment f = Fragment.instantiate(this, pref.getFragment(), pref.getExtras()); - startPreferenceFragment(f, true); + FragmentTransaction transaction = getFragmentManager().openTransaction(); + startPreferenceFragment(f, transaction); + transaction.setBreadCrumbTitle(pref.getTitle()); + transaction.addToBackStack(BACK_STACK_PREFS); + transaction.commit(); return true; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 00efa90..ac65e09 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8745,7 +8745,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility mPrivateFlags = (mPrivateFlags & ~ACTIVATED) | (activated ? ACTIVATED : 0); invalidate(); refreshDrawableState(); - dispatchSetSelected(activated); + dispatchSetActivated(activated); } } diff --git a/core/res/res/color/primary_text_dark.xml b/core/res/res/color/primary_text_dark.xml index 39c9e22..3dd73e7 100644 --- a/core/res/res/color/primary_text_dark.xml +++ b/core/res/res/color/primary_text_dark.xml @@ -19,7 +19,6 @@ <item android:state_window_focused="false" android:color="@android:color/bright_foreground_dark"/> <item android:state_pressed="true" android:color="@android:color/bright_foreground_dark_inverse"/> <item android:state_selected="true" android:color="@android:color/bright_foreground_dark_inverse"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse"/> <item android:color="@android:color/bright_foreground_dark"/> <!-- not selected --> - </selector> - diff --git a/core/res/res/color/primary_text_dark_focused.xml b/core/res/res/color/primary_text_dark_focused.xml index 7f3906a..c97c0bd 100644 --- a/core/res/res/color/primary_text_dark_focused.xml +++ b/core/res/res/color/primary_text_dark_focused.xml @@ -16,6 +16,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="@android:color/bright_foreground_dark_inverse" /> + <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse" /> <item android:state_focused="true" android:color="@android:color/bright_foreground_dark_inverse" /> <item android:state_pressed="true" android:color="@android:color/bright_foreground_dark_inverse" /> <item android:color="@android:color/bright_foreground_dark" /> diff --git a/core/res/res/color/primary_text_dark_nodisable.xml b/core/res/res/color/primary_text_dark_nodisable.xml index be1b9f9..443f7f4 100644 --- a/core/res/res/color/primary_text_dark_nodisable.xml +++ b/core/res/res/color/primary_text_dark_nodisable.xml @@ -16,6 +16,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="@android:color/bright_foreground_dark_inverse"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse"/> <item android:color="@android:color/bright_foreground_dark"/> <!-- not selected --> </selector> diff --git a/core/res/res/color/primary_text_light.xml b/core/res/res/color/primary_text_light.xml index e112034..a12c6b4 100644 --- a/core/res/res/color/primary_text_light.xml +++ b/core/res/res/color/primary_text_light.xml @@ -19,6 +19,7 @@ <item android:state_window_focused="false" android:color="@android:color/bright_foreground_light"/> <item android:state_pressed="true" android:color="@android:color/bright_foreground_light"/> <item android:state_selected="true" android:color="@android:color/bright_foreground_light"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_light"/> <item android:color="@android:color/bright_foreground_light"/> <!-- not selected --> </selector> diff --git a/core/res/res/color/primary_text_light_nodisable.xml b/core/res/res/color/primary_text_light_nodisable.xml index 2d35470..051cccf 100644 --- a/core/res/res/color/primary_text_light_nodisable.xml +++ b/core/res/res/color/primary_text_light_nodisable.xml @@ -16,6 +16,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="@android:color/bright_foreground_light"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_light"/> <item android:color="@android:color/bright_foreground_light"/> <!-- not selected --> </selector> diff --git a/core/res/res/color/secondary_text_dark.xml b/core/res/res/color/secondary_text_dark.xml index c195ef0..1a38fa9 100644 --- a/core/res/res/color/secondary_text_dark.xml +++ b/core/res/res/color/secondary_text_dark.xml @@ -20,6 +20,7 @@ <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_inverse_disabled"/> <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_inverse_disabled"/> <item android:state_selected="true" android:color="@android:color/dim_foreground_dark_inverse"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse"/> <item android:state_pressed="true" android:color="@android:color/dim_foreground_dark_inverse"/> <item android:state_enabled="false" android:color="@android:color/dim_foreground_dark_disabled"/> <item android:color="@android:color/dim_foreground_dark"/> <!-- not selected --> diff --git a/core/res/res/color/secondary_text_dark_nodisable.xml b/core/res/res/color/secondary_text_dark_nodisable.xml index 2c87a25..cbc7b02 100644 --- a/core/res/res/color/secondary_text_dark_nodisable.xml +++ b/core/res/res/color/secondary_text_dark_nodisable.xml @@ -16,5 +16,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="@android:color/dim_foreground_dark_inverse"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse"/> <item android:color="@android:color/dim_foreground_dark"/> <!-- not selected --> </selector> diff --git a/core/res/res/color/secondary_text_light.xml b/core/res/res/color/secondary_text_light.xml index 99249a5..293f4aa 100644 --- a/core/res/res/color/secondary_text_light.xml +++ b/core/res/res/color/secondary_text_light.xml @@ -22,6 +22,7 @@ <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_light_disabled"/> <item android:state_pressed="true" android:color="@android:color/dim_foreground_light"/> <item android:state_selected="true" android:color="@android:color/dim_foreground_light"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_light"/> <item android:state_enabled="false" android:color="@android:color/dim_foreground_light_disabled"/> <item android:color="@android:color/dim_foreground_light"/> <!-- not selected --> </selector> diff --git a/core/res/res/color/secondary_text_light_nodisable.xml b/core/res/res/color/secondary_text_light_nodisable.xml index 2c87a25..cbc7b02 100644 --- a/core/res/res/color/secondary_text_light_nodisable.xml +++ b/core/res/res/color/secondary_text_light_nodisable.xml @@ -16,5 +16,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="@android:color/dim_foreground_dark_inverse"/> + <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse"/> <item android:color="@android:color/dim_foreground_dark"/> <!-- not selected --> </selector> diff --git a/core/res/res/drawable-hdpi/nav_divider.png b/core/res/res/drawable-hdpi/nav_divider.png Binary files differnew file mode 100644 index 0000000..7ca3e61 --- /dev/null +++ b/core/res/res/drawable-hdpi/nav_divider.png diff --git a/core/res/res/drawable-mdpi/nav_divider.png b/core/res/res/drawable-mdpi/nav_divider.png Binary files differnew file mode 100644 index 0000000..c9413d7 --- /dev/null +++ b/core/res/res/drawable-mdpi/nav_divider.png diff --git a/core/res/res/layout-port/preference_header_item.xml b/core/res/res/layout-port/preference_header_item.xml new file mode 100644 index 0000000..cc76c8e --- /dev/null +++ b/core/res/res/layout-port/preference_header_item.xml @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2006 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. +--> + +<!-- Layout of a header item in PreferenceActivity. --> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="96dp" + android:background="?android:attr/activatedBackgroundIndicator" + android:paddingRight="?android:attr/scrollbarSize"> + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_gravity="center" + android:paddingLeft="4dip" + android:paddingRight="4dip" + android:paddingTop="4dip" + android:paddingBottom="4dip"> + + <ImageView + android:id="@+id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginBottom="2dip" /> + + <TextView android:id="@+android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginBottom="2dip" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceLarge" + android:ellipsize="marquee" + android:fadingEdge="horizontal" /> + + <TextView android:id="@+android:id/summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:gravity="center" + android:textAppearance="?android:attr/textAppearanceSmall" + android:ellipsize="end" + android:maxLines="2" /> + + </LinearLayout> +</FrameLayout> diff --git a/core/res/res/layout/fragment_bread_crumb_item.xml b/core/res/res/layout/fragment_bread_crumb_item.xml new file mode 100644 index 0000000..408f6e8 --- /dev/null +++ b/core/res/res/layout/fragment_bread_crumb_item.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical" + android:textAppearance="?android:attr/textAppearanceMediumInverse" + android:drawableLeft="@drawable/nav_divider" + android:paddingLeft="12dp" + android:drawablePadding="12dp" + /> diff --git a/core/res/res/layout/fragment_bread_crumbs.xml b/core/res/res/layout/fragment_bread_crumbs.xml new file mode 100644 index 0000000..f289e14 --- /dev/null +++ b/core/res/res/layout/fragment_bread_crumbs.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:gravity="center_vertical" + android:layout_width="wrap_content" + android:layout_height="match_parent"> +</LinearLayout> diff --git a/core/res/res/layout/preference_header_item.xml b/core/res/res/layout/preference_header_item.xml index 80a3ac2..aba7b2a 100644 --- a/core/res/res/layout/preference_header_item.xml +++ b/core/res/res/layout/preference_header_item.xml @@ -54,6 +54,7 @@ android:layout_below="@android:id/title" android:layout_alignLeft="@android:id/title" android:textAppearance="?android:attr/textAppearanceSmall" + android:ellipsize="end" android:maxLines="2" /> </RelativeLayout> diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml index fe950b2..9661c64 100644 --- a/core/res/res/layout/preference_list_content.xml +++ b/core/res/res/layout/preference_list_content.xml @@ -33,7 +33,7 @@ android:orientation="vertical" android:layout_width="0px" android:layout_height="match_parent" - android:layout_weight="1"> + android:layout_weight="10"> <ListView android:id="@android:id/list" android:layout_width="match_parent" @@ -52,7 +52,7 @@ <FrameLayout android:id="@+id/prefs" android:layout_width="0px" android:layout_height="match_parent" - android:layout_weight="3" + android:layout_weight="33" android:visibility="gone" /> </LinearLayout> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index b3d39f3..2dec5c5 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3561,6 +3561,10 @@ <attr name="title" /> <!-- The summary for the item. --> <attr name="summary" format="string" /> + <!-- The title for the bread crumb of this item. --> + <attr name="breadCrumbTitle" format="string" /> + <!-- The short title for the bread crumb of this item. --> + <attr name="breadCrumbShortTitle" format="string" /> <!-- An icon for the item. --> <attr name="icon" /> <!-- The fragment that is displayed when the user selects this item. --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 3b69acb..fbee438 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1352,6 +1352,8 @@ <public type="attr" name="popupMenuStyle" /> <public type="attr" name="textAppearanceLargePopupMenu" /> <public type="attr" name="textAppearanceSmallPopupMenu" /> + <public type="attr" name="breadCrumbTitle" /> + <public type="attr" name="breadCrumbShortTitle" /> <public type="anim" name="animator_fade_in" /> <public type="anim" name="animator_fade_out" /> @@ -1390,6 +1392,7 @@ <public type="style" name="Widget.ActionButton.CloseMode" /> <public type="style" name="TextAppearance.Widget.PopupMenu.Large" /> <public type="style" name="TextAppearance.Widget.PopupMenu.Small" /> + <public type="style" name="Widget.FragmentBreadCrumbs" /> <public type="string" name="selectTextMode" /> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 9ba0131..1db6f87 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -563,6 +563,11 @@ <item name="android:popupBackground">@android:drawable/editbox_dropdown_background_dark</item> </style> + <!-- Default style for {@link android.app.FragmentBreadCrumbs} view. --> + <style name="Widget.FragmentBreadCrumbs"> + <item name="android:padding">4dp</item> + </style> + <style name="Widget.KeyboardView" parent="android:Widget"> <item name="android:background">@android:drawable/keyboard_background</item> <item name="android:keyBackground">@android:drawable/btn_keyboard_key</item> |
