Action bar work for phones
Drop tabs to a second row at < w480dp
Make 9-patches for the cab's "done" button thinner
Add a "disable home" display option to the action bar to turn off
focus and touch feedback when tapping home would do nothing
Change-Id: Ib2eedf311655f02055357321e2e9ad5b9037fed1
diff --git a/api/current.txt b/api/current.txt
index fd05e48..e66b9a3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2102,6 +2102,7 @@
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 @@
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 a9e84d7..cac06ec 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -107,6 +107,18 @@
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 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 9652085..dccfa6c 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.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 @@
private ActionBarContextView mUpperContextView;
private LinearLayout mLowerContextView;
private View mContentView;
+ private ViewGroup mExternalTabView;
private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
@@ -172,6 +175,18 @@
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 @@
}
@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 @@
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 @@
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 c9b0ec9..3deb036 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.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import android.view.View;
import android.widget.FrameLayout;
/**
@@ -29,6 +30,7 @@
*/
public class ActionBarContainer extends FrameLayout {
private boolean mIsTransitioning;
+ private View mTabContainer;
public ActionBarContainer(Context context) {
this(context, null);
@@ -65,6 +67,44 @@
@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 fa8eb51..a572e116 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -97,7 +97,7 @@
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 @@
private boolean mShowMenu;
private boolean mUserTitle;
+ private boolean mIncludeTabs;
private MenuBuilder mOptionsMenu;
private ActionMenuView mMenuView;
@@ -201,6 +202,8 @@
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 @@
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 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 @@
}
break;
case ActionBar.NAVIGATION_MODE_TABS:
- if (mTabLayout != null) {
+ if (mTabScrollView != null) {
removeView(mTabScrollView);
}
}
@@ -502,7 +519,9 @@
break;
case ActionBar.NAVIGATION_MODE_TABS:
ensureTabsExist();
- addView(mTabScrollView);
+ if (mTabScrollView != null) {
+ addView(mTabScrollView);
+ }
break;
}
mNavigationMode = mode;
@@ -511,15 +530,24 @@
}
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
index c66716f..f5e6054 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
Binary files differ
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
index 0f1d9a0..1121070 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
Binary files differ
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
index 391227e..1a072a9 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
Binary files differ
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
index 3a113ee..7af26ca 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
Binary files differ
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
index 8496965..486c37a 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
Binary files differ
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
index dc70c6a..3cfb4bd 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
Binary files differ
diff --git a/core/res/res/drawable/btn_cab_done.xml b/core/res/res/drawable/btn_cab_done.xml
index 154837d..e3cf461 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 ea7eeb5..c202d90 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 e8767d8..3a44e4f 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 c7dcb51..6eb006f 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 198ff8b..8ce35f8 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">