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 */ 16package com.android.internal.widget; 17 18import com.android.internal.R; 19import com.android.internal.view.menu.ActionMenuPresenter; 20import com.android.internal.view.menu.ActionMenuView; 21 22import android.animation.Animator; 23import android.animation.AnimatorSet; 24import android.animation.ObjectAnimator; 25import android.animation.TimeInterpolator; 26import android.content.Context; 27import android.content.res.Configuration; 28import android.content.res.TypedArray; 29import android.util.AttributeSet; 30import android.view.View; 31import android.view.ViewGroup; 32import android.view.animation.DecelerateInterpolator; 33 34public 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 49 public AbsActionBarView(Context context) { 50 super(context); 51 } 52 53 public AbsActionBarView(Context context, AttributeSet attrs) { 54 super(context, attrs); 55 } 56 57 public AbsActionBarView(Context context, AttributeSet attrs, int defStyle) { 58 super(context, attrs, defStyle); 59 } 60 61 @Override 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 */ 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 */ 92 public void setSplitWhenNarrow(boolean splitWhenNarrow) { 93 mSplitWhenNarrow = splitWhenNarrow; 94 } 95 96 public void setContentHeight(int height) { 97 mContentHeight = height; 98 if (mMenuView != null) { 99 mMenuView.setMaxItemHeight(mContentHeight); 100 } 101 requestLayout(); 102 } 103 104 public int getContentHeight() { 105 return mContentHeight; 106 } 107 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 */ 115 public int getAnimatedVisibility() { 116 if (mVisibilityAnim != null) { 117 return mVisAnimListener.mFinalVisibility; 118 } 119 return getVisibility(); 120 } 121 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 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 175 public boolean showOverflowMenu() { 176 if (mActionMenuPresenter != null) { 177 return mActionMenuPresenter.showOverflowMenu(); 178 } 179 return false; 180 } 181 182 public void postShowOverflowMenu() { 183 post(new Runnable() { 184 public void run() { 185 showOverflowMenu(); 186 } 187 }); 188 } 189 190 public boolean hideOverflowMenu() { 191 if (mActionMenuPresenter != null) { 192 return mActionMenuPresenter.hideOverflowMenu(); 193 } 194 return false; 195 } 196 197 public boolean isOverflowMenuShowing() { 198 if (mActionMenuPresenter != null) { 199 return mActionMenuPresenter.isOverflowMenuShowing(); 200 } 201 return false; 202 } 203 204 public boolean isOverflowReserved() { 205 return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved(); 206 } 207 208 public void dismissPopupMenus() { 209 if (mActionMenuPresenter != null) { 210 mActionMenuPresenter.dismissPopupMenus(); 211 } 212 } 213 214 protected int measureChildView(View child, int availableWidth, int childSpecHeight, 215 int spacing) { 216 child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), 217 childSpecHeight); 218 219 availableWidth -= child.getMeasuredWidth(); 220 availableWidth -= spacing; 221 222 return Math.max(0, availableWidth); 223 } 224 225 static protected int next(int x, int val, boolean isRtl) { 226 return isRtl ? x - val : x + val; 227 } 228 229 protected int positionChild(View child, int x, int y, int contentHeight, boolean reverse) { 230 int childWidth = child.getMeasuredWidth(); 231 int childHeight = child.getMeasuredHeight(); 232 int childTop = y + (contentHeight - childHeight) / 2; 233 234 if (reverse) { 235 child.layout(x - childWidth, childTop, x, childTop + childHeight); 236 } else { 237 child.layout(x, childTop, x + childWidth, childTop + childHeight); 238 } 239 240 return (reverse ? -childWidth : childWidth); 241 } 242 243 protected class VisibilityAnimListener implements Animator.AnimatorListener { 244 private boolean mCanceled = false; 245 int mFinalVisibility; 246 247 public VisibilityAnimListener withFinalVisibility(int visibility) { 248 mFinalVisibility = visibility; 249 return this; 250 } 251 252 @Override 253 public void onAnimationStart(Animator animation) { 254 setVisibility(VISIBLE); 255 mVisibilityAnim = animation; 256 mCanceled = false; 257 } 258 259 @Override 260 public void onAnimationEnd(Animator animation) { 261 if (mCanceled) return; 262 263 mVisibilityAnim = null; 264 setVisibility(mFinalVisibility); 265 if (mSplitView != null && mMenuView != null) { 266 mMenuView.setVisibility(mFinalVisibility); 267 } 268 } 269 270 @Override 271 public void onAnimationCancel(Animator animation) { 272 mCanceled = true; 273 } 274 275 @Override 276 public void onAnimationRepeat(Animator animation) { 277 } 278 } 279} 280