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 requestLayout(); 99 } 100 getContentHeight()101 public int getContentHeight() { 102 return mContentHeight; 103 } 104 setSplitView(ActionBarContainer splitView)105 public void setSplitView(ActionBarContainer splitView) { 106 mSplitView = splitView; 107 } 108 109 /** 110 * @return Current visibility or if animating, the visibility being animated to. 111 */ getAnimatedVisibility()112 public int getAnimatedVisibility() { 113 if (mVisibilityAnim != null) { 114 return mVisAnimListener.mFinalVisibility; 115 } 116 return getVisibility(); 117 } 118 animateToVisibility(int visibility)119 public void animateToVisibility(int visibility) { 120 if (mVisibilityAnim != null) { 121 mVisibilityAnim.cancel(); 122 } 123 if (visibility == VISIBLE) { 124 if (getVisibility() != VISIBLE) { 125 setAlpha(0); 126 if (mSplitView != null && mMenuView != null) { 127 mMenuView.setAlpha(0); 128 } 129 } 130 ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1); 131 anim.setDuration(FADE_DURATION); 132 anim.setInterpolator(sAlphaInterpolator); 133 if (mSplitView != null && mMenuView != null) { 134 AnimatorSet set = new AnimatorSet(); 135 ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1); 136 splitAnim.setDuration(FADE_DURATION); 137 set.addListener(mVisAnimListener.withFinalVisibility(visibility)); 138 set.play(anim).with(splitAnim); 139 set.start(); 140 } else { 141 anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); 142 anim.start(); 143 } 144 } else { 145 ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0); 146 anim.setDuration(FADE_DURATION); 147 anim.setInterpolator(sAlphaInterpolator); 148 if (mSplitView != null && mMenuView != null) { 149 AnimatorSet set = new AnimatorSet(); 150 ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0); 151 splitAnim.setDuration(FADE_DURATION); 152 set.addListener(mVisAnimListener.withFinalVisibility(visibility)); 153 set.play(anim).with(splitAnim); 154 set.start(); 155 } else { 156 anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); 157 anim.start(); 158 } 159 } 160 } 161 162 @Override setVisibility(int visibility)163 public void setVisibility(int visibility) { 164 if (visibility != getVisibility()) { 165 if (mVisibilityAnim != null) { 166 mVisibilityAnim.end(); 167 } 168 super.setVisibility(visibility); 169 } 170 } 171 showOverflowMenu()172 public boolean showOverflowMenu() { 173 if (mActionMenuPresenter != null) { 174 return mActionMenuPresenter.showOverflowMenu(); 175 } 176 return false; 177 } 178 postShowOverflowMenu()179 public void postShowOverflowMenu() { 180 post(new Runnable() { 181 public void run() { 182 showOverflowMenu(); 183 } 184 }); 185 } 186 hideOverflowMenu()187 public boolean hideOverflowMenu() { 188 if (mActionMenuPresenter != null) { 189 return mActionMenuPresenter.hideOverflowMenu(); 190 } 191 return false; 192 } 193 isOverflowMenuShowing()194 public boolean isOverflowMenuShowing() { 195 if (mActionMenuPresenter != null) { 196 return mActionMenuPresenter.isOverflowMenuShowing(); 197 } 198 return false; 199 } 200 isOverflowReserved()201 public boolean isOverflowReserved() { 202 return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved(); 203 } 204 dismissPopupMenus()205 public void dismissPopupMenus() { 206 if (mActionMenuPresenter != null) { 207 mActionMenuPresenter.dismissPopupMenus(); 208 } 209 } 210 measureChildView(View child, int availableWidth, int childSpecHeight, int spacing)211 protected int measureChildView(View child, int availableWidth, int childSpecHeight, 212 int spacing) { 213 child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), 214 childSpecHeight); 215 216 availableWidth -= child.getMeasuredWidth(); 217 availableWidth -= spacing; 218 219 return Math.max(0, availableWidth); 220 } 221 positionChild(View child, int x, int y, int contentHeight)222 protected int positionChild(View child, int x, int y, int contentHeight) { 223 int childWidth = child.getMeasuredWidth(); 224 int childHeight = child.getMeasuredHeight(); 225 int childTop = y + (contentHeight - childHeight) / 2; 226 227 child.layout(x, childTop, x + childWidth, childTop + childHeight); 228 229 return childWidth; 230 } 231 positionChildInverse(View child, int x, int y, int contentHeight)232 protected int positionChildInverse(View child, int x, int y, int contentHeight) { 233 int childWidth = child.getMeasuredWidth(); 234 int childHeight = child.getMeasuredHeight(); 235 int childTop = y + (contentHeight - childHeight) / 2; 236 237 child.layout(x - childWidth, childTop, x, childTop + childHeight); 238 239 return childWidth; 240 } 241 242 protected class VisibilityAnimListener implements Animator.AnimatorListener { 243 private boolean mCanceled = false; 244 int mFinalVisibility; 245 withFinalVisibility(int visibility)246 public VisibilityAnimListener withFinalVisibility(int visibility) { 247 mFinalVisibility = visibility; 248 return this; 249 } 250 251 @Override onAnimationStart(Animator animation)252 public void onAnimationStart(Animator animation) { 253 setVisibility(VISIBLE); 254 mVisibilityAnim = animation; 255 mCanceled = false; 256 } 257 258 @Override onAnimationEnd(Animator animation)259 public void onAnimationEnd(Animator animation) { 260 if (mCanceled) return; 261 262 mVisibilityAnim = null; 263 setVisibility(mFinalVisibility); 264 if (mSplitView != null && mMenuView != null) { 265 mMenuView.setVisibility(mFinalVisibility); 266 } 267 } 268 269 @Override onAnimationCancel(Animator animation)270 public void onAnimationCancel(Animator animation) { 271 mCanceled = true; 272 } 273 274 @Override onAnimationRepeat(Animator animation)275 public void onAnimationRepeat(Animator animation) { 276 } 277 } 278 } 279