blob: e6a539c652d03e6c80b1ff95f36ecd272b20c6fe [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 Powell01feaee2011-02-10 15:05:05 -080022import com.android.internal.widget.ActionBarContainer;
Adam Powell89e06452010-06-23 20:24:52 -070023import com.android.internal.widget.ActionBarContextView;
24import com.android.internal.widget.ActionBarView;
25
Adam Powelld8b3f2e2010-12-02 13:37:03 -080026import android.animation.Animator;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080027import android.animation.Animator.AnimatorListener;
Adam Powell07e1f982011-03-24 11:11:15 -070028import android.animation.AnimatorListenerAdapter;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080029import android.animation.AnimatorSet;
Adam Powelle6ec7322010-12-07 15:29:26 -080030import android.animation.ObjectAnimator;
Adam Powell45f1e082010-12-10 14:20:13 -080031import android.animation.TimeInterpolator;
Adam Powell89e06452010-06-23 20:24:52 -070032import android.app.ActionBar;
Adam Powell661c9082010-07-02 10:09:44 -070033import android.app.Activity;
Adam Powelldec9dfd2010-08-09 15:27:54 -070034import android.app.Dialog;
Adam Powell661c9082010-07-02 10:09:44 -070035import android.app.FragmentTransaction;
Adam Powelldec9dfd2010-08-09 15:27:54 -070036import android.content.Context;
Adam Powell89e06452010-06-23 20:24:52 -070037import android.graphics.drawable.Drawable;
Adam Powell0e94b512010-06-29 17:58:20 -070038import android.os.Handler;
Adam Powell6e346362010-07-23 10:18:23 -070039import android.view.ActionMode;
Adam Powell32555f32010-11-17 13:49:22 -080040import android.view.LayoutInflater;
Adam Powell89e06452010-06-23 20:24:52 -070041import android.view.Menu;
Adam Powell9168f0b2010-08-02 15:46:24 -070042import android.view.MenuInflater;
Adam Powell89e06452010-06-23 20:24:52 -070043import android.view.MenuItem;
44import android.view.View;
Adam Powelle6ec7322010-12-07 15:29:26 -080045import android.view.Window;
Adam Powell45f1e082010-12-10 14:20:13 -080046import android.view.animation.DecelerateInterpolator;
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 Powell01feaee2011-02-10 15:05:05 -080068 private ActionBarContainer 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 Powell07e1f982011-03-24 11:11:15 -070094 private Animator mCurrentShowAnim;
95 private Animator mCurrentModeAnim;
Adam Powell50efbed2011-02-08 16:20:15 -080096 private boolean mShowHideAnimationEnabled;
Adam Powell07e1f982011-03-24 11:11:15 -070097 boolean mWasHiddenBeforeMode;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080098
Adam Powell45f1e082010-12-10 14:20:13 -080099 private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator();
100
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800101 final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
Adam Powell07e1f982011-03-24 11:11:15 -0700102 new AnimatorListenerAdapter() { // NORMAL_VIEW
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800103 @Override
104 public void onAnimationEnd(Animator animation) {
105 if (mLowerContextView != null) {
106 mLowerContextView.removeAllViews();
107 }
Adam Powell07e1f982011-03-24 11:11:15 -0700108 mCurrentModeAnim = null;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800109 hideAllExcept(NORMAL_VIEW);
110 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800111 },
Adam Powell07e1f982011-03-24 11:11:15 -0700112 new AnimatorListenerAdapter() { // CONTEXT_VIEW
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800113 @Override
114 public void onAnimationEnd(Animator animation) {
Adam Powell07e1f982011-03-24 11:11:15 -0700115 mCurrentModeAnim = null;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800116 hideAllExcept(CONTEXT_VIEW);
117 }
Adam Powell0e94b512010-06-29 17:58:20 -0700118 }
Adam Powell0e94b512010-06-29 17:58:20 -0700119 };
120
Adam Powell07e1f982011-03-24 11:11:15 -0700121 final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
Adam Powelle6ec7322010-12-07 15:29:26 -0800122 @Override
123 public void onAnimationEnd(Animator animation) {
124 if (mContentView != null) {
125 mContentView.setTranslationY(0);
126 }
127 mContainerView.setVisibility(View.GONE);
Adam Powell01feaee2011-02-10 15:05:05 -0800128 mContainerView.setTransitioning(false);
Adam Powell07e1f982011-03-24 11:11:15 -0700129 mCurrentShowAnim = null;
Adam Powelle6ec7322010-12-07 15:29:26 -0800130 }
131 };
132
Adam Powell07e1f982011-03-24 11:11:15 -0700133 final AnimatorListener mShowListener = new AnimatorListenerAdapter() {
Adam Powelle6ec7322010-12-07 15:29:26 -0800134 @Override
135 public void onAnimationEnd(Animator animation) {
Adam Powell07e1f982011-03-24 11:11:15 -0700136 mCurrentShowAnim = null;
Adam Powell45f1e082010-12-10 14:20:13 -0800137 mContainerView.requestLayout();
Adam Powelle6ec7322010-12-07 15:29:26 -0800138 }
Adam Powelle6ec7322010-12-07 15:29:26 -0800139 };
140
Adam Powell661c9082010-07-02 10:09:44 -0700141 public ActionBarImpl(Activity activity) {
Adam Powell661c9082010-07-02 10:09:44 -0700142 mActivity = activity;
Adam Powelle6ec7322010-12-07 15:29:26 -0800143 Window window = activity.getWindow();
144 View decor = window.getDecorView();
145 init(decor);
146 if (!mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) {
147 mContentView = decor.findViewById(android.R.id.content);
148 }
Adam Powelldec9dfd2010-08-09 15:27:54 -0700149 }
150
151 public ActionBarImpl(Dialog dialog) {
152 mDialog = dialog;
153 init(dialog.getWindow().getDecorView());
154 }
155
156 private void init(View decor) {
157 mContext = decor.getContext();
Adam Powell89e06452010-06-23 20:24:52 -0700158 mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
159 mUpperContextView = (ActionBarContextView) decor.findViewById(
160 com.android.internal.R.id.action_context_bar);
161 mLowerContextView = (LinearLayout) decor.findViewById(
162 com.android.internal.R.id.lower_action_context_bar);
Adam Powell01feaee2011-02-10 15:05:05 -0800163 mContainerView = (ActionBarContainer) decor.findViewById(
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800164 com.android.internal.R.id.action_bar_container);
Steve Block08f194b2010-08-24 18:20:48 +0100165
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800166 if (mActionView == null || mUpperContextView == null || mContainerView == null) {
Adam Powell89e06452010-06-23 20:24:52 -0700167 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
168 "with a compatible window decor layout");
169 }
Adam Powell0e94b512010-06-29 17:58:20 -0700170
Steve Block08f194b2010-08-24 18:20:48 +0100171 mActionView.setContextView(mUpperContextView);
Adam Powell89e06452010-06-23 20:24:52 -0700172 mContextDisplayMode = mLowerContextView == null ?
173 CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT;
174 }
175
Adam Powell50efbed2011-02-08 16:20:15 -0800176 /**
177 * Enables or disables animation between show/hide states.
178 * If animation is disabled using this method, animations in progress
179 * will be finished.
180 *
181 * @param enabled true to animate, false to not animate.
182 */
183 public void setShowHideAnimationEnabled(boolean enabled) {
184 mShowHideAnimationEnabled = enabled;
Adam Powell07e1f982011-03-24 11:11:15 -0700185 if (!enabled && mCurrentShowAnim != null) {
186 mCurrentShowAnim.end();
Adam Powell50efbed2011-02-08 16:20:15 -0800187 }
188 }
189
Adam Powell8515ee82010-11-30 14:09:55 -0800190 public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
191 mMenuVisibilityListeners.add(listener);
192 }
193
194 public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
195 mMenuVisibilityListeners.remove(listener);
196 }
197
198 public void dispatchMenuVisibilityChanged(boolean isVisible) {
199 if (isVisible == mLastMenuVisibility) {
200 return;
201 }
202 mLastMenuVisibility = isVisible;
203
204 final int count = mMenuVisibilityListeners.size();
205 for (int i = 0; i < count; i++) {
206 mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
207 }
208 }
209
Adam Powella66c7b02010-07-28 15:28:25 -0700210 @Override
Adam Powell3f476b32011-01-03 19:25:36 -0800211 public void setCustomView(int resId) {
212 setCustomView(LayoutInflater.from(mContext).inflate(resId, mActionView, false));
213 }
214
215 @Override
216 public void setDisplayUseLogoEnabled(boolean useLogo) {
217 setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
218 }
219
220 @Override
221 public void setDisplayShowHomeEnabled(boolean showHome) {
222 setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
223 }
224
225 @Override
226 public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
227 setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
228 }
229
230 @Override
231 public void setDisplayShowTitleEnabled(boolean showTitle) {
232 setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
233 }
234
235 @Override
236 public void setDisplayShowCustomEnabled(boolean showCustom) {
237 setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
238 }
239
240 @Override
Adam Powella66c7b02010-07-28 15:28:25 -0700241 public void setTitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700242 setTitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700243 }
244
245 @Override
246 public void setSubtitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700247 setSubtitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700248 }
249
Adam Powell17809772010-07-21 13:25:11 -0700250 public void setSelectedNavigationItem(int position) {
251 switch (mActionView.getNavigationMode()) {
252 case NAVIGATION_MODE_TABS:
253 selectTab(mTabs.get(position));
254 break;
Adam Powell9ab97872010-10-26 21:47:29 -0700255 case NAVIGATION_MODE_LIST:
Adam Powell17809772010-07-21 13:25:11 -0700256 mActionView.setDropdownSelectedPosition(position);
257 break;
258 default:
259 throw new IllegalStateException(
Adam Powell9ab97872010-10-26 21:47:29 -0700260 "setSelectedNavigationIndex not valid for current navigation mode");
Adam Powell17809772010-07-21 13:25:11 -0700261 }
262 }
263
Adam Powell9ab97872010-10-26 21:47:29 -0700264 public void removeAllTabs() {
265 cleanupTabs();
Adam Powell17809772010-07-21 13:25:11 -0700266 }
267
Adam Powell661c9082010-07-02 10:09:44 -0700268 private void cleanupTabs() {
269 if (mSelectedTab != null) {
270 selectTab(null);
271 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700272 mTabs.clear();
Adam Powell0c24a552010-11-03 16:44:11 -0700273 mActionView.removeAllTabs();
274 mSavedTabPosition = INVALID_POSITION;
Adam Powell661c9082010-07-02 10:09:44 -0700275 }
276
Adam Powell0e94b512010-06-29 17:58:20 -0700277 public void setTitle(CharSequence title) {
278 mActionView.setTitle(title);
279 }
280
281 public void setSubtitle(CharSequence subtitle) {
282 mActionView.setSubtitle(subtitle);
283 }
284
Adam Powell89e06452010-06-23 20:24:52 -0700285 public void setDisplayOptions(int options) {
286 mActionView.setDisplayOptions(options);
287 }
Adam Powell0e94b512010-06-29 17:58:20 -0700288
Adam Powell89e06452010-06-23 20:24:52 -0700289 public void setDisplayOptions(int options, int mask) {
290 final int current = mActionView.getDisplayOptions();
291 mActionView.setDisplayOptions((options & mask) | (current & ~mask));
292 }
293
294 public void setBackgroundDrawable(Drawable d) {
Adam Powelle8c1e5c2010-12-13 10:49:32 -0800295 mContainerView.setBackgroundDrawable(d);
Adam Powell89e06452010-06-23 20:24:52 -0700296 }
297
Adam Powellef704442010-11-16 14:48:22 -0800298 public View getCustomView() {
Adam Powell89e06452010-06-23 20:24:52 -0700299 return mActionView.getCustomNavigationView();
300 }
301
302 public CharSequence getTitle() {
303 return mActionView.getTitle();
304 }
305
306 public CharSequence getSubtitle() {
307 return mActionView.getSubtitle();
308 }
309
310 public int getNavigationMode() {
311 return mActionView.getNavigationMode();
312 }
313
314 public int getDisplayOptions() {
315 return mActionView.getDisplayOptions();
316 }
317
Adam Powell5d279772010-07-27 16:34:07 -0700318 public ActionMode startActionMode(ActionMode.Callback callback) {
319 if (mActionMode != null) {
320 mActionMode.finish();
Adam Powell6e346362010-07-23 10:18:23 -0700321 }
Adam Powell3461b322010-07-14 11:34:43 -0700322
Adam Powella1e63582011-01-18 16:51:22 -0800323 mUpperContextView.killMode();
Adam Powell5d279772010-07-27 16:34:07 -0700324 ActionMode mode = new ActionModeImpl(callback);
Adam Powell6e346362010-07-23 10:18:23 -0700325 if (callback.onCreateActionMode(mode, mode.getMenu())) {
Adam Powell07e1f982011-03-24 11:11:15 -0700326 mWasHiddenBeforeMode = !isShowing();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700327 mode.invalidate();
328 mUpperContextView.initForMode(mode);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800329 animateTo(CONTEXT_VIEW);
Adam Powell89e06452010-06-23 20:24:52 -0700330 if (mLowerContextView != null) {
331 // TODO animate this
332 mLowerContextView.setVisibility(View.VISIBLE);
333 }
Adam Powell5d279772010-07-27 16:34:07 -0700334 mActionMode = mode;
Adam Powellac695c62010-07-20 18:19:27 -0700335 return mode;
Adam Powell89e06452010-06-23 20:24:52 -0700336 }
Adam Powellac695c62010-07-20 18:19:27 -0700337 return null;
Adam Powell89e06452010-06-23 20:24:52 -0700338 }
339
Adam Powell661c9082010-07-02 10:09:44 -0700340 private void configureTab(Tab tab, int position) {
341 final TabImpl tabi = (TabImpl) tab;
Adam Powell2b6230e2010-09-07 17:55:25 -0700342 final ActionBar.TabListener callback = tabi.getCallback();
343
344 if (callback == null) {
345 throw new IllegalStateException("Action Bar Tab must have a Callback");
346 }
Adam Powell661c9082010-07-02 10:09:44 -0700347
348 tabi.setPosition(position);
349 mTabs.add(position, tabi);
350
Adam Powell81b89442010-11-02 17:58:56 -0700351 final int count = mTabs.size();
352 for (int i = position + 1; i < count; i++) {
353 mTabs.get(i).setPosition(i);
Adam Powell661c9082010-07-02 10:09:44 -0700354 }
Adam Powell661c9082010-07-02 10:09:44 -0700355 }
356
357 @Override
358 public void addTab(Tab tab) {
Adam Powell81b89442010-11-02 17:58:56 -0700359 addTab(tab, mTabs.isEmpty());
Adam Powell661c9082010-07-02 10:09:44 -0700360 }
361
362 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700363 public void addTab(Tab tab, int position) {
Adam Powell81b89442010-11-02 17:58:56 -0700364 addTab(tab, position, mTabs.isEmpty());
365 }
366
367 @Override
368 public void addTab(Tab tab, boolean setSelected) {
369 mActionView.addTab(tab, setSelected);
370 configureTab(tab, mTabs.size());
371 if (setSelected) {
372 selectTab(tab);
373 }
374 }
375
376 @Override
377 public void addTab(Tab tab, int position, boolean setSelected) {
378 mActionView.addTab(tab, position, setSelected);
Adam Powell661c9082010-07-02 10:09:44 -0700379 configureTab(tab, position);
Adam Powell81b89442010-11-02 17:58:56 -0700380 if (setSelected) {
381 selectTab(tab);
382 }
Adam Powell661c9082010-07-02 10:09:44 -0700383 }
384
385 @Override
386 public Tab newTab() {
387 return new TabImpl();
388 }
389
390 @Override
391 public void removeTab(Tab tab) {
392 removeTabAt(tab.getPosition());
393 }
394
395 @Override
396 public void removeTabAt(int position) {
Adam Powell0c24a552010-11-03 16:44:11 -0700397 int selectedTabPosition = mSelectedTab != null
398 ? mSelectedTab.getPosition() : mSavedTabPosition;
Adam Powell661c9082010-07-02 10:09:44 -0700399 mActionView.removeTabAt(position);
400 mTabs.remove(position);
401
402 final int newTabCount = mTabs.size();
403 for (int i = position; i < newTabCount; i++) {
404 mTabs.get(i).setPosition(i);
405 }
406
Adam Powell0c24a552010-11-03 16:44:11 -0700407 if (selectedTabPosition == position) {
408 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
409 }
Adam Powell661c9082010-07-02 10:09:44 -0700410 }
411
412 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700413 public void selectTab(Tab tab) {
Adam Powell0c24a552010-11-03 16:44:11 -0700414 if (getNavigationMode() != NAVIGATION_MODE_TABS) {
415 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
416 return;
417 }
418
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800419 final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction()
Adam Powell0c24a552010-11-03 16:44:11 -0700420 .disallowAddToBackStack();
Adam Powell7f9b9052010-10-19 16:56:07 -0700421
422 if (mSelectedTab == tab) {
423 if (mSelectedTab != null) {
424 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
425 }
426 } else {
427 mActionView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
428 if (mSelectedTab != null) {
429 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
430 }
431 mSelectedTab = (TabImpl) tab;
432 if (mSelectedTab != null) {
433 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
434 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700435 }
436
437 if (!trans.isEmpty()) {
438 trans.commit();
439 }
440 }
441
442 @Override
443 public Tab getSelectedTab() {
444 return mSelectedTab;
Adam Powell661c9082010-07-02 10:09:44 -0700445 }
446
Adam Powell6b336f82010-08-10 20:13:01 -0700447 @Override
448 public int getHeight() {
449 return mActionView.getHeight();
450 }
451
452 @Override
453 public void show() {
Adam Powell07e1f982011-03-24 11:11:15 -0700454 show(true);
455 }
456
457 void show(boolean markHiddenBeforeMode) {
458 if (mCurrentShowAnim != null) {
459 mCurrentShowAnim.end();
Adam Powell45f1e082010-12-10 14:20:13 -0800460 }
Adam Powelld76cee22011-01-31 15:05:05 -0800461 if (mContainerView.getVisibility() == View.VISIBLE) {
Adam Powell07e1f982011-03-24 11:11:15 -0700462 if (markHiddenBeforeMode) mWasHiddenBeforeMode = false;
Adam Powelld76cee22011-01-31 15:05:05 -0800463 return;
464 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800465 mContainerView.setVisibility(View.VISIBLE);
Adam Powell50efbed2011-02-08 16:20:15 -0800466
467 if (mShowHideAnimationEnabled) {
468 mContainerView.setAlpha(0);
469 AnimatorSet anim = new AnimatorSet();
470 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1));
471 if (mContentView != null) {
472 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
473 -mContainerView.getHeight(), 0));
474 mContainerView.setTranslationY(-mContainerView.getHeight());
475 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
476 }
477 anim.addListener(mShowListener);
Adam Powell07e1f982011-03-24 11:11:15 -0700478 mCurrentShowAnim = anim;
Adam Powell50efbed2011-02-08 16:20:15 -0800479 anim.start();
480 } else {
481 mShowListener.onAnimationEnd(null);
Adam Powelle6ec7322010-12-07 15:29:26 -0800482 }
Adam Powell6b336f82010-08-10 20:13:01 -0700483 }
484
485 @Override
486 public void hide() {
Adam Powell07e1f982011-03-24 11:11:15 -0700487 if (mCurrentShowAnim != null) {
488 mCurrentShowAnim.end();
Adam Powelle6ec7322010-12-07 15:29:26 -0800489 }
490 if (mContainerView.getVisibility() == View.GONE) {
491 return;
492 }
Adam Powell50efbed2011-02-08 16:20:15 -0800493
494 if (mShowHideAnimationEnabled) {
495 mContainerView.setAlpha(1);
Adam Powell01feaee2011-02-10 15:05:05 -0800496 mContainerView.setTransitioning(true);
Adam Powell50efbed2011-02-08 16:20:15 -0800497 AnimatorSet anim = new AnimatorSet();
498 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0));
499 if (mContentView != null) {
500 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
501 0, -mContainerView.getHeight()));
502 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
503 -mContainerView.getHeight()));
504 }
505 anim.addListener(mHideListener);
Adam Powell07e1f982011-03-24 11:11:15 -0700506 mCurrentShowAnim = anim;
Adam Powell50efbed2011-02-08 16:20:15 -0800507 anim.start();
508 } else {
509 mHideListener.onAnimationEnd(null);
Adam Powelle6ec7322010-12-07 15:29:26 -0800510 }
Adam Powell6b336f82010-08-10 20:13:01 -0700511 }
512
513 public boolean isShowing() {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800514 return mContainerView.getVisibility() == View.VISIBLE;
515 }
516
Adam Powell07e1f982011-03-24 11:11:15 -0700517 long animateTo(int viewIndex) {
518 show(false);
519 if (mCurrentModeAnim != null) {
520 mCurrentModeAnim.end();
521 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800522
523 AnimatorSet set = new AnimatorSet();
524
525 final View targetChild = mContainerView.getChildAt(viewIndex);
526 targetChild.setVisibility(View.VISIBLE);
Adam Powell07e1f982011-03-24 11:11:15 -0700527 targetChild.setAlpha(0);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800528 AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800529
530 final int count = mContainerView.getChildCount();
531 for (int i = 0; i < count; i++) {
532 final View child = mContainerView.getChildAt(i);
533 if (i == viewIndex) {
534 continue;
535 }
536
537 if (child.getVisibility() != View.GONE) {
Adam Powell45f1e082010-12-10 14:20:13 -0800538 Animator a = ObjectAnimator.ofFloat(child, "alpha", 0);
539 a.setInterpolator(sFadeOutInterpolator);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800540 b.with(a);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800541 }
542 }
543
544 set.addListener(mAfterAnimation[viewIndex]);
545
Adam Powell07e1f982011-03-24 11:11:15 -0700546 mCurrentModeAnim = set;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800547 set.start();
548 return set.getDuration();
549 }
550
551 private void hideAllExcept(int viewIndex) {
552 final int count = mContainerView.getChildCount();
553 for (int i = 0; i < count; i++) {
554 mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE);
555 }
Adam Powell6b336f82010-08-10 20:13:01 -0700556 }
557
Adam Powell89e06452010-06-23 20:24:52 -0700558 /**
559 * @hide
560 */
Adam Powell5d279772010-07-27 16:34:07 -0700561 public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
Adam Powell6e346362010-07-23 10:18:23 -0700562 private ActionMode.Callback mCallback;
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700563 private MenuBuilder mMenu;
Adam Powell29ed7572010-07-14 16:24:56 -0700564 private WeakReference<View> mCustomView;
Adam Powell89e06452010-06-23 20:24:52 -0700565
Adam Powell5d279772010-07-27 16:34:07 -0700566 public ActionModeImpl(ActionMode.Callback callback) {
Adam Powell89e06452010-06-23 20:24:52 -0700567 mCallback = callback;
Adam Powell4d9861e2010-08-17 11:14:40 -0700568 mMenu = new MenuBuilder(mActionView.getContext())
569 .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700570 mMenu.setCallback(this);
Adam Powell89e06452010-06-23 20:24:52 -0700571 }
Adam Powell9168f0b2010-08-02 15:46:24 -0700572
573 @Override
574 public MenuInflater getMenuInflater() {
Adam Powell4d9861e2010-08-17 11:14:40 -0700575 return new MenuInflater(mContext);
Adam Powell9168f0b2010-08-02 15:46:24 -0700576 }
577
Adam Powell89e06452010-06-23 20:24:52 -0700578 @Override
579 public Menu getMenu() {
580 return mMenu;
581 }
582
583 @Override
584 public void finish() {
Adam Powell5d279772010-07-27 16:34:07 -0700585 if (mActionMode != this) {
586 // Not the active action mode - no-op
Adam Powell93b6bc32010-07-22 11:36:35 -0700587 return;
588 }
589
Adam Powell6e346362010-07-23 10:18:23 -0700590 mCallback.onDestroyActionMode(this);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800591 mCallback = null;
592 animateTo(NORMAL_VIEW);
Adam Powell0e94b512010-06-29 17:58:20 -0700593
594 // Clear out the context mode views after the animation finishes
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800595 mUpperContextView.closeMode();
Adam Powell89e06452010-06-23 20:24:52 -0700596 if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) {
597 // TODO Animate this
598 mLowerContextView.setVisibility(View.GONE);
599 }
Adam Powell5d279772010-07-27 16:34:07 -0700600 mActionMode = null;
Adam Powell07e1f982011-03-24 11:11:15 -0700601
602 if (mWasHiddenBeforeMode) {
603 hide();
604 }
Adam Powell89e06452010-06-23 20:24:52 -0700605 }
606
607 @Override
608 public void invalidate() {
Adam Powell6e346362010-07-23 10:18:23 -0700609 if (mCallback.onPrepareActionMode(this, mMenu)) {
Adam Powell89e06452010-06-23 20:24:52 -0700610 // Refresh content in both context views
611 }
612 }
613
614 @Override
615 public void setCustomView(View view) {
616 mUpperContextView.setCustomView(view);
Adam Powell29ed7572010-07-14 16:24:56 -0700617 mCustomView = new WeakReference<View>(view);
Adam Powell89e06452010-06-23 20:24:52 -0700618 }
619
620 @Override
621 public void setSubtitle(CharSequence subtitle) {
622 mUpperContextView.setSubtitle(subtitle);
623 }
624
625 @Override
626 public void setTitle(CharSequence title) {
627 mUpperContextView.setTitle(title);
628 }
Adam Powell29ed7572010-07-14 16:24:56 -0700629
630 @Override
Adam Powellc9ae2a22010-07-28 14:44:21 -0700631 public void setTitle(int resId) {
Adam Powell48e8ac32011-01-14 12:10:24 -0800632 setTitle(mContext.getResources().getString(resId));
Adam Powellc9ae2a22010-07-28 14:44:21 -0700633 }
634
635 @Override
636 public void setSubtitle(int resId) {
Adam Powell48e8ac32011-01-14 12:10:24 -0800637 setSubtitle(mContext.getResources().getString(resId));
Adam Powellc9ae2a22010-07-28 14:44:21 -0700638 }
639
640 @Override
Adam Powell29ed7572010-07-14 16:24:56 -0700641 public CharSequence getTitle() {
642 return mUpperContextView.getTitle();
643 }
644
645 @Override
646 public CharSequence getSubtitle() {
647 return mUpperContextView.getSubtitle();
648 }
Adam Powell89e06452010-06-23 20:24:52 -0700649
Adam Powell29ed7572010-07-14 16:24:56 -0700650 @Override
651 public View getCustomView() {
652 return mCustomView != null ? mCustomView.get() : null;
653 }
654
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700655 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800656 if (mCallback != null) {
657 return mCallback.onActionItemClicked(this, item);
658 } else {
659 return false;
660 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700661 }
662
663 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
664 }
665
666 public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800667 if (mCallback == null) {
668 return false;
669 }
670
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700671 if (!subMenu.hasVisibleItems()) {
672 return true;
Adam Powell89e06452010-06-23 20:24:52 -0700673 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700674
Adam Powelldec9dfd2010-08-09 15:27:54 -0700675 new MenuPopupHelper(mContext, subMenu).show();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700676 return true;
677 }
678
679 public void onCloseSubMenu(SubMenuBuilder menu) {
680 }
681
682 public void onMenuModeChange(MenuBuilder menu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800683 if (mCallback == null) {
684 return;
685 }
Adam Powellf6148c52010-08-11 21:10:16 -0700686 invalidate();
Adam Powell8515ee82010-11-30 14:09:55 -0800687 mUpperContextView.openOverflowMenu();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700688 }
Adam Powell661c9082010-07-02 10:09:44 -0700689 }
690
691 /**
692 * @hide
693 */
694 public class TabImpl extends ActionBar.Tab {
Adam Powell2b6230e2010-09-07 17:55:25 -0700695 private ActionBar.TabListener mCallback;
696 private Object mTag;
Adam Powell661c9082010-07-02 10:09:44 -0700697 private Drawable mIcon;
698 private CharSequence mText;
699 private int mPosition;
Adam Powell2b6230e2010-09-07 17:55:25 -0700700 private View mCustomView;
Adam Powell661c9082010-07-02 10:09:44 -0700701
702 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700703 public Object getTag() {
704 return mTag;
705 }
706
707 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700708 public Tab setTag(Object tag) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700709 mTag = tag;
Adam Powell9ab97872010-10-26 21:47:29 -0700710 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700711 }
712
713 public ActionBar.TabListener getCallback() {
714 return mCallback;
715 }
716
717 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700718 public Tab setTabListener(ActionBar.TabListener callback) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700719 mCallback = callback;
Adam Powell9ab97872010-10-26 21:47:29 -0700720 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700721 }
722
723 @Override
724 public View getCustomView() {
725 return mCustomView;
726 }
727
728 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700729 public Tab setCustomView(View view) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700730 mCustomView = view;
Adam Powell9ab97872010-10-26 21:47:29 -0700731 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700732 }
733
734 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800735 public Tab setCustomView(int layoutResId) {
736 return setCustomView(LayoutInflater.from(mContext).inflate(layoutResId, null));
737 }
738
739 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700740 public Drawable getIcon() {
741 return mIcon;
742 }
743
744 @Override
745 public int getPosition() {
746 return mPosition;
747 }
748
749 public void setPosition(int position) {
750 mPosition = position;
751 }
752
753 @Override
754 public CharSequence getText() {
755 return mText;
756 }
757
758 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700759 public Tab setIcon(Drawable icon) {
Adam Powell661c9082010-07-02 10:09:44 -0700760 mIcon = icon;
Adam Powell9ab97872010-10-26 21:47:29 -0700761 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700762 }
763
764 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800765 public Tab setIcon(int resId) {
766 return setIcon(mContext.getResources().getDrawable(resId));
767 }
768
769 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700770 public Tab setText(CharSequence text) {
Adam Powell661c9082010-07-02 10:09:44 -0700771 mText = text;
Adam Powell9ab97872010-10-26 21:47:29 -0700772 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700773 }
774
775 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800776 public Tab setText(int resId) {
777 return setText(mContext.getResources().getText(resId));
778 }
779
780 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700781 public void select() {
782 selectTab(this);
Adam Powell89e06452010-06-23 20:24:52 -0700783 }
784 }
Adam Powell9ab97872010-10-26 21:47:29 -0700785
786 @Override
787 public void setCustomView(View view) {
788 mActionView.setCustomNavigationView(view);
789 }
790
791 @Override
792 public void setCustomView(View view, LayoutParams layoutParams) {
793 view.setLayoutParams(layoutParams);
794 mActionView.setCustomNavigationView(view);
795 }
796
797 @Override
Adam Powell8515ee82010-11-30 14:09:55 -0800798 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
Adam Powell9ab97872010-10-26 21:47:29 -0700799 mActionView.setDropdownAdapter(adapter);
800 mActionView.setCallback(callback);
801 }
802
803 @Override
804 public int getSelectedNavigationIndex() {
805 switch (mActionView.getNavigationMode()) {
806 case NAVIGATION_MODE_TABS:
Adam Powell04587962010-11-11 22:15:07 -0800807 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
Adam Powell9ab97872010-10-26 21:47:29 -0700808 case NAVIGATION_MODE_LIST:
809 return mActionView.getDropdownSelectedPosition();
810 default:
811 return -1;
812 }
813 }
814
815 @Override
816 public int getNavigationItemCount() {
817 switch (mActionView.getNavigationMode()) {
818 case NAVIGATION_MODE_TABS:
819 return mTabs.size();
820 case NAVIGATION_MODE_LIST:
821 SpinnerAdapter adapter = mActionView.getDropdownAdapter();
822 return adapter != null ? adapter.getCount() : 0;
823 default:
824 return 0;
825 }
826 }
827
828 @Override
Adam Powell0c24a552010-11-03 16:44:11 -0700829 public int getTabCount() {
830 return mTabs.size();
831 }
832
833 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700834 public void setNavigationMode(int mode) {
Adam Powell0c24a552010-11-03 16:44:11 -0700835 final int oldMode = mActionView.getNavigationMode();
836 switch (oldMode) {
837 case NAVIGATION_MODE_TABS:
838 mSavedTabPosition = getSelectedNavigationIndex();
839 selectTab(null);
840 break;
841 }
Adam Powell9ab97872010-10-26 21:47:29 -0700842 mActionView.setNavigationMode(mode);
Adam Powell0c24a552010-11-03 16:44:11 -0700843 switch (mode) {
844 case NAVIGATION_MODE_TABS:
845 if (mSavedTabPosition != INVALID_POSITION) {
846 setSelectedNavigationItem(mSavedTabPosition);
847 mSavedTabPosition = INVALID_POSITION;
848 }
849 break;
850 }
Adam Powell9ab97872010-10-26 21:47:29 -0700851 }
852
853 @Override
854 public Tab getTabAt(int index) {
855 return mTabs.get(index);
856 }
Adam Powell0c24a552010-11-03 16:44:11 -0700857
Adam Powell0c24a552010-11-03 16:44:11 -0700858
Adam Powell1969b872011-03-22 11:52:48 -0700859 @Override
860 public void setIcon(int resId) {
861 mActionView.setIcon(mContext.getResources().getDrawable(resId));
862 }
Adam Powell0c24a552010-11-03 16:44:11 -0700863
Adam Powell1969b872011-03-22 11:52:48 -0700864 @Override
865 public void setIcon(Drawable icon) {
866 mActionView.setIcon(icon);
867 }
868
869 @Override
870 public void setLogo(int resId) {
871 mActionView.setLogo(mContext.getResources().getDrawable(resId));
872 }
873
874 @Override
875 public void setLogo(Drawable logo) {
876 mActionView.setLogo(logo);
Adam Powell0c24a552010-11-03 16:44:11 -0700877 }
Adam Powell89e06452010-06-23 20:24:52 -0700878}