blob: ab53adb8ae43e6aa5b73e24242bfecffb45e3a6f [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 Powell45f1e082010-12-10 14:20:13 -080029import android.animation.TimeInterpolator;
Adam Powell89e06452010-06-23 20:24:52 -070030import android.app.ActionBar;
Adam Powell661c9082010-07-02 10:09:44 -070031import android.app.Activity;
Adam Powelldec9dfd2010-08-09 15:27:54 -070032import android.app.Dialog;
Adam Powell661c9082010-07-02 10:09:44 -070033import android.app.Fragment;
34import android.app.FragmentTransaction;
Adam Powelldec9dfd2010-08-09 15:27:54 -070035import android.content.Context;
Adam Powell89e06452010-06-23 20:24:52 -070036import android.graphics.drawable.Drawable;
Adam Powell0e94b512010-06-29 17:58:20 -070037import android.os.Handler;
Adam Powell6e346362010-07-23 10:18:23 -070038import android.view.ActionMode;
Adam Powell32555f32010-11-17 13:49:22 -080039import android.view.LayoutInflater;
Adam Powell89e06452010-06-23 20:24:52 -070040import android.view.Menu;
Adam Powell9168f0b2010-08-02 15:46:24 -070041import android.view.MenuInflater;
Adam Powell89e06452010-06-23 20:24:52 -070042import android.view.MenuItem;
43import android.view.View;
Adam Powelle6ec7322010-12-07 15:29:26 -080044import android.view.Window;
Adam Powell45f1e082010-12-10 14:20:13 -080045import android.view.animation.DecelerateInterpolator;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080046import android.widget.FrameLayout;
Adam Powell89e06452010-06-23 20:24:52 -070047import android.widget.LinearLayout;
48import android.widget.SpinnerAdapter;
Adam Powell89e06452010-06-23 20:24:52 -070049
Adam Powell29ed7572010-07-14 16:24:56 -070050import java.lang.ref.WeakReference;
Adam Powell661c9082010-07-02 10:09:44 -070051import java.util.ArrayList;
52
Adam Powell89e06452010-06-23 20:24:52 -070053/**
54 * ActionBarImpl is the ActionBar implementation used
55 * by devices of all screen sizes. If it detects a compatible decor,
56 * it will split contextual modes across both the ActionBarView at
57 * the top of the screen and a horizontal LinearLayout at the bottom
58 * which is normally hidden.
59 */
60public class ActionBarImpl extends ActionBar {
61 private static final int NORMAL_VIEW = 0;
62 private static final int CONTEXT_VIEW = 1;
Adam Powell661c9082010-07-02 10:09:44 -070063
Adam Powelldec9dfd2010-08-09 15:27:54 -070064 private Context mContext;
Adam Powell661c9082010-07-02 10:09:44 -070065 private Activity mActivity;
Adam Powelldec9dfd2010-08-09 15:27:54 -070066 private Dialog mDialog;
Adam Powell661c9082010-07-02 10:09:44 -070067
Adam Powelld8b3f2e2010-12-02 13:37:03 -080068 private FrameLayout mContainerView;
Adam Powell89e06452010-06-23 20:24:52 -070069 private ActionBarView mActionView;
70 private ActionBarContextView mUpperContextView;
71 private LinearLayout mLowerContextView;
Adam Powelle6ec7322010-12-07 15:29:26 -080072 private View mContentView;
Adam Powell661c9082010-07-02 10:09:44 -070073
74 private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
75
Adam Powell661c9082010-07-02 10:09:44 -070076 private TabImpl mSelectedTab;
Adam Powell0c24a552010-11-03 16:44:11 -070077 private int mSavedTabPosition = INVALID_POSITION;
Adam Powell89e06452010-06-23 20:24:52 -070078
Adam Powell5d279772010-07-27 16:34:07 -070079 private ActionMode mActionMode;
Adam Powell89e06452010-06-23 20:24:52 -070080
Adam Powell8515ee82010-11-30 14:09:55 -080081 private boolean mLastMenuVisibility;
82 private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
83 new ArrayList<OnMenuVisibilityListener>();
84
Adam Powell89e06452010-06-23 20:24:52 -070085 private static final int CONTEXT_DISPLAY_NORMAL = 0;
86 private static final int CONTEXT_DISPLAY_SPLIT = 1;
87
Adam Powell0c24a552010-11-03 16:44:11 -070088 private static final int INVALID_POSITION = -1;
89
Adam Powell89e06452010-06-23 20:24:52 -070090 private int mContextDisplayMode;
Adam Powell0e94b512010-06-29 17:58:20 -070091
92 final Handler mHandler = new Handler();
Adam Powelld8b3f2e2010-12-02 13:37:03 -080093
Adam Powelle6ec7322010-12-07 15:29:26 -080094 private Animator mCurrentAnim;
Adam Powell50efbed2011-02-08 16:20:15 -080095 private boolean mShowHideAnimationEnabled;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080096
Adam Powell45f1e082010-12-10 14:20:13 -080097 private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator();
98
Adam Powelld8b3f2e2010-12-02 13:37:03 -080099 final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
100 new AnimatorListener() { // NORMAL_VIEW
101 @Override
102 public void onAnimationStart(Animator animation) {
103 }
104
105 @Override
106 public void onAnimationEnd(Animator animation) {
107 if (mLowerContextView != null) {
108 mLowerContextView.removeAllViews();
109 }
Adam Powelle6ec7322010-12-07 15:29:26 -0800110 mCurrentAnim = null;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800111 hideAllExcept(NORMAL_VIEW);
112 }
113
114 @Override
115 public void onAnimationCancel(Animator animation) {
116 }
117
118 @Override
119 public void onAnimationRepeat(Animator animation) {
120 }
121 },
122 new AnimatorListener() { // CONTEXT_VIEW
123 @Override
124 public void onAnimationStart(Animator animation) {
125 }
126
127 @Override
128 public void onAnimationEnd(Animator animation) {
Adam Powelle6ec7322010-12-07 15:29:26 -0800129 mCurrentAnim = null;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800130 hideAllExcept(CONTEXT_VIEW);
131 }
132
133 @Override
134 public void onAnimationCancel(Animator animation) {
135 }
136
137 @Override
138 public void onAnimationRepeat(Animator animation) {
139 }
Adam Powell0e94b512010-06-29 17:58:20 -0700140 }
Adam Powell0e94b512010-06-29 17:58:20 -0700141 };
142
Adam Powelle6ec7322010-12-07 15:29:26 -0800143 final AnimatorListener mHideListener = new AnimatorListener() {
144 @Override
145 public void onAnimationStart(Animator animation) {
146 }
147
148 @Override
149 public void onAnimationEnd(Animator animation) {
150 if (mContentView != null) {
151 mContentView.setTranslationY(0);
152 }
153 mContainerView.setVisibility(View.GONE);
154 mCurrentAnim = null;
155 }
156
157 @Override
158 public void onAnimationCancel(Animator animation) {
159 }
160
161 @Override
162 public void onAnimationRepeat(Animator animation) {
163 }
164 };
165
166 final AnimatorListener mShowListener = new AnimatorListener() {
167 @Override
168 public void onAnimationStart(Animator animation) {
169 }
170
171 @Override
172 public void onAnimationEnd(Animator animation) {
173 mCurrentAnim = null;
Adam Powell45f1e082010-12-10 14:20:13 -0800174 mContainerView.requestLayout();
Adam Powelle6ec7322010-12-07 15:29:26 -0800175 }
176
177 @Override
178 public void onAnimationCancel(Animator animation) {
179 }
180
181 @Override
182 public void onAnimationRepeat(Animator animation) {
183 }
184 };
185
Adam Powell661c9082010-07-02 10:09:44 -0700186 public ActionBarImpl(Activity activity) {
Adam Powell661c9082010-07-02 10:09:44 -0700187 mActivity = activity;
Adam Powelle6ec7322010-12-07 15:29:26 -0800188 Window window = activity.getWindow();
189 View decor = window.getDecorView();
190 init(decor);
191 if (!mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) {
192 mContentView = decor.findViewById(android.R.id.content);
193 }
Adam Powelldec9dfd2010-08-09 15:27:54 -0700194 }
195
196 public ActionBarImpl(Dialog dialog) {
197 mDialog = dialog;
198 init(dialog.getWindow().getDecorView());
199 }
200
201 private void init(View decor) {
202 mContext = decor.getContext();
Adam Powell89e06452010-06-23 20:24:52 -0700203 mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
204 mUpperContextView = (ActionBarContextView) decor.findViewById(
205 com.android.internal.R.id.action_context_bar);
206 mLowerContextView = (LinearLayout) decor.findViewById(
207 com.android.internal.R.id.lower_action_context_bar);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800208 mContainerView = (FrameLayout) decor.findViewById(
209 com.android.internal.R.id.action_bar_container);
Steve Block08f194b2010-08-24 18:20:48 +0100210
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800211 if (mActionView == null || mUpperContextView == null || mContainerView == null) {
Adam Powell89e06452010-06-23 20:24:52 -0700212 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
213 "with a compatible window decor layout");
214 }
Adam Powell0e94b512010-06-29 17:58:20 -0700215
Steve Block08f194b2010-08-24 18:20:48 +0100216 mActionView.setContextView(mUpperContextView);
Adam Powell89e06452010-06-23 20:24:52 -0700217 mContextDisplayMode = mLowerContextView == null ?
218 CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT;
219 }
220
Adam Powell50efbed2011-02-08 16:20:15 -0800221 /**
222 * Enables or disables animation between show/hide states.
223 * If animation is disabled using this method, animations in progress
224 * will be finished.
225 *
226 * @param enabled true to animate, false to not animate.
227 */
228 public void setShowHideAnimationEnabled(boolean enabled) {
229 mShowHideAnimationEnabled = enabled;
230 if (!enabled && mCurrentAnim != null) {
231 mCurrentAnim.end();
232 }
233 }
234
Adam Powell8515ee82010-11-30 14:09:55 -0800235 public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
236 mMenuVisibilityListeners.add(listener);
237 }
238
239 public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
240 mMenuVisibilityListeners.remove(listener);
241 }
242
243 public void dispatchMenuVisibilityChanged(boolean isVisible) {
244 if (isVisible == mLastMenuVisibility) {
245 return;
246 }
247 mLastMenuVisibility = isVisible;
248
249 final int count = mMenuVisibilityListeners.size();
250 for (int i = 0; i < count; i++) {
251 mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
252 }
253 }
254
Adam Powella66c7b02010-07-28 15:28:25 -0700255 @Override
Adam Powell3f476b32011-01-03 19:25:36 -0800256 public void setCustomView(int resId) {
257 setCustomView(LayoutInflater.from(mContext).inflate(resId, mActionView, false));
258 }
259
260 @Override
261 public void setDisplayUseLogoEnabled(boolean useLogo) {
262 setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
263 }
264
265 @Override
266 public void setDisplayShowHomeEnabled(boolean showHome) {
267 setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
268 }
269
270 @Override
271 public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
272 setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
273 }
274
275 @Override
276 public void setDisplayShowTitleEnabled(boolean showTitle) {
277 setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
278 }
279
280 @Override
281 public void setDisplayShowCustomEnabled(boolean showCustom) {
282 setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
283 }
284
285 @Override
Adam Powella66c7b02010-07-28 15:28:25 -0700286 public void setTitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700287 setTitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700288 }
289
290 @Override
291 public void setSubtitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700292 setSubtitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700293 }
294
Adam Powell17809772010-07-21 13:25:11 -0700295 public void setSelectedNavigationItem(int position) {
296 switch (mActionView.getNavigationMode()) {
297 case NAVIGATION_MODE_TABS:
298 selectTab(mTabs.get(position));
299 break;
Adam Powell9ab97872010-10-26 21:47:29 -0700300 case NAVIGATION_MODE_LIST:
Adam Powell17809772010-07-21 13:25:11 -0700301 mActionView.setDropdownSelectedPosition(position);
302 break;
303 default:
304 throw new IllegalStateException(
Adam Powell9ab97872010-10-26 21:47:29 -0700305 "setSelectedNavigationIndex not valid for current navigation mode");
Adam Powell17809772010-07-21 13:25:11 -0700306 }
307 }
308
Adam Powell9ab97872010-10-26 21:47:29 -0700309 public void removeAllTabs() {
310 cleanupTabs();
Adam Powell17809772010-07-21 13:25:11 -0700311 }
312
Adam Powell661c9082010-07-02 10:09:44 -0700313 private void cleanupTabs() {
314 if (mSelectedTab != null) {
315 selectTab(null);
316 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700317 mTabs.clear();
Adam Powell0c24a552010-11-03 16:44:11 -0700318 mActionView.removeAllTabs();
319 mSavedTabPosition = INVALID_POSITION;
Adam Powell661c9082010-07-02 10:09:44 -0700320 }
321
Adam Powell0e94b512010-06-29 17:58:20 -0700322 public void setTitle(CharSequence title) {
323 mActionView.setTitle(title);
324 }
325
326 public void setSubtitle(CharSequence subtitle) {
327 mActionView.setSubtitle(subtitle);
328 }
329
Adam Powell89e06452010-06-23 20:24:52 -0700330 public void setDisplayOptions(int options) {
331 mActionView.setDisplayOptions(options);
332 }
Adam Powell0e94b512010-06-29 17:58:20 -0700333
Adam Powell89e06452010-06-23 20:24:52 -0700334 public void setDisplayOptions(int options, int mask) {
335 final int current = mActionView.getDisplayOptions();
336 mActionView.setDisplayOptions((options & mask) | (current & ~mask));
337 }
338
339 public void setBackgroundDrawable(Drawable d) {
Adam Powelle8c1e5c2010-12-13 10:49:32 -0800340 mContainerView.setBackgroundDrawable(d);
Adam Powell89e06452010-06-23 20:24:52 -0700341 }
342
Adam Powellef704442010-11-16 14:48:22 -0800343 public View getCustomView() {
Adam Powell89e06452010-06-23 20:24:52 -0700344 return mActionView.getCustomNavigationView();
345 }
346
347 public CharSequence getTitle() {
348 return mActionView.getTitle();
349 }
350
351 public CharSequence getSubtitle() {
352 return mActionView.getSubtitle();
353 }
354
355 public int getNavigationMode() {
356 return mActionView.getNavigationMode();
357 }
358
359 public int getDisplayOptions() {
360 return mActionView.getDisplayOptions();
361 }
362
Adam Powell5d279772010-07-27 16:34:07 -0700363 public ActionMode startActionMode(ActionMode.Callback callback) {
364 if (mActionMode != null) {
365 mActionMode.finish();
Adam Powell6e346362010-07-23 10:18:23 -0700366 }
Adam Powell3461b322010-07-14 11:34:43 -0700367
Adam Powella1e63582011-01-18 16:51:22 -0800368 mUpperContextView.killMode();
Adam Powell5d279772010-07-27 16:34:07 -0700369 ActionMode mode = new ActionModeImpl(callback);
Adam Powell6e346362010-07-23 10:18:23 -0700370 if (callback.onCreateActionMode(mode, mode.getMenu())) {
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700371 mode.invalidate();
372 mUpperContextView.initForMode(mode);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800373 animateTo(CONTEXT_VIEW);
Adam Powell89e06452010-06-23 20:24:52 -0700374 if (mLowerContextView != null) {
375 // TODO animate this
376 mLowerContextView.setVisibility(View.VISIBLE);
377 }
Adam Powell5d279772010-07-27 16:34:07 -0700378 mActionMode = mode;
Adam Powell50efbed2011-02-08 16:20:15 -0800379 show();
Adam Powellac695c62010-07-20 18:19:27 -0700380 return mode;
Adam Powell89e06452010-06-23 20:24:52 -0700381 }
Adam Powellac695c62010-07-20 18:19:27 -0700382 return null;
Adam Powell89e06452010-06-23 20:24:52 -0700383 }
384
Adam Powell661c9082010-07-02 10:09:44 -0700385 private void configureTab(Tab tab, int position) {
386 final TabImpl tabi = (TabImpl) tab;
Adam Powell2b6230e2010-09-07 17:55:25 -0700387 final ActionBar.TabListener callback = tabi.getCallback();
388
389 if (callback == null) {
390 throw new IllegalStateException("Action Bar Tab must have a Callback");
391 }
Adam Powell661c9082010-07-02 10:09:44 -0700392
393 tabi.setPosition(position);
394 mTabs.add(position, tabi);
395
Adam Powell81b89442010-11-02 17:58:56 -0700396 final int count = mTabs.size();
397 for (int i = position + 1; i < count; i++) {
398 mTabs.get(i).setPosition(i);
Adam Powell661c9082010-07-02 10:09:44 -0700399 }
Adam Powell661c9082010-07-02 10:09:44 -0700400 }
401
402 @Override
403 public void addTab(Tab tab) {
Adam Powell81b89442010-11-02 17:58:56 -0700404 addTab(tab, mTabs.isEmpty());
Adam Powell661c9082010-07-02 10:09:44 -0700405 }
406
407 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700408 public void addTab(Tab tab, int position) {
Adam Powell81b89442010-11-02 17:58:56 -0700409 addTab(tab, position, mTabs.isEmpty());
410 }
411
412 @Override
413 public void addTab(Tab tab, boolean setSelected) {
414 mActionView.addTab(tab, setSelected);
415 configureTab(tab, mTabs.size());
416 if (setSelected) {
417 selectTab(tab);
418 }
419 }
420
421 @Override
422 public void addTab(Tab tab, int position, boolean setSelected) {
423 mActionView.addTab(tab, position, setSelected);
Adam Powell661c9082010-07-02 10:09:44 -0700424 configureTab(tab, position);
Adam Powell81b89442010-11-02 17:58:56 -0700425 if (setSelected) {
426 selectTab(tab);
427 }
Adam Powell661c9082010-07-02 10:09:44 -0700428 }
429
430 @Override
431 public Tab newTab() {
432 return new TabImpl();
433 }
434
435 @Override
436 public void removeTab(Tab tab) {
437 removeTabAt(tab.getPosition());
438 }
439
440 @Override
441 public void removeTabAt(int position) {
Adam Powell0c24a552010-11-03 16:44:11 -0700442 int selectedTabPosition = mSelectedTab != null
443 ? mSelectedTab.getPosition() : mSavedTabPosition;
Adam Powell661c9082010-07-02 10:09:44 -0700444 mActionView.removeTabAt(position);
445 mTabs.remove(position);
446
447 final int newTabCount = mTabs.size();
448 for (int i = position; i < newTabCount; i++) {
449 mTabs.get(i).setPosition(i);
450 }
451
Adam Powell0c24a552010-11-03 16:44:11 -0700452 if (selectedTabPosition == position) {
453 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
454 }
Adam Powell661c9082010-07-02 10:09:44 -0700455 }
456
457 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700458 public void selectTab(Tab tab) {
Adam Powell0c24a552010-11-03 16:44:11 -0700459 if (getNavigationMode() != NAVIGATION_MODE_TABS) {
460 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
461 return;
462 }
463
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800464 final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction()
Adam Powell0c24a552010-11-03 16:44:11 -0700465 .disallowAddToBackStack();
Adam Powell7f9b9052010-10-19 16:56:07 -0700466
467 if (mSelectedTab == tab) {
468 if (mSelectedTab != null) {
469 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
470 }
471 } else {
472 mActionView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
473 if (mSelectedTab != null) {
474 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
475 }
476 mSelectedTab = (TabImpl) tab;
477 if (mSelectedTab != null) {
478 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
479 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700480 }
481
482 if (!trans.isEmpty()) {
483 trans.commit();
484 }
485 }
486
487 @Override
488 public Tab getSelectedTab() {
489 return mSelectedTab;
Adam Powell661c9082010-07-02 10:09:44 -0700490 }
491
Adam Powell6b336f82010-08-10 20:13:01 -0700492 @Override
493 public int getHeight() {
494 return mActionView.getHeight();
495 }
496
497 @Override
498 public void show() {
Adam Powell45f1e082010-12-10 14:20:13 -0800499 if (mCurrentAnim != null) {
500 mCurrentAnim.end();
501 }
Adam Powelld76cee22011-01-31 15:05:05 -0800502 if (mContainerView.getVisibility() == View.VISIBLE) {
503 return;
504 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800505 mContainerView.setVisibility(View.VISIBLE);
Adam Powell50efbed2011-02-08 16:20:15 -0800506
507 if (mShowHideAnimationEnabled) {
508 mContainerView.setAlpha(0);
509 AnimatorSet anim = new AnimatorSet();
510 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1));
511 if (mContentView != null) {
512 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
513 -mContainerView.getHeight(), 0));
514 mContainerView.setTranslationY(-mContainerView.getHeight());
515 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
516 }
517 anim.addListener(mShowListener);
518 mCurrentAnim = anim;
519 anim.start();
520 } else {
521 mShowListener.onAnimationEnd(null);
Adam Powelle6ec7322010-12-07 15:29:26 -0800522 }
Adam Powell6b336f82010-08-10 20:13:01 -0700523 }
524
525 @Override
526 public void hide() {
Adam Powelle6ec7322010-12-07 15:29:26 -0800527 if (mCurrentAnim != null) {
528 mCurrentAnim.end();
529 }
530 if (mContainerView.getVisibility() == View.GONE) {
531 return;
532 }
Adam Powell50efbed2011-02-08 16:20:15 -0800533
534 if (mShowHideAnimationEnabled) {
535 mContainerView.setAlpha(1);
536 AnimatorSet anim = new AnimatorSet();
537 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0));
538 if (mContentView != null) {
539 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
540 0, -mContainerView.getHeight()));
541 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
542 -mContainerView.getHeight()));
543 }
544 anim.addListener(mHideListener);
545 mCurrentAnim = anim;
546 anim.start();
547 } else {
548 mHideListener.onAnimationEnd(null);
Adam Powelle6ec7322010-12-07 15:29:26 -0800549 }
Adam Powell6b336f82010-08-10 20:13:01 -0700550 }
551
552 public boolean isShowing() {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800553 return mContainerView.getVisibility() == View.VISIBLE;
554 }
555
556 private long animateTo(int viewIndex) {
Adam Powelle6ec7322010-12-07 15:29:26 -0800557 show();
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800558
559 AnimatorSet set = new AnimatorSet();
560
561 final View targetChild = mContainerView.getChildAt(viewIndex);
562 targetChild.setVisibility(View.VISIBLE);
563 AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800564
565 final int count = mContainerView.getChildCount();
566 for (int i = 0; i < count; i++) {
567 final View child = mContainerView.getChildAt(i);
568 if (i == viewIndex) {
569 continue;
570 }
571
572 if (child.getVisibility() != View.GONE) {
Adam Powell45f1e082010-12-10 14:20:13 -0800573 Animator a = ObjectAnimator.ofFloat(child, "alpha", 0);
574 a.setInterpolator(sFadeOutInterpolator);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800575 b.with(a);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800576 }
577 }
578
579 set.addListener(mAfterAnimation[viewIndex]);
580
Adam Powelle6ec7322010-12-07 15:29:26 -0800581 mCurrentAnim = set;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800582 set.start();
583 return set.getDuration();
584 }
585
586 private void hideAllExcept(int viewIndex) {
587 final int count = mContainerView.getChildCount();
588 for (int i = 0; i < count; i++) {
589 mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE);
590 }
Adam Powell6b336f82010-08-10 20:13:01 -0700591 }
592
Adam Powell89e06452010-06-23 20:24:52 -0700593 /**
594 * @hide
595 */
Adam Powell5d279772010-07-27 16:34:07 -0700596 public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
Adam Powell6e346362010-07-23 10:18:23 -0700597 private ActionMode.Callback mCallback;
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700598 private MenuBuilder mMenu;
Adam Powell29ed7572010-07-14 16:24:56 -0700599 private WeakReference<View> mCustomView;
Adam Powell89e06452010-06-23 20:24:52 -0700600
Adam Powell5d279772010-07-27 16:34:07 -0700601 public ActionModeImpl(ActionMode.Callback callback) {
Adam Powell89e06452010-06-23 20:24:52 -0700602 mCallback = callback;
Adam Powell4d9861e2010-08-17 11:14:40 -0700603 mMenu = new MenuBuilder(mActionView.getContext())
604 .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700605 mMenu.setCallback(this);
Adam Powell89e06452010-06-23 20:24:52 -0700606 }
Adam Powell9168f0b2010-08-02 15:46:24 -0700607
608 @Override
609 public MenuInflater getMenuInflater() {
Adam Powell4d9861e2010-08-17 11:14:40 -0700610 return new MenuInflater(mContext);
Adam Powell9168f0b2010-08-02 15:46:24 -0700611 }
612
Adam Powell89e06452010-06-23 20:24:52 -0700613 @Override
614 public Menu getMenu() {
615 return mMenu;
616 }
617
618 @Override
619 public void finish() {
Adam Powell5d279772010-07-27 16:34:07 -0700620 if (mActionMode != this) {
621 // Not the active action mode - no-op
Adam Powell93b6bc32010-07-22 11:36:35 -0700622 return;
623 }
624
Adam Powell6e346362010-07-23 10:18:23 -0700625 mCallback.onDestroyActionMode(this);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800626 mCallback = null;
627 animateTo(NORMAL_VIEW);
Adam Powell0e94b512010-06-29 17:58:20 -0700628
629 // Clear out the context mode views after the animation finishes
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800630 mUpperContextView.closeMode();
Adam Powell89e06452010-06-23 20:24:52 -0700631 if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) {
632 // TODO Animate this
633 mLowerContextView.setVisibility(View.GONE);
634 }
Adam Powell5d279772010-07-27 16:34:07 -0700635 mActionMode = null;
Adam Powell89e06452010-06-23 20:24:52 -0700636 }
637
638 @Override
639 public void invalidate() {
Adam Powell6e346362010-07-23 10:18:23 -0700640 if (mCallback.onPrepareActionMode(this, mMenu)) {
Adam Powell89e06452010-06-23 20:24:52 -0700641 // Refresh content in both context views
642 }
643 }
644
645 @Override
646 public void setCustomView(View view) {
647 mUpperContextView.setCustomView(view);
Adam Powell29ed7572010-07-14 16:24:56 -0700648 mCustomView = new WeakReference<View>(view);
Adam Powell89e06452010-06-23 20:24:52 -0700649 }
650
651 @Override
652 public void setSubtitle(CharSequence subtitle) {
653 mUpperContextView.setSubtitle(subtitle);
654 }
655
656 @Override
657 public void setTitle(CharSequence title) {
658 mUpperContextView.setTitle(title);
659 }
Adam Powell29ed7572010-07-14 16:24:56 -0700660
661 @Override
Adam Powellc9ae2a22010-07-28 14:44:21 -0700662 public void setTitle(int resId) {
Adam Powell48e8ac32011-01-14 12:10:24 -0800663 setTitle(mContext.getResources().getString(resId));
Adam Powellc9ae2a22010-07-28 14:44:21 -0700664 }
665
666 @Override
667 public void setSubtitle(int resId) {
Adam Powell48e8ac32011-01-14 12:10:24 -0800668 setSubtitle(mContext.getResources().getString(resId));
Adam Powellc9ae2a22010-07-28 14:44:21 -0700669 }
670
671 @Override
Adam Powell29ed7572010-07-14 16:24:56 -0700672 public CharSequence getTitle() {
673 return mUpperContextView.getTitle();
674 }
675
676 @Override
677 public CharSequence getSubtitle() {
678 return mUpperContextView.getSubtitle();
679 }
Adam Powell89e06452010-06-23 20:24:52 -0700680
Adam Powell29ed7572010-07-14 16:24:56 -0700681 @Override
682 public View getCustomView() {
683 return mCustomView != null ? mCustomView.get() : null;
684 }
685
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700686 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800687 if (mCallback != null) {
688 return mCallback.onActionItemClicked(this, item);
689 } else {
690 return false;
691 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700692 }
693
694 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
695 }
696
697 public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800698 if (mCallback == null) {
699 return false;
700 }
701
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700702 if (!subMenu.hasVisibleItems()) {
703 return true;
Adam Powell89e06452010-06-23 20:24:52 -0700704 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700705
Adam Powelldec9dfd2010-08-09 15:27:54 -0700706 new MenuPopupHelper(mContext, subMenu).show();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700707 return true;
708 }
709
710 public void onCloseSubMenu(SubMenuBuilder menu) {
711 }
712
713 public void onMenuModeChange(MenuBuilder menu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800714 if (mCallback == null) {
715 return;
716 }
Adam Powellf6148c52010-08-11 21:10:16 -0700717 invalidate();
Adam Powell8515ee82010-11-30 14:09:55 -0800718 mUpperContextView.openOverflowMenu();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700719 }
Adam Powell661c9082010-07-02 10:09:44 -0700720 }
721
722 /**
723 * @hide
724 */
725 public class TabImpl extends ActionBar.Tab {
Adam Powell2b6230e2010-09-07 17:55:25 -0700726 private ActionBar.TabListener mCallback;
727 private Object mTag;
Adam Powell661c9082010-07-02 10:09:44 -0700728 private Drawable mIcon;
729 private CharSequence mText;
730 private int mPosition;
Adam Powell2b6230e2010-09-07 17:55:25 -0700731 private View mCustomView;
Adam Powell661c9082010-07-02 10:09:44 -0700732
733 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700734 public Object getTag() {
735 return mTag;
736 }
737
738 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700739 public Tab setTag(Object tag) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700740 mTag = tag;
Adam Powell9ab97872010-10-26 21:47:29 -0700741 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700742 }
743
744 public ActionBar.TabListener getCallback() {
745 return mCallback;
746 }
747
748 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700749 public Tab setTabListener(ActionBar.TabListener callback) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700750 mCallback = callback;
Adam Powell9ab97872010-10-26 21:47:29 -0700751 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700752 }
753
754 @Override
755 public View getCustomView() {
756 return mCustomView;
757 }
758
759 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700760 public Tab setCustomView(View view) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700761 mCustomView = view;
Adam Powell9ab97872010-10-26 21:47:29 -0700762 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700763 }
764
765 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800766 public Tab setCustomView(int layoutResId) {
767 return setCustomView(LayoutInflater.from(mContext).inflate(layoutResId, null));
768 }
769
770 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700771 public Drawable getIcon() {
772 return mIcon;
773 }
774
775 @Override
776 public int getPosition() {
777 return mPosition;
778 }
779
780 public void setPosition(int position) {
781 mPosition = position;
782 }
783
784 @Override
785 public CharSequence getText() {
786 return mText;
787 }
788
789 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700790 public Tab setIcon(Drawable icon) {
Adam Powell661c9082010-07-02 10:09:44 -0700791 mIcon = icon;
Adam Powell9ab97872010-10-26 21:47:29 -0700792 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700793 }
794
795 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800796 public Tab setIcon(int resId) {
797 return setIcon(mContext.getResources().getDrawable(resId));
798 }
799
800 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700801 public Tab setText(CharSequence text) {
Adam Powell661c9082010-07-02 10:09:44 -0700802 mText = text;
Adam Powell9ab97872010-10-26 21:47:29 -0700803 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700804 }
805
806 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800807 public Tab setText(int resId) {
808 return setText(mContext.getResources().getText(resId));
809 }
810
811 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700812 public void select() {
813 selectTab(this);
Adam Powell89e06452010-06-23 20:24:52 -0700814 }
815 }
Adam Powell9ab97872010-10-26 21:47:29 -0700816
817 @Override
818 public void setCustomView(View view) {
819 mActionView.setCustomNavigationView(view);
820 }
821
822 @Override
823 public void setCustomView(View view, LayoutParams layoutParams) {
824 view.setLayoutParams(layoutParams);
825 mActionView.setCustomNavigationView(view);
826 }
827
828 @Override
Adam Powell8515ee82010-11-30 14:09:55 -0800829 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
Adam Powell9ab97872010-10-26 21:47:29 -0700830 mActionView.setDropdownAdapter(adapter);
831 mActionView.setCallback(callback);
832 }
833
834 @Override
835 public int getSelectedNavigationIndex() {
836 switch (mActionView.getNavigationMode()) {
837 case NAVIGATION_MODE_TABS:
Adam Powell04587962010-11-11 22:15:07 -0800838 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
Adam Powell9ab97872010-10-26 21:47:29 -0700839 case NAVIGATION_MODE_LIST:
840 return mActionView.getDropdownSelectedPosition();
841 default:
842 return -1;
843 }
844 }
845
846 @Override
847 public int getNavigationItemCount() {
848 switch (mActionView.getNavigationMode()) {
849 case NAVIGATION_MODE_TABS:
850 return mTabs.size();
851 case NAVIGATION_MODE_LIST:
852 SpinnerAdapter adapter = mActionView.getDropdownAdapter();
853 return adapter != null ? adapter.getCount() : 0;
854 default:
855 return 0;
856 }
857 }
858
859 @Override
Adam Powell0c24a552010-11-03 16:44:11 -0700860 public int getTabCount() {
861 return mTabs.size();
862 }
863
864 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700865 public void setNavigationMode(int mode) {
Adam Powell0c24a552010-11-03 16:44:11 -0700866 final int oldMode = mActionView.getNavigationMode();
867 switch (oldMode) {
868 case NAVIGATION_MODE_TABS:
869 mSavedTabPosition = getSelectedNavigationIndex();
870 selectTab(null);
871 break;
872 }
Adam Powell9ab97872010-10-26 21:47:29 -0700873 mActionView.setNavigationMode(mode);
Adam Powell0c24a552010-11-03 16:44:11 -0700874 switch (mode) {
875 case NAVIGATION_MODE_TABS:
876 if (mSavedTabPosition != INVALID_POSITION) {
877 setSelectedNavigationItem(mSavedTabPosition);
878 mSavedTabPosition = INVALID_POSITION;
879 }
880 break;
881 }
Adam Powell9ab97872010-10-26 21:47:29 -0700882 }
883
884 @Override
885 public Tab getTabAt(int index) {
886 return mTabs.get(index);
887 }
Adam Powell0c24a552010-11-03 16:44:11 -0700888
889 /**
890 * This fragment is added when we're keeping a back stack in a tab switch
891 * transaction. We use it to change the selected tab in the action bar view
892 * when we back out.
893 */
894 private class SwitchSelectedTabViewFragment extends Fragment {
895 private int mSelectedTabIndex;
896
897 public SwitchSelectedTabViewFragment(int oldSelectedTab) {
898 mSelectedTabIndex = oldSelectedTab;
899 }
900
901 @Override
902 public void onDetach() {
903 if (mSelectedTabIndex >= 0 && mSelectedTabIndex < getTabCount()) {
904 mActionView.setTabSelected(mSelectedTabIndex);
905 }
906 }
907 }
Adam Powell89e06452010-06-23 20:24:52 -0700908}