1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.internal.widget; 17 18 import com.android.internal.R; 19 import com.android.internal.view.menu.ActionMenuPresenter; 20 import com.android.internal.view.menu.ActionMenuView; 21 22 import android.animation.Animator; 23 import android.animation.AnimatorSet; 24 import android.animation.ObjectAnimator; 25 import android.animation.TimeInterpolator; 26 import android.content.Context; 27 import android.content.res.Configuration; 28 import android.content.res.TypedArray; 29 import android.util.AttributeSet; 30 import android.view.View; 31 import android.view.ViewGroup; 32 import android.view.animation.DecelerateInterpolator; 33 34 public abstract class AbsActionBarView extends ViewGroup { 35 protected ActionMenuView mMenuView; 36 protected ActionMenuPresenter mActionMenuPresenter; 37 protected ActionBarContainer mSplitView; 38 protected boolean mSplitActionBar; 39 protected boolean mSplitWhenNarrow; 40 protected int mContentHeight; 41 42 protected Animator mVisibilityAnim; 43 protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener(); 44 45 private static final TimeInterpolator sAlphaInterpolator = new DecelerateInterpolator(); 46 47 private static final int FADE_DURATION = 200; 48 AbsActionBarView(Context context)49 public AbsActionBarView(Context context) { 50 super(context); 51 } 52 AbsActionBarView(Context context, AttributeSet attrs)53 public AbsActionBarView(Context context, AttributeSet attrs) { 54 super(context, attrs); 55 } 56 AbsActionBarView(Context context, AttributeSet attrs, int defStyle)57 public AbsActionBarView(Context context, AttributeSet attrs, int defStyle) { 58 super(context, attrs, defStyle); 59 } 60 61 @Override onConfigurationChanged(Configuration newConfig)62 protected void onConfigurationChanged(Configuration newConfig) { 63 super.onConfigurationChanged(newConfig); 64 65 // Action bar can change size on configuration changes. 66 // Reread the desired height from the theme-specified style. 67 TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar, 68 com.android.internal.R.attr.actionBarStyle, 0); 69 setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0)); 70 a.recycle(); 71 if (mSplitWhenNarrow) { 72 setSplitActionBar(getContext().getResources().getBoolean( 73 com.android.internal.R.bool.split_action_bar_is_narrow)); 74 } 75 if (mActionMenuPresenter != null) { 76 mActionMenuPresenter.onConfigurationChanged(newConfig); 77 } 78 } 79 80 /** 81 * Sets whether the bar should be split right now, no questions asked. 82 * @param split true if the bar should split 83 */ setSplitActionBar(boolean split)84 public void setSplitActionBar(boolean split) { 85 mSplitActionBar = split; 86 } 87 88 /** 89 * Sets whether the bar should split if we enter a narrow screen configuration. 90 * @param splitWhenNarrow true if the bar should check to split after a config change 91 */ setSplitWhenNarrow(boolean splitWhenNarrow)92 public void setSplitWhenNarrow(boolean splitWhenNarrow) { 93 mSplitWhenNarrow = splitWhenNarrow; 94 } 95 setContentHeight(int height)96 public void setContentHeight(int height) { 97 mContentHeight = height; 98 if (mMenuView != null) { 99 mMenuView.setMaxItemHeight(mContentHeight); 100 } 101 requestLayout(); 102 } 103 getContentHeight()104 public int getContentHeight() { 105 return mContentHeight; 106 } 107 setSplitView(ActionBarContainer splitView)108 public void setSplitView(ActionBarContainer splitView) { 109 mSplitView = splitView; 110 } 111 112 /** 113 * @return Current visibility or if animating, the visibility being animated to. 114 */ getAnimatedVisibility()115 public int getAnimatedVisibility() { 116 if (mVisibilityAnim != null) { 117 return mVisAnimListener.mFinalVisibility; 118 } 119 return getVisibility(); 120 } 121 animateToVisibility(int visibility)122 public void animateToVisibility(int visibility) { 123 if (mVisibilityAnim != null) { 124 mVisibilityAnim.cancel(); 125 } 126 if (visibility == VISIBLE) { 127 if (getVisibility() != VISIBLE) { 128 setAlpha(0); 129 if (mSplitView != null && mMenuView != null) { 130 mMenuView.setAlpha(0); 131 } 132 } 133 ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1); 134 anim.setDuration(FADE_DURATION); 135 anim.setInterpolator(sAlphaInterpolator); 136 if (mSplitView != null && mMenuView != null) { 137 AnimatorSet set = new AnimatorSet(); 138 ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1); 139 splitAnim.setDuration(FADE_DURATION); 140 set.addListener(mVisAnimListener.withFinalVisibility(visibility)); 141 set.play(anim).with(splitAnim); 142 set.start(); 143 } else { 144 anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); 145 anim.start(); 146 } 147 } else { 148 ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0); 149 anim.setDuration(FADE_DURATION); 150 anim.setInterpolator(sAlphaInterpolator); 151 if (mSplitView != null && mMenuView != null) { 152 AnimatorSet set = new AnimatorSet(); 153 ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0); 154 splitAnim.setDuration(FADE_DURATION); 155 set.addListener(mVisAnimListener.withFinalVisibility(visibility)); 156 set.play(anim).with(splitAnim); 157 set.start(); 158 } else { 159 anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); 160 anim.start(); 161 } 162 } 163 } 164 165 @Override setVisibility(int visibility)166 public void setVisibility(int visibility) { 167 if (visibility != getVisibility()) { 168 if (mVisibilityAnim != null) { 169 mVisibilityAnim.end(); 170 } 171 super.setVisibility(visibility); 172 } 173 } 174 showOverflowMenu()175 public boolean showOverflowMenu() { 176 if (mActionMenuPresenter != null) { 177 return mActionMenuPresenter.showOverflowMenu(); 178 } 179 return false; 180 } 181 postShowOverflowMenu()182 public void postShowOverflowMenu() { 183 post(new Runnable() { 184 public void run() { 185 showOverflowMenu(); 186 } 187 }); 188 } 189 hideOverflowMenu()190 public boolean hideOverflowMenu() { 191 if (mActionMenuPresenter != null) { 192 return mActionMenuPresenter.hideOverflowMenu(); 193 } 194 return false; 195 } 196 isOverflowMenuShowing()197 public boolean isOverflowMenuShowing() { 198 if (mActionMenuPresenter != null) { 199 return mActionMenuPresenter.isOverflowMenuShowing(); 200 } 201 return false; 202 } 203 isOverflowMenuShowPending()204 public boolean isOverflowMenuShowPending() { 205 if (mActionMenuPresenter != null) { 206 return mActionMenuPresenter.isOverflowMenuShowPending(); 207 } 208 return false; 209 } 210 isOverflowReserved()211 public boolean isOverflowReserved() { 212 return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved(); 213 } 214 dismissPopupMenus()215 public void dismissPopupMenus() { 216 if (mActionMenuPresenter != null) { 217 mActionMenuPresenter.dismissPopupMenus(); 218 } 219 } 220 measureChildView(View child, int availableWidth, int childSpecHeight, int spacing)221 protected int measureChildView(View child, int availableWidth, int childSpecHeight, 222 int spacing) { 223 child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), 224 childSpecHeight); 225 226 availableWidth -= child.getMeasuredWidth(); 227 availableWidth -= spacing; 228 229 return Math.max(0, availableWidth); 230 } 231 next(int x, int val, boolean isRtl)232 static protected int next(int x, int val, boolean isRtl) { 233 return isRtl ? x - val : x + val; 234 } 235 positionChild(View child, int x, int y, int contentHeight, boolean reverse)236 protected int positionChild(View child, int x, int y, int contentHeight, boolean reverse) { 237 int childWidth = child.getMeasuredWidth(); 238 int childHeight = child.getMeasuredHeight(); 239 int childTop = y + (contentHeight - childHeight) / 2; 240 241 if (reverse) { 242 child.layout(x - childWidth, childTop, x, childTop + childHeight); 243 } else { 244 child.layout(x, childTop, x + childWidth, childTop + childHeight); 245 } 246 247 return (reverse ? -childWidth : childWidth); 248 } 249 250 protected class VisibilityAnimListener implements Animator.AnimatorListener { 251 private boolean mCanceled = false; 252 int mFinalVisibility; 253 withFinalVisibility(int visibility)254 public VisibilityAnimListener withFinalVisibility(int visibility) { 255 mFinalVisibility = visibility; 256 return this; 257 } 258 259 @Override onAnimationStart(Animator animation)260 public void onAnimationStart(Animator animation) { 261 setVisibility(VISIBLE); 262 mVisibilityAnim = animation; 263 mCanceled = false; 264 } 265 266 @Override onAnimationEnd(Animator animation)267 public void onAnimationEnd(Animator animation) { 268 if (mCanceled) return; 269 270 mVisibilityAnim = null; 271 setVisibility(mFinalVisibility); 272 if (mSplitView != null && mMenuView != null) { 273 mMenuView.setVisibility(mFinalVisibility); 274 } 275 } 276 277 @Override onAnimationCancel(Animator animation)278 public void onAnimationCancel(Animator animation) { 279 mCanceled = true; 280 } 281 282 @Override onAnimationRepeat(Animator animation)283 public void onAnimationRepeat(Animator animation) { 284 } 285 } 286 } 287