diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index 1ba6d438b85e5..d0071e3af6026 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -16,6 +16,7 @@ package com.android.internal.app; +import com.android.internal.view.ActionBarPolicy; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.view.menu.SubMenuBuilder; @@ -183,18 +184,13 @@ public class ActionBarImpl extends ActionBar { mContextDisplayMode = mActionView.isSplitActionBar() ? CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL; - // Older apps get the home button interaction enabled by default. - // Newer apps need to enable it explicitly. - setHomeButtonEnabled(mContext.getApplicationInfo().targetSdkVersion < - Build.VERSION_CODES.ICE_CREAM_SANDWICH); - - setHasEmbeddedTabs(mContext.getResources().getBoolean( - com.android.internal.R.bool.action_bar_embed_tabs)); + ActionBarPolicy abp = ActionBarPolicy.get(mContext); + setHomeButtonEnabled(abp.enableHomeButtonByDefault()); + setHasEmbeddedTabs(abp.hasEmbeddedTabs()); } public void onConfigurationChanged(Configuration newConfig) { - setHasEmbeddedTabs(mContext.getResources().getBoolean( - com.android.internal.R.bool.action_bar_embed_tabs)); + setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs()); } private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) { diff --git a/core/java/com/android/internal/view/ActionBarPolicy.java b/core/java/com/android/internal/view/ActionBarPolicy.java new file mode 100644 index 0000000000000..0c6b7800f45c5 --- /dev/null +++ b/core/java/com/android/internal/view/ActionBarPolicy.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 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 com.android.internal.view; + +import com.android.internal.R; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.os.Build; +import android.view.ViewConfiguration; + +/** + * Allows components to query for various configuration policy decisions + * about how the action bar should lay out and behave on the current device. + */ +public class ActionBarPolicy { + private Context mContext; + + public static ActionBarPolicy get(Context context) { + return new ActionBarPolicy(context); + } + + private ActionBarPolicy(Context context) { + mContext = context; + } + + public int getMaxActionButtons() { + return mContext.getResources().getInteger(R.integer.max_action_buttons); + } + + public boolean showsOverflowMenuButton() { + return !ViewConfiguration.get(mContext).hasPermanentMenuKey(); + } + + public int getEmbeddedMenuWidthLimit() { + return mContext.getResources().getDisplayMetrics().widthPixels / 2; + } + + public boolean hasEmbeddedTabs() { + final int targetSdk = mContext.getApplicationInfo().targetSdkVersion; + if (targetSdk >= Build.VERSION_CODES.JELLY_BEAN) { + return mContext.getResources().getBoolean(R.bool.action_bar_embed_tabs); + } + + // The embedded tabs policy changed in Jellybean; give older apps the old policy + // so they get what they expect. + return mContext.getResources().getBoolean(R.bool.action_bar_embed_tabs_pre_jb); + } + + public int getTabContainerHeight() { + TypedArray a = mContext.obtainStyledAttributes(null, R.styleable.ActionBar, + com.android.internal.R.attr.actionBarStyle, 0); + int height = a.getLayoutDimension(R.styleable.ActionBar_height, 0); + Resources r = mContext.getResources(); + if (!hasEmbeddedTabs()) { + // Stacked tabs; limit the height + height = Math.min(height, + r.getDimensionPixelSize(R.dimen.action_bar_stacked_max_height)); + } + a.recycle(); + return height; + } + + public boolean enableHomeButtonByDefault() { + // Older apps get the home button interaction enabled by default. + // Newer apps need to enable it explicitly. + return mContext.getApplicationInfo().targetSdkVersion < + Build.VERSION_CODES.ICE_CREAM_SANDWICH; + } + + public int getStackedTabMaxWidth() { + return mContext.getResources().getDimensionPixelSize( + R.dimen.action_bar_stacked_tab_max_width); + } +} diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index dca45a9a9b64d..73324c0264512 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -16,6 +16,7 @@ package com.android.internal.view.menu; +import com.android.internal.view.ActionBarPolicy; import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView; import android.content.Context; @@ -29,7 +30,6 @@ import android.view.MenuItem; import android.view.SoundEffectConstants; import android.view.View; import android.view.View.MeasureSpec; -import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.ImageButton; @@ -79,17 +79,18 @@ public class ActionMenuPresenter extends BaseMenuPresenter final Resources res = context.getResources(); + final ActionBarPolicy abp = ActionBarPolicy.get(context); if (!mReserveOverflowSet) { - mReserveOverflow = !ViewConfiguration.get(context).hasPermanentMenuKey(); + mReserveOverflow = abp.showsOverflowMenuButton(); } if (!mWidthLimitSet) { - mWidthLimit = res.getDisplayMetrics().widthPixels / 2; + mWidthLimit = abp.getEmbeddedMenuWidthLimit(); } // Measure for initial configuration if (!mMaxItemsSet) { - mMaxItems = res.getInteger(com.android.internal.R.integer.max_action_buttons); + mMaxItems = abp.getMaxActionButtons(); } int width = mWidthLimit; diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java index 1767d68415308..83ac89689942b 100644 --- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java +++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java @@ -15,7 +15,7 @@ */ package com.android.internal.widget; -import com.android.internal.R; +import com.android.internal.view.ActionBarPolicy; import android.animation.Animator; import android.animation.ObjectAnimator; @@ -23,7 +23,6 @@ import android.animation.TimeInterpolator; import android.app.ActionBar; import android.content.Context; import android.content.res.Configuration; -import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.text.TextUtils.TruncateAt; import android.view.Gravity; @@ -55,6 +54,7 @@ public class ScrollingTabContainerView extends HorizontalScrollView private boolean mAllowCollapse; int mMaxTabWidth; + int mStackedTabMaxWidth; private int mContentHeight; private int mSelectedTabIndex; @@ -69,10 +69,9 @@ public class ScrollingTabContainerView extends HorizontalScrollView super(context); setHorizontalScrollBarEnabled(false); - TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar, - com.android.internal.R.attr.actionBarStyle, 0); - setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0)); - a.recycle(); + ActionBarPolicy abp = ActionBarPolicy.get(context); + setContentHeight(abp.getTabContainerHeight()); + mStackedTabMaxWidth = abp.getStackedTabMaxWidth(); mTabLayout = createTabLayout(); addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, @@ -93,6 +92,7 @@ public class ScrollingTabContainerView extends HorizontalScrollView } else { mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2; } + mMaxTabWidth = Math.min(mMaxTabWidth, mStackedTabMaxWidth); } else { mMaxTabWidth = -1; } @@ -187,6 +187,7 @@ public class ScrollingTabContainerView extends HorizontalScrollView final LinearLayout tabLayout = new LinearLayout(getContext(), null, com.android.internal.R.attr.actionBarTabBarStyle); tabLayout.setMeasureWithLargestChildEnabled(true); + tabLayout.setGravity(Gravity.CENTER); tabLayout.setLayoutParams(new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT)); return tabLayout; @@ -205,12 +206,11 @@ public class ScrollingTabContainerView extends HorizontalScrollView protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + ActionBarPolicy abp = ActionBarPolicy.get(getContext()); // Action bar can change size on configuration changes. // Reread the desired height from the theme-specified style. - TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar, - com.android.internal.R.attr.actionBarStyle, 0); - setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0)); - a.recycle(); + setContentHeight(abp.getTabContainerHeight()); + mStackedTabMaxWidth = abp.getStackedTabMaxWidth(); } public void animateToVisibility(int visibility) { diff --git a/core/res/res/values-port/bools.xml b/core/res/res/values-port/bools.xml new file mode 100644 index 0000000000000..fc62b69b85840 --- /dev/null +++ b/core/res/res/values-port/bools.xml @@ -0,0 +1,19 @@ + + + + + false + diff --git a/core/res/res/values-sw600dp/bools.xml b/core/res/res/values-sw600dp/bools.xml index 2097049e3229c..e74379cc46f83 100644 --- a/core/res/res/values-sw600dp/bools.xml +++ b/core/res/res/values-sw600dp/bools.xml @@ -17,6 +17,5 @@ true false - false false diff --git a/core/res/res/values-w480dp/bools.xml b/core/res/res/values-w480dp/bools.xml index 57a2939b34ed3..3a463a6a77d01 100644 --- a/core/res/res/values-w480dp/bools.xml +++ b/core/res/res/values-w480dp/bools.xml @@ -17,6 +17,6 @@ */ --> - true + true false diff --git a/core/res/res/values-w720dp/bools.xml b/core/res/res/values-w720dp/bools.xml new file mode 100644 index 0000000000000..352c3198c3035 --- /dev/null +++ b/core/res/res/values-w720dp/bools.xml @@ -0,0 +1,19 @@ + + + + + false + diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml index 87a98e2c220d6..f9762b18f9ad5 100644 --- a/core/res/res/values/bools.xml +++ b/core/res/res/values/bools.xml @@ -15,7 +15,8 @@ --> - false + true + false true false true diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 0442be87ff641..ef80160bd3489 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -213,4 +213,13 @@ 56dip + + + 48dp + + + 180dp + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index b564b97ae8a81..03ba08c026fe4 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -234,6 +234,7 @@ + @@ -292,6 +293,8 @@ + +