blob: c82323eedb131c861f4fa9d650d7101857cca130 [file] [log] [blame]
Adam Powell89e06452010-06-23 20:24:52 -07001/*
2 * Copyright (C) 2010 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;
Adam Powell696cba52011-03-29 10:38:16 -070019import com.android.internal.view.menu.ActionMenuPresenter;
Adam Powell2c9c9fe2010-07-16 10:17:57 -070020import com.android.internal.view.menu.ActionMenuView;
21import com.android.internal.view.menu.MenuBuilder;
Adam Powell89e06452010-06-23 20:24:52 -070022
Adam Powelld8b3f2e2010-12-02 13:37:03 -080023import android.animation.Animator;
24import android.animation.Animator.AnimatorListener;
25import android.animation.AnimatorSet;
26import android.animation.ObjectAnimator;
Adam Powell89e06452010-06-23 20:24:52 -070027import android.content.Context;
28import android.content.res.TypedArray;
Adam Powell89e06452010-06-23 20:24:52 -070029import android.util.AttributeSet;
Adam Powell6e346362010-07-23 10:18:23 -070030import android.view.ActionMode;
Adam Powell89e06452010-06-23 20:24:52 -070031import android.view.LayoutInflater;
Adam Powell89e06452010-06-23 20:24:52 -070032import android.view.View;
Adam Powell640a66e2011-04-29 10:18:53 -070033import android.view.ViewGroup.LayoutParams;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080034import android.view.animation.DecelerateInterpolator;
Adam Powell0e94b512010-06-29 17:58:20 -070035import android.widget.LinearLayout;
Adam Powell89e06452010-06-23 20:24:52 -070036import android.widget.TextView;
37
38/**
39 * @hide
40 */
Adam Powell640a66e2011-04-29 10:18:53 -070041public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
Adam Powell77769c72011-01-17 12:05:08 -080042 private static final String TAG = "ActionBarContextView";
43
Adam Powell89e06452010-06-23 20:24:52 -070044 private int mContentHeight;
45
46 private CharSequence mTitle;
47 private CharSequence mSubtitle;
Adam Powellf16888f2010-10-11 17:05:29 -070048
49 private View mClose;
Adam Powell89e06452010-06-23 20:24:52 -070050 private View mCustomView;
Adam Powell0e94b512010-06-29 17:58:20 -070051 private LinearLayout mTitleLayout;
Adam Powell89e06452010-06-23 20:24:52 -070052 private TextView mTitleView;
Adam Powell0e94b512010-06-29 17:58:20 -070053 private TextView mSubtitleView;
Adam Powellbc234a12010-09-09 17:03:50 -070054 private int mTitleStyleRes;
55 private int mSubtitleStyleRes;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080056
57 private Animator mCurrentAnimation;
58 private boolean mAnimateInOnLayout;
59 private int mAnimationMode;
60
61 private static final int ANIMATE_IDLE = 0;
62 private static final int ANIMATE_IN = 1;
63 private static final int ANIMATE_OUT = 2;
Adam Powell89e06452010-06-23 20:24:52 -070064
65 public ActionBarContextView(Context context) {
Adam Powellbc234a12010-09-09 17:03:50 -070066 this(context, null);
Adam Powell89e06452010-06-23 20:24:52 -070067 }
68
69 public ActionBarContextView(Context context, AttributeSet attrs) {
Adam Powellbc234a12010-09-09 17:03:50 -070070 this(context, attrs, com.android.internal.R.attr.actionModeStyle);
Adam Powell89e06452010-06-23 20:24:52 -070071 }
72
73 public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) {
74 super(context, attrs, defStyle);
75
Adam Powellbc234a12010-09-09 17:03:50 -070076 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionMode, defStyle, 0);
Adam Powell89e06452010-06-23 20:24:52 -070077 setBackgroundDrawable(a.getDrawable(
Adam Powellbc234a12010-09-09 17:03:50 -070078 com.android.internal.R.styleable.ActionMode_background));
Adam Powellbc234a12010-09-09 17:03:50 -070079 mTitleStyleRes = a.getResourceId(
80 com.android.internal.R.styleable.ActionMode_titleTextStyle, 0);
81 mSubtitleStyleRes = a.getResourceId(
82 com.android.internal.R.styleable.ActionMode_subtitleTextStyle, 0);
Adam Powelldcdefbb2010-07-19 15:45:22 -070083
Adam Powelle2194442010-08-12 18:13:03 -070084 mContentHeight = a.getLayoutDimension(
Adam Powellbc234a12010-09-09 17:03:50 -070085 com.android.internal.R.styleable.ActionMode_height, 0);
Adam Powell89e06452010-06-23 20:24:52 -070086 a.recycle();
87 }
Adam Powell9146ac72010-08-16 18:53:38 -070088
Adam Powelle2194442010-08-12 18:13:03 -070089 public void setHeight(int height) {
90 mContentHeight = height;
91 }
92
Adam Powell89e06452010-06-23 20:24:52 -070093 public void setCustomView(View view) {
94 if (mCustomView != null) {
95 removeView(mCustomView);
96 }
97 mCustomView = view;
Adam Powell0e94b512010-06-29 17:58:20 -070098 if (mTitleLayout != null) {
99 removeView(mTitleLayout);
100 mTitleLayout = null;
Adam Powell89e06452010-06-23 20:24:52 -0700101 }
102 if (view != null) {
103 addView(view);
104 }
105 requestLayout();
106 }
Adam Powell0e94b512010-06-29 17:58:20 -0700107
Adam Powell89e06452010-06-23 20:24:52 -0700108 public void setTitle(CharSequence title) {
109 mTitle = title;
Adam Powell0e94b512010-06-29 17:58:20 -0700110 initTitle();
111 }
112
113 public void setSubtitle(CharSequence subtitle) {
114 mSubtitle = subtitle;
115 initTitle();
116 }
117
Adam Powell29ed7572010-07-14 16:24:56 -0700118 public CharSequence getTitle() {
119 return mTitle;
120 }
121
122 public CharSequence getSubtitle() {
123 return mSubtitle;
124 }
125
Adam Powell0e94b512010-06-29 17:58:20 -0700126 private void initTitle() {
127 if (mTitleLayout == null) {
Adam Powell89e06452010-06-23 20:24:52 -0700128 LayoutInflater inflater = LayoutInflater.from(getContext());
Adam Powellf16888f2010-10-11 17:05:29 -0700129 inflater.inflate(R.layout.action_bar_title_item, this);
130 mTitleLayout = (LinearLayout) getChildAt(getChildCount() - 1);
Adam Powell0e94b512010-06-29 17:58:20 -0700131 mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title);
132 mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
133 if (mTitle != null) {
134 mTitleView.setText(mTitle);
Adam Powellbc234a12010-09-09 17:03:50 -0700135 if (mTitleStyleRes != 0) {
136 mTitleView.setTextAppearance(mContext, mTitleStyleRes);
137 }
Adam Powell89e06452010-06-23 20:24:52 -0700138 }
Adam Powell0e94b512010-06-29 17:58:20 -0700139 if (mSubtitle != null) {
140 mSubtitleView.setText(mSubtitle);
Adam Powellbc234a12010-09-09 17:03:50 -0700141 if (mSubtitleStyleRes != 0) {
142 mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes);
143 }
Adam Powell8350f7d2010-07-28 14:27:28 -0700144 mSubtitleView.setVisibility(VISIBLE);
Adam Powell0e94b512010-06-29 17:58:20 -0700145 }
Adam Powell89e06452010-06-23 20:24:52 -0700146 } else {
Adam Powell0e94b512010-06-29 17:58:20 -0700147 mTitleView.setText(mTitle);
148 mSubtitleView.setText(mSubtitle);
Adam Powell8350f7d2010-07-28 14:27:28 -0700149 mSubtitleView.setVisibility(mSubtitle != null ? VISIBLE : GONE);
Adam Powell0e94b512010-06-29 17:58:20 -0700150 if (mTitleLayout.getParent() == null) {
151 addView(mTitleLayout);
Adam Powell89e06452010-06-23 20:24:52 -0700152 }
153 }
154 }
Adam Powell0e94b512010-06-29 17:58:20 -0700155
Adam Powell6e346362010-07-23 10:18:23 -0700156 public void initForMode(final ActionMode mode) {
Adam Powellf16888f2010-10-11 17:05:29 -0700157 if (mClose == null) {
158 LayoutInflater inflater = LayoutInflater.from(mContext);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800159 mClose = inflater.inflate(R.layout.action_mode_close_item, this, false);
160 addView(mClose);
Adam Powell45f1e082010-12-10 14:20:13 -0800161 } else if (mClose.getParent() == null) {
Adam Powellf16888f2010-10-11 17:05:29 -0700162 addView(mClose);
Adam Powell89e06452010-06-23 20:24:52 -0700163 }
Adam Powellf16888f2010-10-11 17:05:29 -0700164
165 View closeButton = mClose.findViewById(R.id.action_mode_close_button);
166 closeButton.setOnClickListener(new OnClickListener() {
Adam Powell269b8bb2010-07-20 16:46:42 -0700167 public void onClick(View v) {
168 mode.finish();
169 }
170 });
Adam Powell89e06452010-06-23 20:24:52 -0700171
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700172 final MenuBuilder menu = (MenuBuilder) mode.getMenu();
Adam Powell640a66e2011-04-29 10:18:53 -0700173 mMenuPresenter = new ActionMenuPresenter();
174 menu.addMenuPresenter(mMenuPresenter);
175 mMenuView = (ActionMenuView) mMenuPresenter.getMenuView(this);
176
177 final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
178 LayoutParams.MATCH_PARENT);
179 mMenuView.setLayoutParams(layoutParams);
180 if (mSplitView == null) {
181 addView(mMenuView);
182 } else {
183 // Allow full screen width in split mode.
184 mMenuPresenter.setWidthLimit(
185 getContext().getResources().getDisplayMetrics().widthPixels, true);
186 // No limit to the item count; use whatever will fit.
187 mMenuPresenter.setItemLimit(Integer.MAX_VALUE);
188 // Span the whole width
189 layoutParams.width = LayoutParams.MATCH_PARENT;
190 mSplitView.addView(mMenuView);
191 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800192
193 mAnimateInOnLayout = true;
Adam Powell89e06452010-06-23 20:24:52 -0700194 }
Adam Powell0e94b512010-06-29 17:58:20 -0700195
Adam Powell89e06452010-06-23 20:24:52 -0700196 public void closeMode() {
Adam Powell45f1e082010-12-10 14:20:13 -0800197 if (mAnimationMode == ANIMATE_OUT) {
198 // Called again during close; just finish what we were doing.
199 return;
200 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800201 if (mClose == null) {
202 killMode();
203 return;
204 }
205
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800206 finishAnimation();
Adam Powella1e63582011-01-18 16:51:22 -0800207 mAnimationMode = ANIMATE_OUT;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800208 mCurrentAnimation = makeOutAnimation();
209 mCurrentAnimation.start();
210 }
211
212 private void finishAnimation() {
Adam Powell45f1e082010-12-10 14:20:13 -0800213 final Animator a = mCurrentAnimation;
Adam Powella1e63582011-01-18 16:51:22 -0800214 if (a != null) {
Adam Powell45f1e082010-12-10 14:20:13 -0800215 mCurrentAnimation = null;
216 a.end();
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800217 }
218 }
219
220 public void killMode() {
221 finishAnimation();
Adam Powell89e06452010-06-23 20:24:52 -0700222 removeAllViews();
Adam Powell640a66e2011-04-29 10:18:53 -0700223 if (mSplitView != null) {
224 mSplitView.removeView(mMenuView);
225 }
Adam Powell89e06452010-06-23 20:24:52 -0700226 mCustomView = null;
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700227 mMenuView = null;
Adam Powell00bba682011-01-08 15:53:38 -0800228 mAnimateInOnLayout = false;
Adam Powell89e06452010-06-23 20:24:52 -0700229 }
Adam Powell0e94b512010-06-29 17:58:20 -0700230
Adam Powellf6148c52010-08-11 21:10:16 -0700231 public boolean showOverflowMenu() {
Adam Powell640a66e2011-04-29 10:18:53 -0700232 if (mMenuPresenter != null) {
233 return mMenuPresenter.showOverflowMenu();
Adam Powellf6148c52010-08-11 21:10:16 -0700234 }
235 return false;
236 }
237
238 public boolean hideOverflowMenu() {
Adam Powell640a66e2011-04-29 10:18:53 -0700239 if (mMenuPresenter != null) {
240 return mMenuPresenter.hideOverflowMenu();
Adam Powellf6148c52010-08-11 21:10:16 -0700241 }
242 return false;
243 }
244
245 public boolean isOverflowMenuShowing() {
Adam Powell640a66e2011-04-29 10:18:53 -0700246 if (mMenuPresenter != null) {
247 return mMenuPresenter.isOverflowMenuShowing();
Adam Powellf6148c52010-08-11 21:10:16 -0700248 }
249 return false;
250 }
251
Adam Powell89e06452010-06-23 20:24:52 -0700252 @Override
Adam Powella7db0372010-06-30 17:08:47 -0700253 protected LayoutParams generateDefaultLayoutParams() {
254 // Used by custom views if they don't supply layout params. Everything else
255 // added to an ActionBarContextView should have them already.
256 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
257 }
258
259 @Override
Adam Powell89e06452010-06-23 20:24:52 -0700260 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
261 final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
262 if (widthMode != MeasureSpec.EXACTLY) {
263 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
264 "with android:layout_width=\"match_parent\" (or fill_parent)");
265 }
266
267 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
Adam Powell85446e92010-10-22 17:43:56 -0700268 if (heightMode == MeasureSpec.UNSPECIFIED) {
Adam Powell89e06452010-06-23 20:24:52 -0700269 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
270 "with android:layout_height=\"wrap_content\"");
271 }
272
273 final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
Adam Powell89e06452010-06-23 20:24:52 -0700274
Adam Powelle2194442010-08-12 18:13:03 -0700275 int maxHeight = mContentHeight > 0 ?
276 mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
277
278 final int verticalPadding = getPaddingTop() + getPaddingBottom();
Adam Powell89e06452010-06-23 20:24:52 -0700279 int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
Adam Powelle2194442010-08-12 18:13:03 -0700280 final int height = maxHeight - verticalPadding;
Adam Powell89e06452010-06-23 20:24:52 -0700281 final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
282
Adam Powellf16888f2010-10-11 17:05:29 -0700283 if (mClose != null) {
284 availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0);
Adam Powell89e06452010-06-23 20:24:52 -0700285 }
286
Adam Powellb0ff6f92011-01-23 18:07:45 -0800287 if (mMenuView != null) {
288 availableWidth = measureChildView(mMenuView, availableWidth,
289 childSpecHeight, 0);
Adam Powell89e06452010-06-23 20:24:52 -0700290 }
291
Adam Powellb0ff6f92011-01-23 18:07:45 -0800292 if (mTitleLayout != null && mCustomView == null) {
293 availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
Adam Powell89e06452010-06-23 20:24:52 -0700294 }
295
296 if (mCustomView != null) {
Adam Powella7db0372010-06-30 17:08:47 -0700297 LayoutParams lp = mCustomView.getLayoutParams();
298 final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
299 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
300 final int customWidth = lp.width >= 0 ?
301 Math.min(lp.width, availableWidth) : availableWidth;
302 final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
303 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
304 final int customHeight = lp.height >= 0 ?
305 Math.min(lp.height, height) : height;
306 mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode),
307 MeasureSpec.makeMeasureSpec(customHeight, customHeightMode));
Adam Powell89e06452010-06-23 20:24:52 -0700308 }
309
Adam Powelle2194442010-08-12 18:13:03 -0700310 if (mContentHeight <= 0) {
311 int measuredHeight = 0;
312 final int count = getChildCount();
313 for (int i = 0; i < count; i++) {
314 View v = getChildAt(i);
315 int paddedViewHeight = v.getMeasuredHeight() + verticalPadding;
316 if (paddedViewHeight > measuredHeight) {
317 measuredHeight = paddedViewHeight;
318 }
319 }
320 setMeasuredDimension(contentWidth, measuredHeight);
321 } else {
322 setMeasuredDimension(contentWidth, maxHeight);
323 }
Adam Powell89e06452010-06-23 20:24:52 -0700324 }
325
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800326 private Animator makeInAnimation() {
327 mClose.setTranslationX(-mClose.getWidth());
328 ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", 0);
329 buttonAnimator.setDuration(200);
330 buttonAnimator.addListener(this);
331 buttonAnimator.setInterpolator(new DecelerateInterpolator());
332
333 AnimatorSet set = new AnimatorSet();
334 AnimatorSet.Builder b = set.play(buttonAnimator);
335
336 if (mMenuView != null) {
337 final int count = mMenuView.getChildCount();
338 if (count > 0) {
339 for (int i = count - 1, j = 0; i >= 0; i--, j++) {
340 View child = mMenuView.getChildAt(i);
341 child.setScaleY(0);
342 ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0, 1);
343 a.setDuration(100);
344 a.setStartDelay(j * 70);
345 b.with(a);
346 }
347 }
348 }
349
350 return set;
351 }
352
353 private Animator makeOutAnimation() {
354 ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
Adam Powell640a66e2011-04-29 10:18:53 -0700355 -mClose.getWidth());
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800356 buttonAnimator.setDuration(200);
357 buttonAnimator.addListener(this);
358 buttonAnimator.setInterpolator(new DecelerateInterpolator());
359
360 AnimatorSet set = new AnimatorSet();
361 AnimatorSet.Builder b = set.play(buttonAnimator);
362
363 if (mMenuView != null) {
364 final int count = mMenuView.getChildCount();
365 if (count > 0) {
366 for (int i = 0; i < 0; i++) {
367 View child = mMenuView.getChildAt(i);
368 child.setScaleY(0);
Adam Powell640a66e2011-04-29 10:18:53 -0700369 ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800370 a.setDuration(100);
371 a.setStartDelay(i * 70);
372 b.with(a);
373 }
374 }
375 }
376
377 return set;
378 }
379
Adam Powell89e06452010-06-23 20:24:52 -0700380 @Override
381 protected void onLayout(boolean changed, int l, int t, int r, int b) {
382 int x = getPaddingLeft();
383 final int y = getPaddingTop();
384 final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
Adam Powell89e06452010-06-23 20:24:52 -0700385
Adam Powellf16888f2010-10-11 17:05:29 -0700386 if (mClose != null && mClose.getVisibility() != GONE) {
387 x += positionChild(mClose, x, y, contentHeight);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800388
389 if (mAnimateInOnLayout) {
390 mAnimationMode = ANIMATE_IN;
391 mCurrentAnimation = makeInAnimation();
392 mCurrentAnimation.start();
393 mAnimateInOnLayout = false;
394 }
Adam Powell89e06452010-06-23 20:24:52 -0700395 }
Adam Powell640a66e2011-04-29 10:18:53 -0700396
Adam Powell0e94b512010-06-29 17:58:20 -0700397 if (mTitleLayout != null && mCustomView == null) {
Adam Powellbe4d68e2010-10-08 18:16:34 -0700398 x += positionChild(mTitleLayout, x, y, contentHeight);
Adam Powell89e06452010-06-23 20:24:52 -0700399 }
400
401 if (mCustomView != null) {
Adam Powellbe4d68e2010-10-08 18:16:34 -0700402 x += positionChild(mCustomView, x, y, contentHeight);
Adam Powell89e06452010-06-23 20:24:52 -0700403 }
404
405 x = r - l - getPaddingRight();
Adam Powell89e06452010-06-23 20:24:52 -0700406
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700407 if (mMenuView != null) {
Adam Powellbe4d68e2010-10-08 18:16:34 -0700408 x -= positionChildInverse(mMenuView, x, y, contentHeight);
Adam Powell89e06452010-06-23 20:24:52 -0700409 }
410 }
411
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800412 @Override
413 public void onAnimationStart(Animator animation) {
414 }
415
416 @Override
417 public void onAnimationEnd(Animator animation) {
Adam Powella1e63582011-01-18 16:51:22 -0800418 if (mAnimationMode == ANIMATE_OUT) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800419 killMode();
420 }
421 mAnimationMode = ANIMATE_IDLE;
422 }
423
424 @Override
425 public void onAnimationCancel(Animator animation) {
426 }
427
428 @Override
429 public void onAnimationRepeat(Animator animation) {
430 }
Patrick Dubroye0a799a2011-05-04 16:19:22 -0700431
432 @Override
433 public boolean shouldDelayChildPressedState() {
434 return false;
435 }
Adam Powell89e06452010-06-23 20:24:52 -0700436}