blob: ce7ab84af02a0a020b57d4990b66dc34147701ba [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;
26import android.animation.ObjectAnimator;
27import android.animation.Animator.AnimatorListener;
28import android.animation.AnimatorSet;
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 Powelld8b3f2e2010-12-02 13:37:03 -080043import android.widget.FrameLayout;
Adam Powell89e06452010-06-23 20:24:52 -070044import android.widget.LinearLayout;
45import android.widget.SpinnerAdapter;
46import android.widget.ViewAnimator;
47
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 Powell661c9082010-07-02 10:09:44 -070070
71 private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
72
Adam Powell661c9082010-07-02 10:09:44 -070073 private TabImpl mSelectedTab;
Adam Powell0c24a552010-11-03 16:44:11 -070074 private int mSavedTabPosition = INVALID_POSITION;
Adam Powell89e06452010-06-23 20:24:52 -070075
Adam Powell5d279772010-07-27 16:34:07 -070076 private ActionMode mActionMode;
Adam Powell89e06452010-06-23 20:24:52 -070077
Adam Powell8515ee82010-11-30 14:09:55 -080078 private boolean mLastMenuVisibility;
79 private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
80 new ArrayList<OnMenuVisibilityListener>();
81
Adam Powell89e06452010-06-23 20:24:52 -070082 private static final int CONTEXT_DISPLAY_NORMAL = 0;
83 private static final int CONTEXT_DISPLAY_SPLIT = 1;
84
Adam Powell0c24a552010-11-03 16:44:11 -070085 private static final int INVALID_POSITION = -1;
86
Adam Powell89e06452010-06-23 20:24:52 -070087 private int mContextDisplayMode;
Adam Powell0e94b512010-06-29 17:58:20 -070088
89 final Handler mHandler = new Handler();
Adam Powelld8b3f2e2010-12-02 13:37:03 -080090
91 private Animator mCurrentAnimation;
92
93 final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
94 new AnimatorListener() { // NORMAL_VIEW
95 @Override
96 public void onAnimationStart(Animator animation) {
97 }
98
99 @Override
100 public void onAnimationEnd(Animator animation) {
101 if (mLowerContextView != null) {
102 mLowerContextView.removeAllViews();
103 }
104 mCurrentAnimation = null;
105 hideAllExcept(NORMAL_VIEW);
106 }
107
108 @Override
109 public void onAnimationCancel(Animator animation) {
110 }
111
112 @Override
113 public void onAnimationRepeat(Animator animation) {
114 }
115 },
116 new AnimatorListener() { // CONTEXT_VIEW
117 @Override
118 public void onAnimationStart(Animator animation) {
119 }
120
121 @Override
122 public void onAnimationEnd(Animator animation) {
123 mCurrentAnimation = null;
124 hideAllExcept(CONTEXT_VIEW);
125 }
126
127 @Override
128 public void onAnimationCancel(Animator animation) {
129 }
130
131 @Override
132 public void onAnimationRepeat(Animator animation) {
133 }
Adam Powell0e94b512010-06-29 17:58:20 -0700134 }
Adam Powell0e94b512010-06-29 17:58:20 -0700135 };
136
Adam Powell661c9082010-07-02 10:09:44 -0700137 public ActionBarImpl(Activity activity) {
Adam Powell661c9082010-07-02 10:09:44 -0700138 mActivity = activity;
Adam Powelldec9dfd2010-08-09 15:27:54 -0700139 init(activity.getWindow().getDecorView());
140 }
141
142 public ActionBarImpl(Dialog dialog) {
143 mDialog = dialog;
144 init(dialog.getWindow().getDecorView());
145 }
146
147 private void init(View decor) {
148 mContext = decor.getContext();
Adam Powell89e06452010-06-23 20:24:52 -0700149 mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
150 mUpperContextView = (ActionBarContextView) decor.findViewById(
151 com.android.internal.R.id.action_context_bar);
152 mLowerContextView = (LinearLayout) decor.findViewById(
153 com.android.internal.R.id.lower_action_context_bar);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800154 mContainerView = (FrameLayout) decor.findViewById(
155 com.android.internal.R.id.action_bar_container);
Steve Block08f194b2010-08-24 18:20:48 +0100156
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800157 if (mActionView == null || mUpperContextView == null || mContainerView == null) {
Adam Powell89e06452010-06-23 20:24:52 -0700158 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
159 "with a compatible window decor layout");
160 }
Adam Powell0e94b512010-06-29 17:58:20 -0700161
Steve Block08f194b2010-08-24 18:20:48 +0100162 mActionView.setContextView(mUpperContextView);
Adam Powell89e06452010-06-23 20:24:52 -0700163 mContextDisplayMode = mLowerContextView == null ?
164 CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT;
165 }
166
Adam Powell8515ee82010-11-30 14:09:55 -0800167 public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
168 mMenuVisibilityListeners.add(listener);
169 }
170
171 public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
172 mMenuVisibilityListeners.remove(listener);
173 }
174
175 public void dispatchMenuVisibilityChanged(boolean isVisible) {
176 if (isVisible == mLastMenuVisibility) {
177 return;
178 }
179 mLastMenuVisibility = isVisible;
180
181 final int count = mMenuVisibilityListeners.size();
182 for (int i = 0; i < count; i++) {
183 mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
184 }
185 }
186
Adam Powella66c7b02010-07-28 15:28:25 -0700187 @Override
Adam Powella66c7b02010-07-28 15:28:25 -0700188 public void setTitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700189 setTitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700190 }
191
192 @Override
193 public void setSubtitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700194 setSubtitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700195 }
196
Adam Powell89e06452010-06-23 20:24:52 -0700197 public void setCustomNavigationMode(View view) {
Adam Powell661c9082010-07-02 10:09:44 -0700198 cleanupTabs();
Adam Powell9ab97872010-10-26 21:47:29 -0700199 setCustomView(view);
200 setDisplayOptions(DISPLAY_SHOW_CUSTOM, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE);
201 mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
Adam Powell89e06452010-06-23 20:24:52 -0700202 mActionView.setCallback(null);
203 }
Adam Powell0e94b512010-06-29 17:58:20 -0700204
Adam Powell8515ee82010-11-30 14:09:55 -0800205 public void setDropdownNavigationMode(SpinnerAdapter adapter, OnNavigationListener callback) {
Adam Powell17809772010-07-21 13:25:11 -0700206 setDropdownNavigationMode(adapter, callback, -1);
207 }
208
Adam Powell8515ee82010-11-30 14:09:55 -0800209 public void setDropdownNavigationMode(SpinnerAdapter adapter, OnNavigationListener callback,
Adam Powell17809772010-07-21 13:25:11 -0700210 int defaultSelectedPosition) {
Adam Powell661c9082010-07-02 10:09:44 -0700211 cleanupTabs();
Adam Powell9ab97872010-10-26 21:47:29 -0700212 setDisplayOptions(0, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE);
213 mActionView.setNavigationMode(NAVIGATION_MODE_LIST);
214 setListNavigationCallbacks(adapter, callback);
Adam Powell17809772010-07-21 13:25:11 -0700215 if (defaultSelectedPosition >= 0) {
216 mActionView.setDropdownSelectedPosition(defaultSelectedPosition);
217 }
Adam Powell89e06452010-06-23 20:24:52 -0700218 }
Adam Powell0e94b512010-06-29 17:58:20 -0700219
220 public void setStandardNavigationMode() {
Adam Powell661c9082010-07-02 10:09:44 -0700221 cleanupTabs();
Adam Powell9ab97872010-10-26 21:47:29 -0700222 setDisplayOptions(DISPLAY_SHOW_TITLE, DISPLAY_SHOW_TITLE | DISPLAY_SHOW_CUSTOM);
Adam Powell0e94b512010-06-29 17:58:20 -0700223 mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
224 mActionView.setCallback(null);
225 }
226
Adam Powell17809772010-07-21 13:25:11 -0700227 public void setSelectedNavigationItem(int position) {
228 switch (mActionView.getNavigationMode()) {
229 case NAVIGATION_MODE_TABS:
230 selectTab(mTabs.get(position));
231 break;
Adam Powell9ab97872010-10-26 21:47:29 -0700232 case NAVIGATION_MODE_LIST:
Adam Powell17809772010-07-21 13:25:11 -0700233 mActionView.setDropdownSelectedPosition(position);
234 break;
235 default:
236 throw new IllegalStateException(
Adam Powell9ab97872010-10-26 21:47:29 -0700237 "setSelectedNavigationIndex not valid for current navigation mode");
Adam Powell17809772010-07-21 13:25:11 -0700238 }
239 }
240
241 public int getSelectedNavigationItem() {
Adam Powell9ab97872010-10-26 21:47:29 -0700242 return getSelectedNavigationIndex();
243 }
244
245 public void removeAllTabs() {
246 cleanupTabs();
Adam Powell17809772010-07-21 13:25:11 -0700247 }
248
Adam Powell661c9082010-07-02 10:09:44 -0700249 private void cleanupTabs() {
250 if (mSelectedTab != null) {
251 selectTab(null);
252 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700253 mTabs.clear();
Adam Powell0c24a552010-11-03 16:44:11 -0700254 mActionView.removeAllTabs();
255 mSavedTabPosition = INVALID_POSITION;
Adam Powell661c9082010-07-02 10:09:44 -0700256 }
257
Adam Powell0e94b512010-06-29 17:58:20 -0700258 public void setTitle(CharSequence title) {
259 mActionView.setTitle(title);
260 }
261
262 public void setSubtitle(CharSequence subtitle) {
263 mActionView.setSubtitle(subtitle);
264 }
265
Adam Powell89e06452010-06-23 20:24:52 -0700266 public void setDisplayOptions(int options) {
267 mActionView.setDisplayOptions(options);
268 }
Adam Powell0e94b512010-06-29 17:58:20 -0700269
Adam Powell89e06452010-06-23 20:24:52 -0700270 public void setDisplayOptions(int options, int mask) {
271 final int current = mActionView.getDisplayOptions();
272 mActionView.setDisplayOptions((options & mask) | (current & ~mask));
273 }
274
275 public void setBackgroundDrawable(Drawable d) {
276 mActionView.setBackgroundDrawable(d);
277 }
278
279 public View getCustomNavigationView() {
Adam Powellef704442010-11-16 14:48:22 -0800280 return getCustomView();
281 }
282
283 public View getCustomView() {
Adam Powell89e06452010-06-23 20:24:52 -0700284 return mActionView.getCustomNavigationView();
285 }
286
287 public CharSequence getTitle() {
288 return mActionView.getTitle();
289 }
290
291 public CharSequence getSubtitle() {
292 return mActionView.getSubtitle();
293 }
294
295 public int getNavigationMode() {
296 return mActionView.getNavigationMode();
297 }
298
299 public int getDisplayOptions() {
300 return mActionView.getDisplayOptions();
301 }
302
Adam Powell5d279772010-07-27 16:34:07 -0700303 public ActionMode startActionMode(ActionMode.Callback callback) {
304 if (mActionMode != null) {
305 mActionMode.finish();
Adam Powell6e346362010-07-23 10:18:23 -0700306 }
Adam Powell3461b322010-07-14 11:34:43 -0700307
Adam Powell5d279772010-07-27 16:34:07 -0700308 ActionMode mode = new ActionModeImpl(callback);
Adam Powell6e346362010-07-23 10:18:23 -0700309 if (callback.onCreateActionMode(mode, mode.getMenu())) {
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700310 mode.invalidate();
311 mUpperContextView.initForMode(mode);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800312 animateTo(CONTEXT_VIEW);
Adam Powell89e06452010-06-23 20:24:52 -0700313 if (mLowerContextView != null) {
314 // TODO animate this
315 mLowerContextView.setVisibility(View.VISIBLE);
316 }
Adam Powell5d279772010-07-27 16:34:07 -0700317 mActionMode = mode;
Adam Powellac695c62010-07-20 18:19:27 -0700318 return mode;
Adam Powell89e06452010-06-23 20:24:52 -0700319 }
Adam Powellac695c62010-07-20 18:19:27 -0700320 return null;
Adam Powell89e06452010-06-23 20:24:52 -0700321 }
322
Adam Powell661c9082010-07-02 10:09:44 -0700323 private void configureTab(Tab tab, int position) {
324 final TabImpl tabi = (TabImpl) tab;
Adam Powell2b6230e2010-09-07 17:55:25 -0700325 final ActionBar.TabListener callback = tabi.getCallback();
326
327 if (callback == null) {
328 throw new IllegalStateException("Action Bar Tab must have a Callback");
329 }
Adam Powell661c9082010-07-02 10:09:44 -0700330
331 tabi.setPosition(position);
332 mTabs.add(position, tabi);
333
Adam Powell81b89442010-11-02 17:58:56 -0700334 final int count = mTabs.size();
335 for (int i = position + 1; i < count; i++) {
336 mTabs.get(i).setPosition(i);
Adam Powell661c9082010-07-02 10:09:44 -0700337 }
Adam Powell661c9082010-07-02 10:09:44 -0700338 }
339
340 @Override
341 public void addTab(Tab tab) {
Adam Powell81b89442010-11-02 17:58:56 -0700342 addTab(tab, mTabs.isEmpty());
Adam Powell661c9082010-07-02 10:09:44 -0700343 }
344
345 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700346 public void addTab(Tab tab, int position) {
Adam Powell81b89442010-11-02 17:58:56 -0700347 addTab(tab, position, mTabs.isEmpty());
348 }
349
350 @Override
351 public void addTab(Tab tab, boolean setSelected) {
352 mActionView.addTab(tab, setSelected);
353 configureTab(tab, mTabs.size());
354 if (setSelected) {
355 selectTab(tab);
356 }
357 }
358
359 @Override
360 public void addTab(Tab tab, int position, boolean setSelected) {
361 mActionView.addTab(tab, position, setSelected);
Adam Powell661c9082010-07-02 10:09:44 -0700362 configureTab(tab, position);
Adam Powell81b89442010-11-02 17:58:56 -0700363 if (setSelected) {
364 selectTab(tab);
365 }
Adam Powell661c9082010-07-02 10:09:44 -0700366 }
367
368 @Override
369 public Tab newTab() {
370 return new TabImpl();
371 }
372
373 @Override
374 public void removeTab(Tab tab) {
375 removeTabAt(tab.getPosition());
376 }
377
378 @Override
379 public void removeTabAt(int position) {
Adam Powell0c24a552010-11-03 16:44:11 -0700380 int selectedTabPosition = mSelectedTab != null
381 ? mSelectedTab.getPosition() : mSavedTabPosition;
Adam Powell661c9082010-07-02 10:09:44 -0700382 mActionView.removeTabAt(position);
383 mTabs.remove(position);
384
385 final int newTabCount = mTabs.size();
386 for (int i = position; i < newTabCount; i++) {
387 mTabs.get(i).setPosition(i);
388 }
389
Adam Powell0c24a552010-11-03 16:44:11 -0700390 if (selectedTabPosition == position) {
391 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
392 }
Adam Powell661c9082010-07-02 10:09:44 -0700393 }
394
395 @Override
396 public void setTabNavigationMode() {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700397 if (mActivity == null) {
398 throw new IllegalStateException(
399 "Tab navigation mode cannot be used outside of an Activity");
400 }
Adam Powell9ab97872010-10-26 21:47:29 -0700401 setDisplayOptions(0, DISPLAY_SHOW_TITLE | DISPLAY_SHOW_CUSTOM);
Adam Powell661c9082010-07-02 10:09:44 -0700402 mActionView.setNavigationMode(NAVIGATION_MODE_TABS);
403 }
404
405 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700406 public void selectTab(Tab tab) {
Adam Powell0c24a552010-11-03 16:44:11 -0700407 if (getNavigationMode() != NAVIGATION_MODE_TABS) {
408 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
409 return;
410 }
411
412 final FragmentTransaction trans = mActivity.getFragmentManager().openTransaction()
413 .disallowAddToBackStack();
Adam Powell7f9b9052010-10-19 16:56:07 -0700414
415 if (mSelectedTab == tab) {
416 if (mSelectedTab != null) {
417 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
418 }
419 } else {
420 mActionView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
421 if (mSelectedTab != null) {
422 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
423 }
424 mSelectedTab = (TabImpl) tab;
425 if (mSelectedTab != null) {
426 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
427 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700428 }
429
430 if (!trans.isEmpty()) {
431 trans.commit();
432 }
433 }
434
435 @Override
436 public Tab getSelectedTab() {
437 return mSelectedTab;
Adam Powell661c9082010-07-02 10:09:44 -0700438 }
439
Adam Powell6b336f82010-08-10 20:13:01 -0700440 @Override
441 public int getHeight() {
442 return mActionView.getHeight();
443 }
444
445 @Override
446 public void show() {
447 // TODO animate!
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800448 mContainerView.setVisibility(View.VISIBLE);
Adam Powell6b336f82010-08-10 20:13:01 -0700449 }
450
451 @Override
452 public void hide() {
453 // TODO animate!
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800454 mContainerView.setVisibility(View.GONE);
Adam Powell6b336f82010-08-10 20:13:01 -0700455 }
456
457 public boolean isShowing() {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800458 return mContainerView.getVisibility() == View.VISIBLE;
459 }
460
461 private long animateTo(int viewIndex) {
462 // Don't wait for the current animation to finish.
463 if (mCurrentAnimation != null) {
464 mCurrentAnimation.end();
465 }
466
467 AnimatorSet set = new AnimatorSet();
468
469 final View targetChild = mContainerView.getChildAt(viewIndex);
470 targetChild.setVisibility(View.VISIBLE);
471 AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
472 if (viewIndex == NORMAL_VIEW) {
473 targetChild.setScaleY(0);
474 b.with(ObjectAnimator.ofFloat(targetChild, "scaleY", 1));
475 }
476
477 final int count = mContainerView.getChildCount();
478 for (int i = 0; i < count; i++) {
479 final View child = mContainerView.getChildAt(i);
480 if (i == viewIndex) {
481 continue;
482 }
483
484 if (child.getVisibility() != View.GONE) {
485 ObjectAnimator a = ObjectAnimator.ofFloat(child, "alpha", 0);
486 b.with(a);
487 if (viewIndex == CONTEXT_VIEW) {
488 b.with(ObjectAnimator.ofFloat(child, "scaleY", 0));
489 }
490 }
491 }
492
493 set.addListener(mAfterAnimation[viewIndex]);
494
495 mCurrentAnimation = set;
496 set.start();
497 return set.getDuration();
498 }
499
500 private void hideAllExcept(int viewIndex) {
501 final int count = mContainerView.getChildCount();
502 for (int i = 0; i < count; i++) {
503 mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE);
504 }
Adam Powell6b336f82010-08-10 20:13:01 -0700505 }
506
Adam Powell89e06452010-06-23 20:24:52 -0700507 /**
508 * @hide
509 */
Adam Powell5d279772010-07-27 16:34:07 -0700510 public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
Adam Powell6e346362010-07-23 10:18:23 -0700511 private ActionMode.Callback mCallback;
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700512 private MenuBuilder mMenu;
Adam Powell29ed7572010-07-14 16:24:56 -0700513 private WeakReference<View> mCustomView;
Adam Powell89e06452010-06-23 20:24:52 -0700514
Adam Powell5d279772010-07-27 16:34:07 -0700515 public ActionModeImpl(ActionMode.Callback callback) {
Adam Powell89e06452010-06-23 20:24:52 -0700516 mCallback = callback;
Adam Powell4d9861e2010-08-17 11:14:40 -0700517 mMenu = new MenuBuilder(mActionView.getContext())
518 .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700519 mMenu.setCallback(this);
Adam Powell89e06452010-06-23 20:24:52 -0700520 }
Adam Powell9168f0b2010-08-02 15:46:24 -0700521
522 @Override
523 public MenuInflater getMenuInflater() {
Adam Powell4d9861e2010-08-17 11:14:40 -0700524 return new MenuInflater(mContext);
Adam Powell9168f0b2010-08-02 15:46:24 -0700525 }
526
Adam Powell89e06452010-06-23 20:24:52 -0700527 @Override
528 public Menu getMenu() {
529 return mMenu;
530 }
531
532 @Override
533 public void finish() {
Adam Powell5d279772010-07-27 16:34:07 -0700534 if (mActionMode != this) {
535 // Not the active action mode - no-op
Adam Powell93b6bc32010-07-22 11:36:35 -0700536 return;
537 }
538
Adam Powell6e346362010-07-23 10:18:23 -0700539 mCallback.onDestroyActionMode(this);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800540 mCallback = null;
541 animateTo(NORMAL_VIEW);
Adam Powell0e94b512010-06-29 17:58:20 -0700542
543 // Clear out the context mode views after the animation finishes
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800544 mUpperContextView.closeMode();
Adam Powell89e06452010-06-23 20:24:52 -0700545 if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) {
546 // TODO Animate this
547 mLowerContextView.setVisibility(View.GONE);
548 }
Adam Powell5d279772010-07-27 16:34:07 -0700549 mActionMode = null;
Adam Powell89e06452010-06-23 20:24:52 -0700550 }
551
552 @Override
553 public void invalidate() {
Adam Powell6e346362010-07-23 10:18:23 -0700554 if (mCallback.onPrepareActionMode(this, mMenu)) {
Adam Powell89e06452010-06-23 20:24:52 -0700555 // Refresh content in both context views
556 }
557 }
558
559 @Override
560 public void setCustomView(View view) {
561 mUpperContextView.setCustomView(view);
Adam Powell29ed7572010-07-14 16:24:56 -0700562 mCustomView = new WeakReference<View>(view);
Adam Powell89e06452010-06-23 20:24:52 -0700563 }
564
565 @Override
566 public void setSubtitle(CharSequence subtitle) {
567 mUpperContextView.setSubtitle(subtitle);
568 }
569
570 @Override
571 public void setTitle(CharSequence title) {
572 mUpperContextView.setTitle(title);
573 }
Adam Powell29ed7572010-07-14 16:24:56 -0700574
575 @Override
Adam Powellc9ae2a22010-07-28 14:44:21 -0700576 public void setTitle(int resId) {
577 setTitle(mActivity.getString(resId));
578 }
579
580 @Override
581 public void setSubtitle(int resId) {
582 setSubtitle(mActivity.getString(resId));
583 }
584
585 @Override
Adam Powell29ed7572010-07-14 16:24:56 -0700586 public CharSequence getTitle() {
587 return mUpperContextView.getTitle();
588 }
589
590 @Override
591 public CharSequence getSubtitle() {
592 return mUpperContextView.getSubtitle();
593 }
Adam Powell89e06452010-06-23 20:24:52 -0700594
Adam Powell29ed7572010-07-14 16:24:56 -0700595 @Override
596 public View getCustomView() {
597 return mCustomView != null ? mCustomView.get() : null;
598 }
599
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700600 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800601 if (mCallback != null) {
602 return mCallback.onActionItemClicked(this, item);
603 } else {
604 return false;
605 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700606 }
607
608 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
609 }
610
611 public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800612 if (mCallback == null) {
613 return false;
614 }
615
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700616 if (!subMenu.hasVisibleItems()) {
617 return true;
Adam Powell89e06452010-06-23 20:24:52 -0700618 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700619
Adam Powelldec9dfd2010-08-09 15:27:54 -0700620 new MenuPopupHelper(mContext, subMenu).show();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700621 return true;
622 }
623
624 public void onCloseSubMenu(SubMenuBuilder menu) {
625 }
626
627 public void onMenuModeChange(MenuBuilder menu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800628 if (mCallback == null) {
629 return;
630 }
Adam Powellf6148c52010-08-11 21:10:16 -0700631 invalidate();
Adam Powell8515ee82010-11-30 14:09:55 -0800632 mUpperContextView.openOverflowMenu();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700633 }
Adam Powell661c9082010-07-02 10:09:44 -0700634 }
635
636 /**
637 * @hide
638 */
639 public class TabImpl extends ActionBar.Tab {
Adam Powell2b6230e2010-09-07 17:55:25 -0700640 private ActionBar.TabListener mCallback;
641 private Object mTag;
Adam Powell661c9082010-07-02 10:09:44 -0700642 private Drawable mIcon;
643 private CharSequence mText;
644 private int mPosition;
Adam Powell2b6230e2010-09-07 17:55:25 -0700645 private View mCustomView;
Adam Powell661c9082010-07-02 10:09:44 -0700646
647 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700648 public Object getTag() {
649 return mTag;
650 }
651
652 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700653 public Tab setTag(Object tag) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700654 mTag = tag;
Adam Powell9ab97872010-10-26 21:47:29 -0700655 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700656 }
657
658 public ActionBar.TabListener getCallback() {
659 return mCallback;
660 }
661
662 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700663 public Tab setTabListener(ActionBar.TabListener callback) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700664 mCallback = callback;
Adam Powell9ab97872010-10-26 21:47:29 -0700665 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700666 }
667
668 @Override
669 public View getCustomView() {
670 return mCustomView;
671 }
672
673 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700674 public Tab setCustomView(View view) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700675 mCustomView = view;
Adam Powell9ab97872010-10-26 21:47:29 -0700676 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700677 }
678
679 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800680 public Tab setCustomView(int layoutResId) {
681 return setCustomView(LayoutInflater.from(mContext).inflate(layoutResId, null));
682 }
683
684 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700685 public Drawable getIcon() {
686 return mIcon;
687 }
688
689 @Override
690 public int getPosition() {
691 return mPosition;
692 }
693
694 public void setPosition(int position) {
695 mPosition = position;
696 }
697
698 @Override
699 public CharSequence getText() {
700 return mText;
701 }
702
703 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700704 public Tab setIcon(Drawable icon) {
Adam Powell661c9082010-07-02 10:09:44 -0700705 mIcon = icon;
Adam Powell9ab97872010-10-26 21:47:29 -0700706 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700707 }
708
709 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800710 public Tab setIcon(int resId) {
711 return setIcon(mContext.getResources().getDrawable(resId));
712 }
713
714 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700715 public Tab setText(CharSequence text) {
Adam Powell661c9082010-07-02 10:09:44 -0700716 mText = text;
Adam Powell9ab97872010-10-26 21:47:29 -0700717 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700718 }
719
720 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800721 public Tab setText(int resId) {
722 return setText(mContext.getResources().getText(resId));
723 }
724
725 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700726 public void select() {
727 selectTab(this);
Adam Powell89e06452010-06-23 20:24:52 -0700728 }
729 }
Adam Powell9ab97872010-10-26 21:47:29 -0700730
731 @Override
732 public void setCustomView(View view) {
733 mActionView.setCustomNavigationView(view);
734 }
735
736 @Override
737 public void setCustomView(View view, LayoutParams layoutParams) {
738 view.setLayoutParams(layoutParams);
739 mActionView.setCustomNavigationView(view);
740 }
741
742 @Override
Adam Powell8515ee82010-11-30 14:09:55 -0800743 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
Adam Powell9ab97872010-10-26 21:47:29 -0700744 mActionView.setDropdownAdapter(adapter);
745 mActionView.setCallback(callback);
746 }
747
748 @Override
749 public int getSelectedNavigationIndex() {
750 switch (mActionView.getNavigationMode()) {
751 case NAVIGATION_MODE_TABS:
Adam Powell04587962010-11-11 22:15:07 -0800752 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
Adam Powell9ab97872010-10-26 21:47:29 -0700753 case NAVIGATION_MODE_LIST:
754 return mActionView.getDropdownSelectedPosition();
755 default:
756 return -1;
757 }
758 }
759
760 @Override
761 public int getNavigationItemCount() {
762 switch (mActionView.getNavigationMode()) {
763 case NAVIGATION_MODE_TABS:
764 return mTabs.size();
765 case NAVIGATION_MODE_LIST:
766 SpinnerAdapter adapter = mActionView.getDropdownAdapter();
767 return adapter != null ? adapter.getCount() : 0;
768 default:
769 return 0;
770 }
771 }
772
773 @Override
Adam Powell0c24a552010-11-03 16:44:11 -0700774 public int getTabCount() {
775 return mTabs.size();
776 }
777
778 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700779 public void setNavigationMode(int mode) {
Adam Powell0c24a552010-11-03 16:44:11 -0700780 final int oldMode = mActionView.getNavigationMode();
781 switch (oldMode) {
782 case NAVIGATION_MODE_TABS:
783 mSavedTabPosition = getSelectedNavigationIndex();
784 selectTab(null);
785 break;
786 }
Adam Powell9ab97872010-10-26 21:47:29 -0700787 mActionView.setNavigationMode(mode);
Adam Powell0c24a552010-11-03 16:44:11 -0700788 switch (mode) {
789 case NAVIGATION_MODE_TABS:
790 if (mSavedTabPosition != INVALID_POSITION) {
791 setSelectedNavigationItem(mSavedTabPosition);
792 mSavedTabPosition = INVALID_POSITION;
793 }
794 break;
795 }
Adam Powell9ab97872010-10-26 21:47:29 -0700796 }
797
798 @Override
799 public Tab getTabAt(int index) {
800 return mTabs.get(index);
801 }
Adam Powell0c24a552010-11-03 16:44:11 -0700802
803 /**
804 * This fragment is added when we're keeping a back stack in a tab switch
805 * transaction. We use it to change the selected tab in the action bar view
806 * when we back out.
807 */
808 private class SwitchSelectedTabViewFragment extends Fragment {
809 private int mSelectedTabIndex;
810
811 public SwitchSelectedTabViewFragment(int oldSelectedTab) {
812 mSelectedTabIndex = oldSelectedTab;
813 }
814
815 @Override
816 public void onDetach() {
817 if (mSelectedTabIndex >= 0 && mSelectedTabIndex < getTabCount()) {
818 mActionView.setTabSelected(mSelectedTabIndex);
819 }
820 }
821 }
Adam Powell89e06452010-06-23 20:24:52 -0700822}