diff options
16 files changed, 138 insertions, 8 deletions
diff --git a/api/current.txt b/api/current.txt index fd05e485b0a3..e66b9a34a3f3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2102,6 +2102,7 @@ package android.app { method public abstract void setCustomView(android.view.View); method public abstract void setCustomView(android.view.View, android.app.ActionBar.LayoutParams); method public abstract void setCustomView(int); + method public abstract void setDisplayDisableHomeEnabled(boolean); method public abstract void setDisplayHomeAsUpEnabled(boolean); method public abstract void setDisplayOptions(int); method public abstract void setDisplayOptions(int, int); @@ -2121,6 +2122,7 @@ package android.app { method public abstract void setTitle(java.lang.CharSequence); method public abstract void setTitle(int); method public abstract void show(); + field public static final int DISPLAY_DISABLE_HOME = 32; // 0x20 field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4 field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10 field public static final int DISPLAY_SHOW_HOME = 2; // 0x2 diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index a9e84d7e9a31..cac06ec54eeb 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -107,6 +107,18 @@ public abstract class ActionBar { public static final int DISPLAY_SHOW_CUSTOM = 0x10; /** + * Disable the 'home' element. This may be combined with + * {@link #DISPLAY_SHOW_HOME} to create a non-focusable/non-clickable + * 'home' element. Useful for a level of your app's navigation hierarchy + * where clicking 'home' doesn't do anything. + * + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + * @see #setDisplayDisableHomeEnabled(boolean) + */ + public static final int DISPLAY_DISABLE_HOME = 0x20; + + /** * Set the action bar into custom navigation mode, supplying a view * for custom navigation. * @@ -393,6 +405,21 @@ public abstract class ActionBar { public abstract void setDisplayShowCustomEnabled(boolean showCustom); /** + * Set whether the 'home' affordance on the action bar should be disabled. + * If set, the 'home' element will not be focusable or clickable, useful if + * the user is at the top level of the app's navigation hierarchy. + * + * <p>To set several display options at once, see the setDisplayOptions methods. + * + * @param disableHome true to disable the 'home' element. + * + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + * @see #DISPLAY_DISABLE_HOME + */ + public abstract void setDisplayDisableHomeEnabled(boolean disableHome); + + /** * Set the ActionBar's background. * * @param d Background drawable diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index 96520858fe95..dccfa6c537fb 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -42,8 +42,10 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.Window; import android.view.animation.DecelerateInterpolator; +import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import android.widget.SpinnerAdapter; @@ -71,6 +73,7 @@ public class ActionBarImpl extends ActionBar { private ActionBarContextView mUpperContextView; private LinearLayout mLowerContextView; private View mContentView; + private ViewGroup mExternalTabView; private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>(); @@ -172,6 +175,18 @@ public class ActionBarImpl extends ActionBar { mActionView.setContextView(mUpperContextView); mContextDisplayMode = mLowerContextView == null ? CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT; + + if (!mActionView.hasEmbeddedTabs()) { + HorizontalScrollView tabScroller = new HorizontalScrollView(mContext); + ViewGroup tabContainer = mActionView.createTabContainer(); + tabScroller.setHorizontalFadingEdgeEnabled(true); + tabScroller.addView(tabContainer); + tabScroller.setVisibility(getNavigationMode() == NAVIGATION_MODE_TABS ? + View.VISIBLE : View.GONE); + mActionView.setExternalTabLayout(tabContainer); + mContainerView.setTabContainer(tabScroller); + mExternalTabView = tabScroller; + } } /** @@ -239,6 +254,11 @@ public class ActionBarImpl extends ActionBar { } @Override + public void setDisplayDisableHomeEnabled(boolean disableHome) { + setDisplayOptions(disableHome ? DISPLAY_DISABLE_HOME : 0, DISPLAY_DISABLE_HOME); + } + + @Override public void setTitle(int resId) { setTitle(mContext.getString(resId)); } @@ -533,7 +553,7 @@ public class ActionBarImpl extends ActionBar { final int count = mContainerView.getChildCount(); for (int i = 0; i < count; i++) { final View child = mContainerView.getChildAt(i); - if (i == viewIndex) { + if (i == viewIndex || child == mContainerView.getTabContainer()) { continue; } @@ -840,11 +860,17 @@ public class ActionBarImpl extends ActionBar { case NAVIGATION_MODE_TABS: mSavedTabPosition = getSelectedNavigationIndex(); selectTab(null); + if (!mActionView.hasEmbeddedTabs()) { + mExternalTabView.setVisibility(View.GONE); + } break; } mActionView.setNavigationMode(mode); switch (mode) { case NAVIGATION_MODE_TABS: + if (!mActionView.hasEmbeddedTabs()) { + mExternalTabView.setVisibility(View.VISIBLE); + } if (mSavedTabPosition != INVALID_POSITION) { setSelectedNavigationItem(mSavedTabPosition); mSavedTabPosition = INVALID_POSITION; diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java index c9b0ec9e838d..3deb036ea89a 100644 --- a/core/java/com/android/internal/widget/ActionBarContainer.java +++ b/core/java/com/android/internal/widget/ActionBarContainer.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.MotionEvent; +import android.view.View; import android.widget.FrameLayout; /** @@ -29,6 +30,7 @@ import android.widget.FrameLayout; */ public class ActionBarContainer extends FrameLayout { private boolean mIsTransitioning; + private View mTabContainer; public ActionBarContainer(Context context) { this(context, null); @@ -65,6 +67,44 @@ public class ActionBarContainer extends FrameLayout { @Override public boolean onTouchEvent(MotionEvent ev) { super.onTouchEvent(ev); + + // An action bar always eats touch events. return true; } + + public void setTabContainer(View tabView) { + if (mTabContainer != null) { + removeView(mTabContainer); + } + mTabContainer = tabView; + addView(tabView); + } + + public View getTabContainer() { + return mTabContainer; + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (mTabContainer != null && mTabContainer.getVisibility() != GONE) { + final int mode = MeasureSpec.getMode(heightMeasureSpec); + if (mode == MeasureSpec.AT_MOST) { + final int measuredHeight = getMeasuredHeight(); + final int maxHeight = MeasureSpec.getSize(heightMeasureSpec); + setMeasuredDimension(getMeasuredWidth(), + Math.min(measuredHeight + mTabContainer.getMeasuredHeight(), maxHeight)); + } + } + } + + @Override + public void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + if (mTabContainer != null && mTabContainer.getVisibility() != GONE) { + final int containerHeight = getMeasuredHeight(); + mTabContainer.layout(l, containerHeight - mTabContainer.getMeasuredHeight(), + r, containerHeight); + } + } } diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index fa8eb5141674..a572e1168372 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -97,7 +97,7 @@ public class ActionBarView extends ViewGroup { private Spinner mSpinner; private LinearLayout mListNavLayout; private HorizontalScrollView mTabScrollView; - private LinearLayout mTabLayout; + private ViewGroup mTabLayout; private View mCustomNavView; private ProgressBar mProgressView; private ProgressBar mIndeterminateProgressView; @@ -112,6 +112,7 @@ public class ActionBarView extends ViewGroup { private boolean mShowMenu; private boolean mUserTitle; + private boolean mIncludeTabs; private MenuBuilder mOptionsMenu; private ActionMenuView mMenuView; @@ -201,6 +202,8 @@ public class ActionBarView extends ViewGroup { mProgressBarPadding = a.getDimensionPixelOffset(R.styleable.ActionBar_progressBarPadding, 0); mItemPadding = a.getDimensionPixelOffset(R.styleable.ActionBar_itemPadding, 0); + mIncludeTabs = a.getBoolean(R.styleable.ActionBar_embeddedTabs, true); + setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT)); final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0); @@ -242,6 +245,14 @@ public class ActionBarView extends ViewGroup { addView(mIndeterminateProgressView); } + public boolean hasEmbeddedTabs() { + return mIncludeTabs; + } + + public void setExternalTabLayout(ViewGroup tabLayout) { + mTabLayout = tabLayout; + } + @Override public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) { // No starting an action mode for an action bar child! (Where would it go?) @@ -389,6 +400,12 @@ public class ActionBarView extends ViewGroup { public void setDisplayOptions(int options) { final int flagsChanged = options ^ mDisplayOptions; mDisplayOptions = options; + + if ((flagsChanged & ActionBar.DISPLAY_DISABLE_HOME) != 0) { + final boolean disableHome = (options & ActionBar.DISPLAY_DISABLE_HOME) != 0; + mHomeLayout.setEnabled(!disableHome); + } + if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) { final int vis = (options & ActionBar.DISPLAY_SHOW_HOME) != 0 ? VISIBLE : GONE; mHomeLayout.setVisibility(vis); @@ -477,7 +494,7 @@ public class ActionBarView extends ViewGroup { } break; case ActionBar.NAVIGATION_MODE_TABS: - if (mTabLayout != null) { + if (mTabScrollView != null) { removeView(mTabScrollView); } } @@ -502,7 +519,9 @@ public class ActionBarView extends ViewGroup { break; case ActionBar.NAVIGATION_MODE_TABS: ensureTabsExist(); - addView(mTabScrollView); + if (mTabScrollView != null) { + addView(mTabScrollView); + } break; } mNavigationMode = mode; @@ -511,15 +530,24 @@ public class ActionBarView extends ViewGroup { } private void ensureTabsExist() { + if (!mIncludeTabs) return; + if (mTabScrollView == null) { mTabScrollView = new HorizontalScrollView(getContext()); mTabScrollView.setHorizontalFadingEdgeEnabled(true); - mTabLayout = new LinearLayout(getContext(), null, - com.android.internal.R.attr.actionBarTabBarStyle); + mTabLayout = createTabContainer(); mTabScrollView.addView(mTabLayout); } } + public ViewGroup createTabContainer() { + ViewGroup result = new LinearLayout(getContext(), null, + com.android.internal.R.attr.actionBarTabBarStyle); + result.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, + mContentHeight)); + return result; + } + public void setDropdownAdapter(SpinnerAdapter adapter) { mSpinnerAdapter = adapter; if (mSpinner != null) { diff --git a/core/res/res/drawable-hdpi/btn_cab_done_default_holo.9.png b/core/res/res/drawable-hdpi/btn_cab_done_default_holo.9.png Binary files differindex c66716fab76e..f5e60541810b 100644 --- a/core/res/res/drawable-hdpi/btn_cab_done_default_holo.9.png +++ b/core/res/res/drawable-hdpi/btn_cab_done_default_holo.9.png diff --git a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo.9.png b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo.9.png Binary files differindex 0f1d9a08cbe5..1121070d5733 100644 --- a/core/res/res/drawable-hdpi/btn_cab_done_focused_holo.9.png +++ b/core/res/res/drawable-hdpi/btn_cab_done_focused_holo.9.png diff --git a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo.9.png b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo.9.png Binary files differindex 391227efcff8..1a072a905368 100644 --- a/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo.9.png +++ b/core/res/res/drawable-hdpi/btn_cab_done_pressed_holo.9.png diff --git a/core/res/res/drawable-mdpi/btn_cab_done_default_holo.9.png b/core/res/res/drawable-mdpi/btn_cab_done_default_holo.9.png Binary files differindex 3a113ee2ea23..7af26cabea27 100644 --- a/core/res/res/drawable-mdpi/btn_cab_done_default_holo.9.png +++ b/core/res/res/drawable-mdpi/btn_cab_done_default_holo.9.png diff --git a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo.9.png b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo.9.png Binary files differindex 8496965b5f00..486c37a72c1f 100644 --- a/core/res/res/drawable-mdpi/btn_cab_done_focused_holo.9.png +++ b/core/res/res/drawable-mdpi/btn_cab_done_focused_holo.9.png diff --git a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo.9.png b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo.9.png Binary files differindex dc70c6a50350..3cfb4bd49764 100644 --- a/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo.9.png +++ b/core/res/res/drawable-mdpi/btn_cab_done_pressed_holo.9.png diff --git a/core/res/res/drawable/btn_cab_done.xml b/core/res/res/drawable/btn_cab_done.xml index 154837d1138c..e3cf461511c0 100644 --- a/core/res/res/drawable/btn_cab_done.xml +++ b/core/res/res/drawable/btn_cab_done.xml @@ -16,11 +16,11 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_window_focused="false" android:state_enabled="true" - android:drawable="@drawable/btn_cab_done_holo" /> + android:drawable="@drawable/btn_cab_done_default_holo" /> <item android:state_pressed="true" android:drawable="@drawable/btn_cab_done_pressed_holo" /> <item android:state_focused="true" android:state_enabled="true" android:drawable="@drawable/btn_cab_done_focused_holo" /> <item android:state_enabled="true" - android:drawable="@drawable/btn_cab_done_holo" /> + android:drawable="@drawable/btn_cab_done_default_holo" /> </selector> diff --git a/core/res/res/values-w480dp/bools.xml b/core/res/res/values-w480dp/bools.xml index ea7eeb58c7d7..c202d90d403b 100644 --- a/core/res/res/values-w480dp/bools.xml +++ b/core/res/res/values-w480dp/bools.xml @@ -18,4 +18,5 @@ --> <resources> <bool name="allow_action_menu_item_text_with_icon">true</bool> + <bool name="action_bar_embed_tabs">true</bool> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index e8767d80a82c..3a44e4f73a82 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4850,6 +4850,7 @@ <flag name="homeAsUp" value="0x4" /> <flag name="showTitle" value="0x8" /> <flag name="showCustom" value="0x10" /> + <flag name="disableHome" value="0x20" /> </attr> <!-- Specifies title text used for navigationMode="normal" --> <attr name="title" /> @@ -4882,6 +4883,9 @@ <!-- Specifies padding that should be applied to the left and right sides of system-provided items in the bar. --> <attr name="itemPadding" format="dimension" /> + <!-- Specifies whether tabs should be embedded within the bar itself (true) + or displayed elsewhere (false). --> + <attr name="embeddedTabs" format="boolean" /> </declare-styleable> <declare-styleable name="ActionMode"> diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml index c7dcb515cd09..6eb006f32f03 100644 --- a/core/res/res/values/bools.xml +++ b/core/res/res/values/bools.xml @@ -18,4 +18,5 @@ --> <resources> <bool name="allow_action_menu_item_text_with_icon">false</bool> + <bool name="action_bar_embed_tabs">false</bool> </resources> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 198ff8b47cbd..8ce35f8aeccc 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1074,6 +1074,7 @@ <item name="android:progressBarStyle">@android:style/Widget.ProgressBar.Horizontal</item> <item name="android:indeterminateProgressStyle">@android:style/Widget.ProgressBar.Small</item> <item name="android:homeLayout">@android:layout/action_bar_home</item> + <item name="android:embeddedTabs">@android:bool/action_bar_embed_tabs</item> </style> <style name="Widget.ActionMode"> |