blob: 3e198119db8909d0f1e3e2082615d92750bc66d8 [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 */
16
17package com.android.internal.app;
18
Adam Powell2c9c9fe2010-07-16 10:17:57 -070019import com.android.internal.view.menu.MenuBuilder;
Adam Powell2c9c9fe2010-07-16 10:17:57 -070020import com.android.internal.view.menu.MenuPopupHelper;
21import com.android.internal.view.menu.SubMenuBuilder;
Adam Powell89e06452010-06-23 20:24:52 -070022import com.android.internal.widget.ActionBarContextView;
23import com.android.internal.widget.ActionBarView;
24
Adam Powelld8b3f2e2010-12-02 13:37:03 -080025import android.animation.Animator;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080026import android.animation.Animator.AnimatorListener;
27import android.animation.AnimatorSet;
Adam Powelle6ec7322010-12-07 15:29:26 -080028import android.animation.ObjectAnimator;
Adam Powell89e06452010-06-23 20:24:52 -070029import android.app.ActionBar;
Adam Powell661c9082010-07-02 10:09:44 -070030import android.app.Activity;
Adam Powelldec9dfd2010-08-09 15:27:54 -070031import android.app.Dialog;
Adam Powell661c9082010-07-02 10:09:44 -070032import android.app.Fragment;
33import android.app.FragmentTransaction;
Adam Powelldec9dfd2010-08-09 15:27:54 -070034import android.content.Context;
Adam Powell89e06452010-06-23 20:24:52 -070035import android.graphics.drawable.Drawable;
Adam Powell0e94b512010-06-29 17:58:20 -070036import android.os.Handler;
Adam Powell6e346362010-07-23 10:18:23 -070037import android.view.ActionMode;
Adam Powell32555f32010-11-17 13:49:22 -080038import android.view.LayoutInflater;
Adam Powell89e06452010-06-23 20:24:52 -070039import android.view.Menu;
Adam Powell9168f0b2010-08-02 15:46:24 -070040import android.view.MenuInflater;
Adam Powell89e06452010-06-23 20:24:52 -070041import android.view.MenuItem;
42import android.view.View;
Adam Powelle6ec7322010-12-07 15:29:26 -080043import android.view.Window;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080044import android.widget.FrameLayout;
Adam Powell89e06452010-06-23 20:24:52 -070045import android.widget.LinearLayout;
46import android.widget.SpinnerAdapter;
Adam Powell89e06452010-06-23 20:24:52 -070047
Adam Powell29ed7572010-07-14 16:24:56 -070048import java.lang.ref.WeakReference;
Adam Powell661c9082010-07-02 10:09:44 -070049import java.util.ArrayList;
50
Adam Powell89e06452010-06-23 20:24:52 -070051/**
52 * ActionBarImpl is the ActionBar implementation used
53 * by devices of all screen sizes. If it detects a compatible decor,
54 * it will split contextual modes across both the ActionBarView at
55 * the top of the screen and a horizontal LinearLayout at the bottom
56 * which is normally hidden.
57 */
58public class ActionBarImpl extends ActionBar {
59 private static final int NORMAL_VIEW = 0;
60 private static final int CONTEXT_VIEW = 1;
Adam Powell661c9082010-07-02 10:09:44 -070061
Adam Powelldec9dfd2010-08-09 15:27:54 -070062 private Context mContext;
Adam Powell661c9082010-07-02 10:09:44 -070063 private Activity mActivity;
Adam Powelldec9dfd2010-08-09 15:27:54 -070064 private Dialog mDialog;
Adam Powell661c9082010-07-02 10:09:44 -070065
Adam Powelld8b3f2e2010-12-02 13:37:03 -080066 private FrameLayout mContainerView;
Adam Powell89e06452010-06-23 20:24:52 -070067 private ActionBarView mActionView;
68 private ActionBarContextView mUpperContextView;
69 private LinearLayout mLowerContextView;
Adam Powelle6ec7322010-12-07 15:29:26 -080070 private View mContentView;
Adam Powell661c9082010-07-02 10:09:44 -070071
72 private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
73
Adam Powell661c9082010-07-02 10:09:44 -070074 private TabImpl mSelectedTab;
Adam Powell0c24a552010-11-03 16:44:11 -070075 private int mSavedTabPosition = INVALID_POSITION;
Adam Powell89e06452010-06-23 20:24:52 -070076
Adam Powell5d279772010-07-27 16:34:07 -070077 private ActionMode mActionMode;
Adam Powell89e06452010-06-23 20:24:52 -070078
Adam Powell8515ee82010-11-30 14:09:55 -080079 private boolean mLastMenuVisibility;
80 private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
81 new ArrayList<OnMenuVisibilityListener>();
82
Adam Powell89e06452010-06-23 20:24:52 -070083 private static final int CONTEXT_DISPLAY_NORMAL = 0;
84 private static final int CONTEXT_DISPLAY_SPLIT = 1;
85
Adam Powell0c24a552010-11-03 16:44:11 -070086 private static final int INVALID_POSITION = -1;
87
Adam Powell89e06452010-06-23 20:24:52 -070088 private int mContextDisplayMode;
Adam Powell0e94b512010-06-29 17:58:20 -070089
90 final Handler mHandler = new Handler();
Adam Powelld8b3f2e2010-12-02 13:37:03 -080091
Adam Powelle6ec7322010-12-07 15:29:26 -080092 private Animator mCurrentAnim;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080093
94 final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
95 new AnimatorListener() { // NORMAL_VIEW
96 @Override
97 public void onAnimationStart(Animator animation) {
98 }
99
100 @Override
101 public void onAnimationEnd(Animator animation) {
102 if (mLowerContextView != null) {
103 mLowerContextView.removeAllViews();
104 }
Adam Powelle6ec7322010-12-07 15:29:26 -0800105 mCurrentAnim = null;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800106 hideAllExcept(NORMAL_VIEW);
107 }
108
109 @Override
110 public void onAnimationCancel(Animator animation) {
111 }
112
113 @Override
114 public void onAnimationRepeat(Animator animation) {
115 }
116 },
117 new AnimatorListener() { // CONTEXT_VIEW
118 @Override
119 public void onAnimationStart(Animator animation) {
120 }
121
122 @Override
123 public void onAnimationEnd(Animator animation) {
Adam Powelle6ec7322010-12-07 15:29:26 -0800124 mCurrentAnim = null;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800125 hideAllExcept(CONTEXT_VIEW);
126 }
127
128 @Override
129 public void onAnimationCancel(Animator animation) {
130 }
131
132 @Override
133 public void onAnimationRepeat(Animator animation) {
134 }
Adam Powell0e94b512010-06-29 17:58:20 -0700135 }
Adam Powell0e94b512010-06-29 17:58:20 -0700136 };
137
Adam Powelle6ec7322010-12-07 15:29:26 -0800138 final AnimatorListener mHideListener = new AnimatorListener() {
139 @Override
140 public void onAnimationStart(Animator animation) {
141 }
142
143 @Override
144 public void onAnimationEnd(Animator animation) {
145 if (mContentView != null) {
146 mContentView.setTranslationY(0);
147 }
148 mContainerView.setVisibility(View.GONE);
149 mCurrentAnim = null;
150 }
151
152 @Override
153 public void onAnimationCancel(Animator animation) {
154 }
155
156 @Override
157 public void onAnimationRepeat(Animator animation) {
158 }
159 };
160
161 final AnimatorListener mShowListener = new AnimatorListener() {
162 @Override
163 public void onAnimationStart(Animator animation) {
164 }
165
166 @Override
167 public void onAnimationEnd(Animator animation) {
168 mCurrentAnim = null;
169 }
170
171 @Override
172 public void onAnimationCancel(Animator animation) {
173 }
174
175 @Override
176 public void onAnimationRepeat(Animator animation) {
177 }
178 };
179
Adam Powell661c9082010-07-02 10:09:44 -0700180 public ActionBarImpl(Activity activity) {
Adam Powell661c9082010-07-02 10:09:44 -0700181 mActivity = activity;
Adam Powelle6ec7322010-12-07 15:29:26 -0800182 Window window = activity.getWindow();
183 View decor = window.getDecorView();
184 init(decor);
185 if (!mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) {
186 mContentView = decor.findViewById(android.R.id.content);
187 }
Adam Powelldec9dfd2010-08-09 15:27:54 -0700188 }
189
190 public ActionBarImpl(Dialog dialog) {
191 mDialog = dialog;
192 init(dialog.getWindow().getDecorView());
193 }
194
195 private void init(View decor) {
196 mContext = decor.getContext();
Adam Powell89e06452010-06-23 20:24:52 -0700197 mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
198 mUpperContextView = (ActionBarContextView) decor.findViewById(
199 com.android.internal.R.id.action_context_bar);
200 mLowerContextView = (LinearLayout) decor.findViewById(
201 com.android.internal.R.id.lower_action_context_bar);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800202 mContainerView = (FrameLayout) decor.findViewById(
203 com.android.internal.R.id.action_bar_container);
Steve Block08f194b2010-08-24 18:20:48 +0100204
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800205 if (mActionView == null || mUpperContextView == null || mContainerView == null) {
Adam Powell89e06452010-06-23 20:24:52 -0700206 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
207 "with a compatible window decor layout");
208 }
Adam Powell0e94b512010-06-29 17:58:20 -0700209
Steve Block08f194b2010-08-24 18:20:48 +0100210 mActionView.setContextView(mUpperContextView);
Adam Powell89e06452010-06-23 20:24:52 -0700211 mContextDisplayMode = mLowerContextView == null ?
212 CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT;
213 }
214
Adam Powell8515ee82010-11-30 14:09:55 -0800215 public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
216 mMenuVisibilityListeners.add(listener);
217 }
218
219 public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
220 mMenuVisibilityListeners.remove(listener);
221 }
222
223 public void dispatchMenuVisibilityChanged(boolean isVisible) {
224 if (isVisible == mLastMenuVisibility) {
225 return;
226 }
227 mLastMenuVisibility = isVisible;
228
229 final int count = mMenuVisibilityListeners.size();
230 for (int i = 0; i < count; i++) {
231 mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
232 }
233 }
234
Adam Powella66c7b02010-07-28 15:28:25 -0700235 @Override
Adam Powella66c7b02010-07-28 15:28:25 -0700236 public void setTitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700237 setTitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700238 }
239
240 @Override
241 public void setSubtitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700242 setSubtitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700243 }
244
Adam Powell89e06452010-06-23 20:24:52 -0700245 public void setCustomNavigationMode(View view) {
Adam Powell661c9082010-07-02 10:09:44 -0700246 cleanupTabs();
Adam Powell9ab97872010-10-26 21:47:29 -0700247 setCustomView(view);
248 setDisplayOptions(DISPLAY_SHOW_CUSTOM, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE);
249 mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
Adam Powell89e06452010-06-23 20:24:52 -0700250 mActionView.setCallback(null);
251 }
Adam Powell0e94b512010-06-29 17:58:20 -0700252
Adam Powell8515ee82010-11-30 14:09:55 -0800253 public void setDropdownNavigationMode(SpinnerAdapter adapter, OnNavigationListener callback) {
Adam Powell17809772010-07-21 13:25:11 -0700254 setDropdownNavigationMode(adapter, callback, -1);
255 }
256
Adam Powell8515ee82010-11-30 14:09:55 -0800257 public void setDropdownNavigationMode(SpinnerAdapter adapter, OnNavigationListener callback,
Adam Powell17809772010-07-21 13:25:11 -0700258 int defaultSelectedPosition) {
Adam Powell661c9082010-07-02 10:09:44 -0700259 cleanupTabs();
Adam Powell9ab97872010-10-26 21:47:29 -0700260 setDisplayOptions(0, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE);
261 mActionView.setNavigationMode(NAVIGATION_MODE_LIST);
262 setListNavigationCallbacks(adapter, callback);
Adam Powell17809772010-07-21 13:25:11 -0700263 if (defaultSelectedPosition >= 0) {
264 mActionView.setDropdownSelectedPosition(defaultSelectedPosition);
265 }
Adam Powell89e06452010-06-23 20:24:52 -0700266 }
Adam Powell0e94b512010-06-29 17:58:20 -0700267
268 public void setStandardNavigationMode() {
Adam Powell661c9082010-07-02 10:09:44 -0700269 cleanupTabs();
Adam Powell9ab97872010-10-26 21:47:29 -0700270 setDisplayOptions(DISPLAY_SHOW_TITLE, DISPLAY_SHOW_TITLE | DISPLAY_SHOW_CUSTOM);
Adam Powell0e94b512010-06-29 17:58:20 -0700271 mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
272 mActionView.setCallback(null);
273 }
274
Adam Powell17809772010-07-21 13:25:11 -0700275 public void setSelectedNavigationItem(int position) {
276 switch (mActionView.getNavigationMode()) {
277 case NAVIGATION_MODE_TABS:
278 selectTab(mTabs.get(position));
279 break;
Adam Powell9ab97872010-10-26 21:47:29 -0700280 case NAVIGATION_MODE_LIST:
Adam Powell17809772010-07-21 13:25:11 -0700281 mActionView.setDropdownSelectedPosition(position);
282 break;
283 default:
284 throw new IllegalStateException(
Adam Powell9ab97872010-10-26 21:47:29 -0700285 "setSelectedNavigationIndex not valid for current navigation mode");
Adam Powell17809772010-07-21 13:25:11 -0700286 }
287 }
288
289 public int getSelectedNavigationItem() {
Adam Powell9ab97872010-10-26 21:47:29 -0700290 return getSelectedNavigationIndex();
291 }
292
293 public void removeAllTabs() {
294 cleanupTabs();
Adam Powell17809772010-07-21 13:25:11 -0700295 }
296
Adam Powell661c9082010-07-02 10:09:44 -0700297 private void cleanupTabs() {
298 if (mSelectedTab != null) {
299 selectTab(null);
300 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700301 mTabs.clear();
Adam Powell0c24a552010-11-03 16:44:11 -0700302 mActionView.removeAllTabs();
303 mSavedTabPosition = INVALID_POSITION;
Adam Powell661c9082010-07-02 10:09:44 -0700304 }
305
Adam Powell0e94b512010-06-29 17:58:20 -0700306 public void setTitle(CharSequence title) {
307 mActionView.setTitle(title);
308 }
309
310 public void setSubtitle(CharSequence subtitle) {
311 mActionView.setSubtitle(subtitle);
312 }
313
Adam Powell89e06452010-06-23 20:24:52 -0700314 public void setDisplayOptions(int options) {
315 mActionView.setDisplayOptions(options);
316 }
Adam Powell0e94b512010-06-29 17:58:20 -0700317
Adam Powell89e06452010-06-23 20:24:52 -0700318 public void setDisplayOptions(int options, int mask) {
319 final int current = mActionView.getDisplayOptions();
320 mActionView.setDisplayOptions((options & mask) | (current & ~mask));
321 }
322
323 public void setBackgroundDrawable(Drawable d) {
324 mActionView.setBackgroundDrawable(d);
325 }
326
327 public View getCustomNavigationView() {
Adam Powellef704442010-11-16 14:48:22 -0800328 return getCustomView();
329 }
330
331 public View getCustomView() {
Adam Powell89e06452010-06-23 20:24:52 -0700332 return mActionView.getCustomNavigationView();
333 }
334
335 public CharSequence getTitle() {
336 return mActionView.getTitle();
337 }
338
339 public CharSequence getSubtitle() {
340 return mActionView.getSubtitle();
341 }
342
343 public int getNavigationMode() {
344 return mActionView.getNavigationMode();
345 }
346
347 public int getDisplayOptions() {
348 return mActionView.getDisplayOptions();
349 }
350
Adam Powell5d279772010-07-27 16:34:07 -0700351 public ActionMode startActionMode(ActionMode.Callback callback) {
352 if (mActionMode != null) {
353 mActionMode.finish();
Adam Powell6e346362010-07-23 10:18:23 -0700354 }
Adam Powell3461b322010-07-14 11:34:43 -0700355
Adam Powell5d279772010-07-27 16:34:07 -0700356 ActionMode mode = new ActionModeImpl(callback);
Adam Powell6e346362010-07-23 10:18:23 -0700357 if (callback.onCreateActionMode(mode, mode.getMenu())) {
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700358 mode.invalidate();
359 mUpperContextView.initForMode(mode);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800360 animateTo(CONTEXT_VIEW);
Adam Powell89e06452010-06-23 20:24:52 -0700361 if (mLowerContextView != null) {
362 // TODO animate this
363 mLowerContextView.setVisibility(View.VISIBLE);
364 }
Adam Powell5d279772010-07-27 16:34:07 -0700365 mActionMode = mode;
Adam Powellac695c62010-07-20 18:19:27 -0700366 return mode;
Adam Powell89e06452010-06-23 20:24:52 -0700367 }
Adam Powellac695c62010-07-20 18:19:27 -0700368 return null;
Adam Powell89e06452010-06-23 20:24:52 -0700369 }
370
Adam Powell661c9082010-07-02 10:09:44 -0700371 private void configureTab(Tab tab, int position) {
372 final TabImpl tabi = (TabImpl) tab;
Adam Powell2b6230e2010-09-07 17:55:25 -0700373 final ActionBar.TabListener callback = tabi.getCallback();
374
375 if (callback == null) {
376 throw new IllegalStateException("Action Bar Tab must have a Callback");
377 }
Adam Powell661c9082010-07-02 10:09:44 -0700378
379 tabi.setPosition(position);
380 mTabs.add(position, tabi);
381
Adam Powell81b89442010-11-02 17:58:56 -0700382 final int count = mTabs.size();
383 for (int i = position + 1; i < count; i++) {
384 mTabs.get(i).setPosition(i);
Adam Powell661c9082010-07-02 10:09:44 -0700385 }
Adam Powell661c9082010-07-02 10:09:44 -0700386 }
387
388 @Override
389 public void addTab(Tab tab) {
Adam Powell81b89442010-11-02 17:58:56 -0700390 addTab(tab, mTabs.isEmpty());
Adam Powell661c9082010-07-02 10:09:44 -0700391 }
392
393 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700394 public void addTab(Tab tab, int position) {
Adam Powell81b89442010-11-02 17:58:56 -0700395 addTab(tab, position, mTabs.isEmpty());
396 }
397
398 @Override
399 public void addTab(Tab tab, boolean setSelected) {
400 mActionView.addTab(tab, setSelected);
401 configureTab(tab, mTabs.size());
402 if (setSelected) {
403 selectTab(tab);
404 }
405 }
406
407 @Override
408 public void addTab(Tab tab, int position, boolean setSelected) {
409 mActionView.addTab(tab, position, setSelected);
Adam Powell661c9082010-07-02 10:09:44 -0700410 configureTab(tab, position);
Adam Powell81b89442010-11-02 17:58:56 -0700411 if (setSelected) {
412 selectTab(tab);
413 }
Adam Powell661c9082010-07-02 10:09:44 -0700414 }
415
416 @Override
417 public Tab newTab() {
418 return new TabImpl();
419 }
420
421 @Override
422 public void removeTab(Tab tab) {
423 removeTabAt(tab.getPosition());
424 }
425
426 @Override
427 public void removeTabAt(int position) {
Adam Powell0c24a552010-11-03 16:44:11 -0700428 int selectedTabPosition = mSelectedTab != null
429 ? mSelectedTab.getPosition() : mSavedTabPosition;
Adam Powell661c9082010-07-02 10:09:44 -0700430 mActionView.removeTabAt(position);
431 mTabs.remove(position);
432
433 final int newTabCount = mTabs.size();
434 for (int i = position; i < newTabCount; i++) {
435 mTabs.get(i).setPosition(i);
436 }
437
Adam Powell0c24a552010-11-03 16:44:11 -0700438 if (selectedTabPosition == position) {
439 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
440 }
Adam Powell661c9082010-07-02 10:09:44 -0700441 }
442
443 @Override
444 public void setTabNavigationMode() {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700445 if (mActivity == null) {
446 throw new IllegalStateException(
447 "Tab navigation mode cannot be used outside of an Activity");
448 }
Adam Powell9ab97872010-10-26 21:47:29 -0700449 setDisplayOptions(0, DISPLAY_SHOW_TITLE | DISPLAY_SHOW_CUSTOM);
Adam Powell661c9082010-07-02 10:09:44 -0700450 mActionView.setNavigationMode(NAVIGATION_MODE_TABS);
451 }
452
453 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700454 public void selectTab(Tab tab) {
Adam Powell0c24a552010-11-03 16:44:11 -0700455 if (getNavigationMode() != NAVIGATION_MODE_TABS) {
456 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
457 return;
458 }
459
460 final FragmentTransaction trans = mActivity.getFragmentManager().openTransaction()
461 .disallowAddToBackStack();
Adam Powell7f9b9052010-10-19 16:56:07 -0700462
463 if (mSelectedTab == tab) {
464 if (mSelectedTab != null) {
465 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
466 }
467 } else {
468 mActionView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
469 if (mSelectedTab != null) {
470 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
471 }
472 mSelectedTab = (TabImpl) tab;
473 if (mSelectedTab != null) {
474 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
475 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700476 }
477
478 if (!trans.isEmpty()) {
479 trans.commit();
480 }
481 }
482
483 @Override
484 public Tab getSelectedTab() {
485 return mSelectedTab;
Adam Powell661c9082010-07-02 10:09:44 -0700486 }
487
Adam Powell6b336f82010-08-10 20:13:01 -0700488 @Override
489 public int getHeight() {
490 return mActionView.getHeight();
491 }
492
493 @Override
494 public void show() {
Adam Powelle6ec7322010-12-07 15:29:26 -0800495 if (mCurrentAnim != null) {
496 mCurrentAnim.end();
497 }
498 if (mContainerView.getVisibility() == View.VISIBLE) {
499 return;
500 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800501 mContainerView.setVisibility(View.VISIBLE);
Adam Powelle6ec7322010-12-07 15:29:26 -0800502 mContainerView.setAlpha(0);
503 mContainerView.setTranslationY(-mContainerView.getHeight());
504 AnimatorSet anim = new AnimatorSet();
505 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "translationY", 0))
506 .with(ObjectAnimator.ofFloat(mContainerView, "alpha", 1));
507 if (mContentView != null) {
508 b.with(ObjectAnimator.ofFloat(mContentView, "translationY", -mContainerView.getHeight(), 0));
509 }
510 anim.addListener(mShowListener);
511 mCurrentAnim = anim;
512 anim.start();
Adam Powell6b336f82010-08-10 20:13:01 -0700513 }
514
515 @Override
516 public void hide() {
Adam Powelle6ec7322010-12-07 15:29:26 -0800517 if (mCurrentAnim != null) {
518 mCurrentAnim.end();
519 }
520 if (mContainerView.getVisibility() == View.GONE) {
521 return;
522 }
523 mContainerView.setAlpha(1);
524 AnimatorSet anim = new AnimatorSet();
525 AnimatorSet.Builder b = anim.play(
526 ObjectAnimator.ofFloat(mContainerView, "translationY", -mContainerView.getHeight()))
527 .with(ObjectAnimator.ofFloat(mContainerView, "alpha", 0));
528 if (mContentView != null) {
529 b.with(ObjectAnimator.ofFloat(mContentView, "translationY", 0, -mContainerView.getHeight()));
530 }
531 anim.addListener(mHideListener);
532 mCurrentAnim = anim;
533 anim.start();
Adam Powell6b336f82010-08-10 20:13:01 -0700534 }
535
536 public boolean isShowing() {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800537 return mContainerView.getVisibility() == View.VISIBLE;
538 }
539
540 private long animateTo(int viewIndex) {
Adam Powelle6ec7322010-12-07 15:29:26 -0800541 show();
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800542
543 AnimatorSet set = new AnimatorSet();
544
545 final View targetChild = mContainerView.getChildAt(viewIndex);
546 targetChild.setVisibility(View.VISIBLE);
547 AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
548 if (viewIndex == NORMAL_VIEW) {
549 targetChild.setScaleY(0);
550 b.with(ObjectAnimator.ofFloat(targetChild, "scaleY", 1));
551 }
552
553 final int count = mContainerView.getChildCount();
554 for (int i = 0; i < count; i++) {
555 final View child = mContainerView.getChildAt(i);
556 if (i == viewIndex) {
557 continue;
558 }
559
560 if (child.getVisibility() != View.GONE) {
561 ObjectAnimator a = ObjectAnimator.ofFloat(child, "alpha", 0);
562 b.with(a);
563 if (viewIndex == CONTEXT_VIEW) {
564 b.with(ObjectAnimator.ofFloat(child, "scaleY", 0));
565 }
566 }
567 }
568
569 set.addListener(mAfterAnimation[viewIndex]);
570
Adam Powelle6ec7322010-12-07 15:29:26 -0800571 mCurrentAnim = set;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800572 set.start();
573 return set.getDuration();
574 }
575
576 private void hideAllExcept(int viewIndex) {
577 final int count = mContainerView.getChildCount();
578 for (int i = 0; i < count; i++) {
579 mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE);
580 }
Adam Powell6b336f82010-08-10 20:13:01 -0700581 }
582
Adam Powell89e06452010-06-23 20:24:52 -0700583 /**
584 * @hide
585 */
Adam Powell5d279772010-07-27 16:34:07 -0700586 public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
Adam Powell6e346362010-07-23 10:18:23 -0700587 private ActionMode.Callback mCallback;
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700588 private MenuBuilder mMenu;
Adam Powell29ed7572010-07-14 16:24:56 -0700589 private WeakReference<View> mCustomView;
Adam Powell89e06452010-06-23 20:24:52 -0700590
Adam Powell5d279772010-07-27 16:34:07 -0700591 public ActionModeImpl(ActionMode.Callback callback) {
Adam Powell89e06452010-06-23 20:24:52 -0700592 mCallback = callback;
Adam Powell4d9861e2010-08-17 11:14:40 -0700593 mMenu = new MenuBuilder(mActionView.getContext())
594 .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700595 mMenu.setCallback(this);
Adam Powell89e06452010-06-23 20:24:52 -0700596 }
Adam Powell9168f0b2010-08-02 15:46:24 -0700597
598 @Override
599 public MenuInflater getMenuInflater() {
Adam Powell4d9861e2010-08-17 11:14:40 -0700600 return new MenuInflater(mContext);
Adam Powell9168f0b2010-08-02 15:46:24 -0700601 }
602
Adam Powell89e06452010-06-23 20:24:52 -0700603 @Override
604 public Menu getMenu() {
605 return mMenu;
606 }
607
608 @Override
609 public void finish() {
Adam Powell5d279772010-07-27 16:34:07 -0700610 if (mActionMode != this) {
611 // Not the active action mode - no-op
Adam Powell93b6bc32010-07-22 11:36:35 -0700612 return;
613 }
614
Adam Powell6e346362010-07-23 10:18:23 -0700615 mCallback.onDestroyActionMode(this);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800616 mCallback = null;
617 animateTo(NORMAL_VIEW);
Adam Powell0e94b512010-06-29 17:58:20 -0700618
619 // Clear out the context mode views after the animation finishes
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800620 mUpperContextView.closeMode();
Adam Powell89e06452010-06-23 20:24:52 -0700621 if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) {
622 // TODO Animate this
623 mLowerContextView.setVisibility(View.GONE);
624 }
Adam Powell5d279772010-07-27 16:34:07 -0700625 mActionMode = null;
Adam Powell89e06452010-06-23 20:24:52 -0700626 }
627
628 @Override
629 public void invalidate() {
Adam Powell6e346362010-07-23 10:18:23 -0700630 if (mCallback.onPrepareActionMode(this, mMenu)) {
Adam Powell89e06452010-06-23 20:24:52 -0700631 // Refresh content in both context views
632 }
633 }
634
635 @Override
636 public void setCustomView(View view) {
637 mUpperContextView.setCustomView(view);
Adam Powell29ed7572010-07-14 16:24:56 -0700638 mCustomView = new WeakReference<View>(view);
Adam Powell89e06452010-06-23 20:24:52 -0700639 }
640
641 @Override
642 public void setSubtitle(CharSequence subtitle) {
643 mUpperContextView.setSubtitle(subtitle);
644 }
645
646 @Override
647 public void setTitle(CharSequence title) {
648 mUpperContextView.setTitle(title);
649 }
Adam Powell29ed7572010-07-14 16:24:56 -0700650
651 @Override
Adam Powellc9ae2a22010-07-28 14:44:21 -0700652 public void setTitle(int resId) {
653 setTitle(mActivity.getString(resId));
654 }
655
656 @Override
657 public void setSubtitle(int resId) {
658 setSubtitle(mActivity.getString(resId));
659 }
660
661 @Override
Adam Powell29ed7572010-07-14 16:24:56 -0700662 public CharSequence getTitle() {
663 return mUpperContextView.getTitle();
664 }
665
666 @Override
667 public CharSequence getSubtitle() {
668 return mUpperContextView.getSubtitle();
669 }
Adam Powell89e06452010-06-23 20:24:52 -0700670
Adam Powell29ed7572010-07-14 16:24:56 -0700671 @Override
672 public View getCustomView() {
673 return mCustomView != null ? mCustomView.get() : null;
674 }
675
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700676 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800677 if (mCallback != null) {
678 return mCallback.onActionItemClicked(this, item);
679 } else {
680 return false;
681 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700682 }
683
684 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
685 }
686
687 public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800688 if (mCallback == null) {
689 return false;
690 }
691
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700692 if (!subMenu.hasVisibleItems()) {
693 return true;
Adam Powell89e06452010-06-23 20:24:52 -0700694 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700695
Adam Powelldec9dfd2010-08-09 15:27:54 -0700696 new MenuPopupHelper(mContext, subMenu).show();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700697 return true;
698 }
699
700 public void onCloseSubMenu(SubMenuBuilder menu) {
701 }
702
703 public void onMenuModeChange(MenuBuilder menu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800704 if (mCallback == null) {
705 return;
706 }
Adam Powellf6148c52010-08-11 21:10:16 -0700707 invalidate();
Adam Powell8515ee82010-11-30 14:09:55 -0800708 mUpperContextView.openOverflowMenu();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700709 }
Adam Powell661c9082010-07-02 10:09:44 -0700710 }
711
712 /**
713 * @hide
714 */
715 public class TabImpl extends ActionBar.Tab {
Adam Powell2b6230e2010-09-07 17:55:25 -0700716 private ActionBar.TabListener mCallback;
717 private Object mTag;
Adam Powell661c9082010-07-02 10:09:44 -0700718 private Drawable mIcon;
719 private CharSequence mText;
720 private int mPosition;
Adam Powell2b6230e2010-09-07 17:55:25 -0700721 private View mCustomView;
Adam Powell661c9082010-07-02 10:09:44 -0700722
723 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700724 public Object getTag() {
725 return mTag;
726 }
727
728 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700729 public Tab setTag(Object tag) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700730 mTag = tag;
Adam Powell9ab97872010-10-26 21:47:29 -0700731 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700732 }
733
734 public ActionBar.TabListener getCallback() {
735 return mCallback;
736 }
737
738 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700739 public Tab setTabListener(ActionBar.TabListener callback) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700740 mCallback = callback;
Adam Powell9ab97872010-10-26 21:47:29 -0700741 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700742 }
743
744 @Override
745 public View getCustomView() {
746 return mCustomView;
747 }
748
749 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700750 public Tab setCustomView(View view) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700751 mCustomView = view;
Adam Powell9ab97872010-10-26 21:47:29 -0700752 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700753 }
754
755 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800756 public Tab setCustomView(int layoutResId) {
757 return setCustomView(LayoutInflater.from(mContext).inflate(layoutResId, null));
758 }
759
760 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700761 public Drawable getIcon() {
762 return mIcon;
763 }
764
765 @Override
766 public int getPosition() {
767 return mPosition;
768 }
769
770 public void setPosition(int position) {
771 mPosition = position;
772 }
773
774 @Override
775 public CharSequence getText() {
776 return mText;
777 }
778
779 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700780 public Tab setIcon(Drawable icon) {
Adam Powell661c9082010-07-02 10:09:44 -0700781 mIcon = icon;
Adam Powell9ab97872010-10-26 21:47:29 -0700782 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700783 }
784
785 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800786 public Tab setIcon(int resId) {
787 return setIcon(mContext.getResources().getDrawable(resId));
788 }
789
790 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700791 public Tab setText(CharSequence text) {
Adam Powell661c9082010-07-02 10:09:44 -0700792 mText = text;
Adam Powell9ab97872010-10-26 21:47:29 -0700793 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700794 }
795
796 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800797 public Tab setText(int resId) {
798 return setText(mContext.getResources().getText(resId));
799 }
800
801 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700802 public void select() {
803 selectTab(this);
Adam Powell89e06452010-06-23 20:24:52 -0700804 }
805 }
Adam Powell9ab97872010-10-26 21:47:29 -0700806
807 @Override
808 public void setCustomView(View view) {
809 mActionView.setCustomNavigationView(view);
810 }
811
812 @Override
813 public void setCustomView(View view, LayoutParams layoutParams) {
814 view.setLayoutParams(layoutParams);
815 mActionView.setCustomNavigationView(view);
816 }
817
818 @Override
Adam Powell8515ee82010-11-30 14:09:55 -0800819 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
Adam Powell9ab97872010-10-26 21:47:29 -0700820 mActionView.setDropdownAdapter(adapter);
821 mActionView.setCallback(callback);
822 }
823
824 @Override
825 public int getSelectedNavigationIndex() {
826 switch (mActionView.getNavigationMode()) {
827 case NAVIGATION_MODE_TABS:
Adam Powell04587962010-11-11 22:15:07 -0800828 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
Adam Powell9ab97872010-10-26 21:47:29 -0700829 case NAVIGATION_MODE_LIST:
830 return mActionView.getDropdownSelectedPosition();
831 default:
832 return -1;
833 }
834 }
835
836 @Override
837 public int getNavigationItemCount() {
838 switch (mActionView.getNavigationMode()) {
839 case NAVIGATION_MODE_TABS:
840 return mTabs.size();
841 case NAVIGATION_MODE_LIST:
842 SpinnerAdapter adapter = mActionView.getDropdownAdapter();
843 return adapter != null ? adapter.getCount() : 0;
844 default:
845 return 0;
846 }
847 }
848
849 @Override
Adam Powell0c24a552010-11-03 16:44:11 -0700850 public int getTabCount() {
851 return mTabs.size();
852 }
853
854 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700855 public void setNavigationMode(int mode) {
Adam Powell0c24a552010-11-03 16:44:11 -0700856 final int oldMode = mActionView.getNavigationMode();
857 switch (oldMode) {
858 case NAVIGATION_MODE_TABS:
859 mSavedTabPosition = getSelectedNavigationIndex();
860 selectTab(null);
861 break;
862 }
Adam Powell9ab97872010-10-26 21:47:29 -0700863 mActionView.setNavigationMode(mode);
Adam Powell0c24a552010-11-03 16:44:11 -0700864 switch (mode) {
865 case NAVIGATION_MODE_TABS:
866 if (mSavedTabPosition != INVALID_POSITION) {
867 setSelectedNavigationItem(mSavedTabPosition);
868 mSavedTabPosition = INVALID_POSITION;
869 }
870 break;
871 }
Adam Powell9ab97872010-10-26 21:47:29 -0700872 }
873
874 @Override
875 public Tab getTabAt(int index) {
876 return mTabs.get(index);
877 }
Adam Powell0c24a552010-11-03 16:44:11 -0700878
879 /**
880 * This fragment is added when we're keeping a back stack in a tab switch
881 * transaction. We use it to change the selected tab in the action bar view
882 * when we back out.
883 */
884 private class SwitchSelectedTabViewFragment extends Fragment {
885 private int mSelectedTabIndex;
886
887 public SwitchSelectedTabViewFragment(int oldSelectedTab) {
888 mSelectedTabIndex = oldSelectedTab;
889 }
890
891 @Override
892 public void onDetach() {
893 if (mSelectedTabIndex >= 0 && mSelectedTabIndex < getTabCount()) {
894 mActionView.setTabSelected(mSelectedTabIndex);
895 }
896 }
897 }
Adam Powell89e06452010-06-23 20:24:52 -0700898}