blob: 1e576ceb044fe00c9857b7699def974a09ad6bb7 [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 Powell640a66e2011-04-29 10:18:53 -070022import com.android.internal.widget.AbsActionBarView;
Adam Powell01feaee2011-02-10 15:05:05 -080023import com.android.internal.widget.ActionBarContainer;
Adam Powell89e06452010-06-23 20:24:52 -070024import com.android.internal.widget.ActionBarContextView;
25import com.android.internal.widget.ActionBarView;
26
Adam Powelld8b3f2e2010-12-02 13:37:03 -080027import android.animation.Animator;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080028import android.animation.Animator.AnimatorListener;
Adam Powell07e1f982011-03-24 11:11:15 -070029import android.animation.AnimatorListenerAdapter;
Adam Powelld8b3f2e2010-12-02 13:37:03 -080030import android.animation.AnimatorSet;
Adam Powelle6ec7322010-12-07 15:29:26 -080031import android.animation.ObjectAnimator;
Adam Powell45f1e082010-12-10 14:20:13 -080032import android.animation.TimeInterpolator;
Adam Powell89e06452010-06-23 20:24:52 -070033import android.app.ActionBar;
Adam Powell661c9082010-07-02 10:09:44 -070034import android.app.Activity;
Adam Powelldec9dfd2010-08-09 15:27:54 -070035import android.app.Dialog;
Adam Powell661c9082010-07-02 10:09:44 -070036import android.app.FragmentTransaction;
Adam Powelldec9dfd2010-08-09 15:27:54 -070037import android.content.Context;
Adam Powell89e06452010-06-23 20:24:52 -070038import android.graphics.drawable.Drawable;
Adam Powell0e94b512010-06-29 17:58:20 -070039import android.os.Handler;
Adam Powell6e346362010-07-23 10:18:23 -070040import android.view.ActionMode;
Adam Powell32555f32010-11-17 13:49:22 -080041import android.view.LayoutInflater;
Adam Powell89e06452010-06-23 20:24:52 -070042import android.view.Menu;
Adam Powell9168f0b2010-08-02 15:46:24 -070043import android.view.MenuInflater;
Adam Powell89e06452010-06-23 20:24:52 -070044import android.view.MenuItem;
45import android.view.View;
Adam Powelldae78242011-04-25 15:23:41 -070046import android.view.ViewGroup;
Adam Powelle6ec7322010-12-07 15:29:26 -080047import android.view.Window;
Adam Powell45f1e082010-12-10 14:20:13 -080048import android.view.animation.DecelerateInterpolator;
Adam Powelldae78242011-04-25 15:23:41 -070049import android.widget.HorizontalScrollView;
Adam Powell89e06452010-06-23 20:24:52 -070050import android.widget.SpinnerAdapter;
Adam Powell89e06452010-06-23 20:24:52 -070051
Adam Powell29ed7572010-07-14 16:24:56 -070052import java.lang.ref.WeakReference;
Adam Powell661c9082010-07-02 10:09:44 -070053import java.util.ArrayList;
54
Adam Powell89e06452010-06-23 20:24:52 -070055/**
56 * ActionBarImpl is the ActionBar implementation used
57 * by devices of all screen sizes. If it detects a compatible decor,
58 * it will split contextual modes across both the ActionBarView at
59 * the top of the screen and a horizontal LinearLayout at the bottom
60 * which is normally hidden.
61 */
62public class ActionBarImpl extends ActionBar {
Adam Powelld8145042011-03-24 14:18:27 -070063 private static final String TAG = "ActionBarImpl";
Adam Powell661c9082010-07-02 10:09:44 -070064
Adam Powelldec9dfd2010-08-09 15:27:54 -070065 private Context mContext;
Adam Powell661c9082010-07-02 10:09:44 -070066 private Activity mActivity;
Adam Powelldec9dfd2010-08-09 15:27:54 -070067 private Dialog mDialog;
Adam Powell661c9082010-07-02 10:09:44 -070068
Adam Powell01feaee2011-02-10 15:05:05 -080069 private ActionBarContainer mContainerView;
Adam Powell89e06452010-06-23 20:24:52 -070070 private ActionBarView mActionView;
Adam Powell640a66e2011-04-29 10:18:53 -070071 private ActionBarContextView mContextView;
72 private ActionBarContainer mSplitView;
Adam Powelle6ec7322010-12-07 15:29:26 -080073 private View mContentView;
Adam Powelldae78242011-04-25 15:23:41 -070074 private ViewGroup mExternalTabView;
Adam Powell661c9082010-07-02 10:09:44 -070075
76 private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
77
Adam Powell661c9082010-07-02 10:09:44 -070078 private TabImpl mSelectedTab;
Adam Powell0c24a552010-11-03 16:44:11 -070079 private int mSavedTabPosition = INVALID_POSITION;
Adam Powell89e06452010-06-23 20:24:52 -070080
Adam Powell5d279772010-07-27 16:34:07 -070081 private ActionMode mActionMode;
Adam Powell89e06452010-06-23 20:24:52 -070082
Adam Powell8515ee82010-11-30 14:09:55 -080083 private boolean mLastMenuVisibility;
84 private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
85 new ArrayList<OnMenuVisibilityListener>();
86
Adam Powell89e06452010-06-23 20:24:52 -070087 private static final int CONTEXT_DISPLAY_NORMAL = 0;
88 private static final int CONTEXT_DISPLAY_SPLIT = 1;
89
Adam Powell0c24a552010-11-03 16:44:11 -070090 private static final int INVALID_POSITION = -1;
91
Adam Powell89e06452010-06-23 20:24:52 -070092 private int mContextDisplayMode;
Adam Powell0e94b512010-06-29 17:58:20 -070093
94 final Handler mHandler = new Handler();
Adam Powelld8b3f2e2010-12-02 13:37:03 -080095
Adam Powell07e1f982011-03-24 11:11:15 -070096 private Animator mCurrentShowAnim;
97 private Animator mCurrentModeAnim;
Adam Powell50efbed2011-02-08 16:20:15 -080098 private boolean mShowHideAnimationEnabled;
Adam Powell07e1f982011-03-24 11:11:15 -070099 boolean mWasHiddenBeforeMode;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800100
Adam Powell45f1e082010-12-10 14:20:13 -0800101 private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator();
102
Adam Powell07e1f982011-03-24 11:11:15 -0700103 final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
Adam Powelle6ec7322010-12-07 15:29:26 -0800104 @Override
105 public void onAnimationEnd(Animator animation) {
106 if (mContentView != null) {
107 mContentView.setTranslationY(0);
108 }
109 mContainerView.setVisibility(View.GONE);
Adam Powell01feaee2011-02-10 15:05:05 -0800110 mContainerView.setTransitioning(false);
Adam Powell07e1f982011-03-24 11:11:15 -0700111 mCurrentShowAnim = null;
Adam Powelle6ec7322010-12-07 15:29:26 -0800112 }
113 };
114
Adam Powell07e1f982011-03-24 11:11:15 -0700115 final AnimatorListener mShowListener = new AnimatorListenerAdapter() {
Adam Powelle6ec7322010-12-07 15:29:26 -0800116 @Override
117 public void onAnimationEnd(Animator animation) {
Adam Powell07e1f982011-03-24 11:11:15 -0700118 mCurrentShowAnim = null;
Adam Powell45f1e082010-12-10 14:20:13 -0800119 mContainerView.requestLayout();
Adam Powelle6ec7322010-12-07 15:29:26 -0800120 }
Adam Powelle6ec7322010-12-07 15:29:26 -0800121 };
122
Adam Powell661c9082010-07-02 10:09:44 -0700123 public ActionBarImpl(Activity activity) {
Adam Powell661c9082010-07-02 10:09:44 -0700124 mActivity = activity;
Adam Powelle6ec7322010-12-07 15:29:26 -0800125 Window window = activity.getWindow();
126 View decor = window.getDecorView();
127 init(decor);
128 if (!mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) {
129 mContentView = decor.findViewById(android.R.id.content);
130 }
Adam Powelldec9dfd2010-08-09 15:27:54 -0700131 }
132
133 public ActionBarImpl(Dialog dialog) {
134 mDialog = dialog;
135 init(dialog.getWindow().getDecorView());
136 }
137
138 private void init(View decor) {
139 mContext = decor.getContext();
Adam Powell89e06452010-06-23 20:24:52 -0700140 mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
Adam Powell640a66e2011-04-29 10:18:53 -0700141 mContextView = (ActionBarContextView) decor.findViewById(
Adam Powell89e06452010-06-23 20:24:52 -0700142 com.android.internal.R.id.action_context_bar);
Adam Powell01feaee2011-02-10 15:05:05 -0800143 mContainerView = (ActionBarContainer) decor.findViewById(
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800144 com.android.internal.R.id.action_bar_container);
Adam Powell640a66e2011-04-29 10:18:53 -0700145 mSplitView = (ActionBarContainer) decor.findViewById(
146 com.android.internal.R.id.split_action_bar);
Steve Block08f194b2010-08-24 18:20:48 +0100147
Adam Powell640a66e2011-04-29 10:18:53 -0700148 if (mActionView == null || mContextView == null || mContainerView == null) {
Adam Powell89e06452010-06-23 20:24:52 -0700149 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
150 "with a compatible window decor layout");
151 }
Adam Powell0e94b512010-06-29 17:58:20 -0700152
Adam Powell640a66e2011-04-29 10:18:53 -0700153 mActionView.setContextView(mContextView);
Adam Powell9b4bee02011-04-27 19:24:47 -0700154 mContextDisplayMode = mActionView.isSplitActionBar() ?
155 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
Adam Powelldae78242011-04-25 15:23:41 -0700156
157 if (!mActionView.hasEmbeddedTabs()) {
158 HorizontalScrollView tabScroller = new HorizontalScrollView(mContext);
159 ViewGroup tabContainer = mActionView.createTabContainer();
160 tabScroller.setHorizontalFadingEdgeEnabled(true);
161 tabScroller.addView(tabContainer);
162 tabScroller.setVisibility(getNavigationMode() == NAVIGATION_MODE_TABS ?
163 View.VISIBLE : View.GONE);
164 mActionView.setExternalTabLayout(tabContainer);
165 mContainerView.setTabContainer(tabScroller);
166 mExternalTabView = tabScroller;
167 }
Adam Powell89e06452010-06-23 20:24:52 -0700168 }
169
Adam Powell50efbed2011-02-08 16:20:15 -0800170 /**
171 * Enables or disables animation between show/hide states.
172 * If animation is disabled using this method, animations in progress
173 * will be finished.
174 *
175 * @param enabled true to animate, false to not animate.
176 */
177 public void setShowHideAnimationEnabled(boolean enabled) {
178 mShowHideAnimationEnabled = enabled;
Adam Powell07e1f982011-03-24 11:11:15 -0700179 if (!enabled && mCurrentShowAnim != null) {
180 mCurrentShowAnim.end();
Adam Powell50efbed2011-02-08 16:20:15 -0800181 }
182 }
183
Adam Powell8515ee82010-11-30 14:09:55 -0800184 public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
185 mMenuVisibilityListeners.add(listener);
186 }
187
188 public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
189 mMenuVisibilityListeners.remove(listener);
190 }
191
192 public void dispatchMenuVisibilityChanged(boolean isVisible) {
193 if (isVisible == mLastMenuVisibility) {
194 return;
195 }
196 mLastMenuVisibility = isVisible;
197
198 final int count = mMenuVisibilityListeners.size();
199 for (int i = 0; i < count; i++) {
200 mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
201 }
202 }
203
Adam Powella66c7b02010-07-28 15:28:25 -0700204 @Override
Adam Powell3f476b32011-01-03 19:25:36 -0800205 public void setCustomView(int resId) {
206 setCustomView(LayoutInflater.from(mContext).inflate(resId, mActionView, false));
207 }
208
209 @Override
210 public void setDisplayUseLogoEnabled(boolean useLogo) {
211 setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
212 }
213
214 @Override
215 public void setDisplayShowHomeEnabled(boolean showHome) {
216 setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
217 }
218
219 @Override
220 public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
221 setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
222 }
223
224 @Override
225 public void setDisplayShowTitleEnabled(boolean showTitle) {
226 setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
227 }
228
229 @Override
230 public void setDisplayShowCustomEnabled(boolean showCustom) {
231 setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
232 }
233
234 @Override
Adam Powelldae78242011-04-25 15:23:41 -0700235 public void setDisplayDisableHomeEnabled(boolean disableHome) {
236 setDisplayOptions(disableHome ? DISPLAY_DISABLE_HOME : 0, DISPLAY_DISABLE_HOME);
237 }
238
239 @Override
Adam Powella66c7b02010-07-28 15:28:25 -0700240 public void setTitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700241 setTitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700242 }
243
244 @Override
245 public void setSubtitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700246 setSubtitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700247 }
248
Adam Powell17809772010-07-21 13:25:11 -0700249 public void setSelectedNavigationItem(int position) {
250 switch (mActionView.getNavigationMode()) {
251 case NAVIGATION_MODE_TABS:
252 selectTab(mTabs.get(position));
253 break;
Adam Powell9ab97872010-10-26 21:47:29 -0700254 case NAVIGATION_MODE_LIST:
Adam Powell17809772010-07-21 13:25:11 -0700255 mActionView.setDropdownSelectedPosition(position);
256 break;
257 default:
258 throw new IllegalStateException(
Adam Powell9ab97872010-10-26 21:47:29 -0700259 "setSelectedNavigationIndex not valid for current navigation mode");
Adam Powell17809772010-07-21 13:25:11 -0700260 }
261 }
262
Adam Powell9ab97872010-10-26 21:47:29 -0700263 public void removeAllTabs() {
264 cleanupTabs();
Adam Powell17809772010-07-21 13:25:11 -0700265 }
266
Adam Powell661c9082010-07-02 10:09:44 -0700267 private void cleanupTabs() {
268 if (mSelectedTab != null) {
269 selectTab(null);
270 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700271 mTabs.clear();
Adam Powell0c24a552010-11-03 16:44:11 -0700272 mActionView.removeAllTabs();
273 mSavedTabPosition = INVALID_POSITION;
Adam Powell661c9082010-07-02 10:09:44 -0700274 }
275
Adam Powell0e94b512010-06-29 17:58:20 -0700276 public void setTitle(CharSequence title) {
277 mActionView.setTitle(title);
278 }
279
280 public void setSubtitle(CharSequence subtitle) {
281 mActionView.setSubtitle(subtitle);
282 }
283
Adam Powell89e06452010-06-23 20:24:52 -0700284 public void setDisplayOptions(int options) {
285 mActionView.setDisplayOptions(options);
286 }
Adam Powell0e94b512010-06-29 17:58:20 -0700287
Adam Powell89e06452010-06-23 20:24:52 -0700288 public void setDisplayOptions(int options, int mask) {
289 final int current = mActionView.getDisplayOptions();
290 mActionView.setDisplayOptions((options & mask) | (current & ~mask));
291 }
292
293 public void setBackgroundDrawable(Drawable d) {
Adam Powelle8c1e5c2010-12-13 10:49:32 -0800294 mContainerView.setBackgroundDrawable(d);
Adam Powell89e06452010-06-23 20:24:52 -0700295 }
296
Adam Powellef704442010-11-16 14:48:22 -0800297 public View getCustomView() {
Adam Powell89e06452010-06-23 20:24:52 -0700298 return mActionView.getCustomNavigationView();
299 }
300
301 public CharSequence getTitle() {
302 return mActionView.getTitle();
303 }
304
305 public CharSequence getSubtitle() {
306 return mActionView.getSubtitle();
307 }
308
309 public int getNavigationMode() {
310 return mActionView.getNavigationMode();
311 }
312
313 public int getDisplayOptions() {
314 return mActionView.getDisplayOptions();
315 }
316
Adam Powell5d279772010-07-27 16:34:07 -0700317 public ActionMode startActionMode(ActionMode.Callback callback) {
318 if (mActionMode != null) {
319 mActionMode.finish();
Adam Powell6e346362010-07-23 10:18:23 -0700320 }
Adam Powell3461b322010-07-14 11:34:43 -0700321
Adam Powell640a66e2011-04-29 10:18:53 -0700322 mContextView.killMode();
Adam Powell5d279772010-07-27 16:34:07 -0700323 ActionMode mode = new ActionModeImpl(callback);
Adam Powell6e346362010-07-23 10:18:23 -0700324 if (callback.onCreateActionMode(mode, mode.getMenu())) {
Adam Powell07e1f982011-03-24 11:11:15 -0700325 mWasHiddenBeforeMode = !isShowing();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700326 mode.invalidate();
Adam Powell640a66e2011-04-29 10:18:53 -0700327 mContextView.initForMode(mode);
328 animateToMode(true);
329 if (mSplitView != null) {
Adam Powell89e06452010-06-23 20:24:52 -0700330 // TODO animate this
Adam Powell640a66e2011-04-29 10:18:53 -0700331 mSplitView.setVisibility(View.VISIBLE);
Adam Powell89e06452010-06-23 20:24:52 -0700332 }
Adam Powell5d279772010-07-27 16:34:07 -0700333 mActionMode = mode;
Adam Powellac695c62010-07-20 18:19:27 -0700334 return mode;
Adam Powell89e06452010-06-23 20:24:52 -0700335 }
Adam Powellac695c62010-07-20 18:19:27 -0700336 return null;
Adam Powell89e06452010-06-23 20:24:52 -0700337 }
338
Adam Powell661c9082010-07-02 10:09:44 -0700339 private void configureTab(Tab tab, int position) {
340 final TabImpl tabi = (TabImpl) tab;
Adam Powell2b6230e2010-09-07 17:55:25 -0700341 final ActionBar.TabListener callback = tabi.getCallback();
342
343 if (callback == null) {
344 throw new IllegalStateException("Action Bar Tab must have a Callback");
345 }
Adam Powell661c9082010-07-02 10:09:44 -0700346
347 tabi.setPosition(position);
348 mTabs.add(position, tabi);
349
Adam Powell81b89442010-11-02 17:58:56 -0700350 final int count = mTabs.size();
351 for (int i = position + 1; i < count; i++) {
352 mTabs.get(i).setPosition(i);
Adam Powell661c9082010-07-02 10:09:44 -0700353 }
Adam Powell661c9082010-07-02 10:09:44 -0700354 }
355
356 @Override
357 public void addTab(Tab tab) {
Adam Powell81b89442010-11-02 17:58:56 -0700358 addTab(tab, mTabs.isEmpty());
Adam Powell661c9082010-07-02 10:09:44 -0700359 }
360
361 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700362 public void addTab(Tab tab, int position) {
Adam Powell81b89442010-11-02 17:58:56 -0700363 addTab(tab, position, mTabs.isEmpty());
364 }
365
366 @Override
367 public void addTab(Tab tab, boolean setSelected) {
368 mActionView.addTab(tab, setSelected);
369 configureTab(tab, mTabs.size());
370 if (setSelected) {
371 selectTab(tab);
372 }
373 }
374
375 @Override
376 public void addTab(Tab tab, int position, boolean setSelected) {
377 mActionView.addTab(tab, position, setSelected);
Adam Powell661c9082010-07-02 10:09:44 -0700378 configureTab(tab, position);
Adam Powell81b89442010-11-02 17:58:56 -0700379 if (setSelected) {
380 selectTab(tab);
381 }
Adam Powell661c9082010-07-02 10:09:44 -0700382 }
383
384 @Override
385 public Tab newTab() {
386 return new TabImpl();
387 }
388
389 @Override
390 public void removeTab(Tab tab) {
391 removeTabAt(tab.getPosition());
392 }
393
394 @Override
395 public void removeTabAt(int position) {
Adam Powell0c24a552010-11-03 16:44:11 -0700396 int selectedTabPosition = mSelectedTab != null
397 ? mSelectedTab.getPosition() : mSavedTabPosition;
Adam Powell661c9082010-07-02 10:09:44 -0700398 mActionView.removeTabAt(position);
Adam Powell0d8ec1d2011-05-03 14:49:13 -0700399 TabImpl removedTab = mTabs.remove(position);
400 if (removedTab != null) {
401 removedTab.setPosition(-1);
402 }
Adam Powell661c9082010-07-02 10:09:44 -0700403
404 final int newTabCount = mTabs.size();
405 for (int i = position; i < newTabCount; i++) {
406 mTabs.get(i).setPosition(i);
407 }
408
Adam Powell0c24a552010-11-03 16:44:11 -0700409 if (selectedTabPosition == position) {
410 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
411 }
Adam Powell661c9082010-07-02 10:09:44 -0700412 }
413
414 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700415 public void selectTab(Tab tab) {
Adam Powell0c24a552010-11-03 16:44:11 -0700416 if (getNavigationMode() != NAVIGATION_MODE_TABS) {
417 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
418 return;
419 }
420
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800421 final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction()
Adam Powell0c24a552010-11-03 16:44:11 -0700422 .disallowAddToBackStack();
Adam Powell7f9b9052010-10-19 16:56:07 -0700423
424 if (mSelectedTab == tab) {
425 if (mSelectedTab != null) {
426 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
427 }
428 } else {
429 mActionView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
430 if (mSelectedTab != null) {
431 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
432 }
433 mSelectedTab = (TabImpl) tab;
434 if (mSelectedTab != null) {
435 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
436 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700437 }
438
439 if (!trans.isEmpty()) {
440 trans.commit();
441 }
442 }
443
444 @Override
445 public Tab getSelectedTab() {
446 return mSelectedTab;
Adam Powell661c9082010-07-02 10:09:44 -0700447 }
448
Adam Powell6b336f82010-08-10 20:13:01 -0700449 @Override
450 public int getHeight() {
451 return mActionView.getHeight();
452 }
453
454 @Override
455 public void show() {
Adam Powell07e1f982011-03-24 11:11:15 -0700456 show(true);
457 }
458
459 void show(boolean markHiddenBeforeMode) {
460 if (mCurrentShowAnim != null) {
461 mCurrentShowAnim.end();
Adam Powell45f1e082010-12-10 14:20:13 -0800462 }
Adam Powelld76cee22011-01-31 15:05:05 -0800463 if (mContainerView.getVisibility() == View.VISIBLE) {
Adam Powell07e1f982011-03-24 11:11:15 -0700464 if (markHiddenBeforeMode) mWasHiddenBeforeMode = false;
Adam Powelld76cee22011-01-31 15:05:05 -0800465 return;
466 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800467 mContainerView.setVisibility(View.VISIBLE);
Adam Powell50efbed2011-02-08 16:20:15 -0800468
469 if (mShowHideAnimationEnabled) {
470 mContainerView.setAlpha(0);
471 AnimatorSet anim = new AnimatorSet();
472 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1));
473 if (mContentView != null) {
474 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
475 -mContainerView.getHeight(), 0));
476 mContainerView.setTranslationY(-mContainerView.getHeight());
477 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
478 }
Adam Powell640a66e2011-04-29 10:18:53 -0700479 if (mSplitView != null) {
480 mSplitView.setAlpha(0);
481 b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1));
482 }
Adam Powell50efbed2011-02-08 16:20:15 -0800483 anim.addListener(mShowListener);
Adam Powell07e1f982011-03-24 11:11:15 -0700484 mCurrentShowAnim = anim;
Adam Powell50efbed2011-02-08 16:20:15 -0800485 anim.start();
486 } else {
Adam Powelld8145042011-03-24 14:18:27 -0700487 mContainerView.setAlpha(1);
488 mContainerView.setTranslationY(0);
Adam Powell50efbed2011-02-08 16:20:15 -0800489 mShowListener.onAnimationEnd(null);
Adam Powelle6ec7322010-12-07 15:29:26 -0800490 }
Adam Powell6b336f82010-08-10 20:13:01 -0700491 }
492
493 @Override
494 public void hide() {
Adam Powell07e1f982011-03-24 11:11:15 -0700495 if (mCurrentShowAnim != null) {
496 mCurrentShowAnim.end();
Adam Powelle6ec7322010-12-07 15:29:26 -0800497 }
498 if (mContainerView.getVisibility() == View.GONE) {
499 return;
500 }
Adam Powell50efbed2011-02-08 16:20:15 -0800501
502 if (mShowHideAnimationEnabled) {
503 mContainerView.setAlpha(1);
Adam Powell01feaee2011-02-10 15:05:05 -0800504 mContainerView.setTransitioning(true);
Adam Powell50efbed2011-02-08 16:20:15 -0800505 AnimatorSet anim = new AnimatorSet();
506 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0));
507 if (mContentView != null) {
508 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
509 0, -mContainerView.getHeight()));
510 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
511 -mContainerView.getHeight()));
512 }
Adam Powell640a66e2011-04-29 10:18:53 -0700513 if (mSplitView != null) {
514 mSplitView.setAlpha(1);
515 b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0));
516 }
Adam Powell50efbed2011-02-08 16:20:15 -0800517 anim.addListener(mHideListener);
Adam Powell07e1f982011-03-24 11:11:15 -0700518 mCurrentShowAnim = anim;
Adam Powell50efbed2011-02-08 16:20:15 -0800519 anim.start();
520 } else {
521 mHideListener.onAnimationEnd(null);
Adam Powelle6ec7322010-12-07 15:29:26 -0800522 }
Adam Powell6b336f82010-08-10 20:13:01 -0700523 }
524
525 public boolean isShowing() {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800526 return mContainerView.getVisibility() == View.VISIBLE;
527 }
528
Adam Powell640a66e2011-04-29 10:18:53 -0700529 void animateToMode(boolean toActionMode) {
Adam Powell07e1f982011-03-24 11:11:15 -0700530 show(false);
531 if (mCurrentModeAnim != null) {
532 mCurrentModeAnim.end();
533 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800534
Adam Powell640a66e2011-04-29 10:18:53 -0700535 mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
536 mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
Adam Powell6b336f82010-08-10 20:13:01 -0700537 }
538
Adam Powell89e06452010-06-23 20:24:52 -0700539 /**
540 * @hide
541 */
Adam Powell5d279772010-07-27 16:34:07 -0700542 public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
Adam Powell6e346362010-07-23 10:18:23 -0700543 private ActionMode.Callback mCallback;
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700544 private MenuBuilder mMenu;
Adam Powell29ed7572010-07-14 16:24:56 -0700545 private WeakReference<View> mCustomView;
Adam Powell89e06452010-06-23 20:24:52 -0700546
Adam Powell5d279772010-07-27 16:34:07 -0700547 public ActionModeImpl(ActionMode.Callback callback) {
Adam Powell89e06452010-06-23 20:24:52 -0700548 mCallback = callback;
Adam Powell4d9861e2010-08-17 11:14:40 -0700549 mMenu = new MenuBuilder(mActionView.getContext())
550 .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700551 mMenu.setCallback(this);
Adam Powell89e06452010-06-23 20:24:52 -0700552 }
Adam Powell9168f0b2010-08-02 15:46:24 -0700553
554 @Override
555 public MenuInflater getMenuInflater() {
Adam Powell4d9861e2010-08-17 11:14:40 -0700556 return new MenuInflater(mContext);
Adam Powell9168f0b2010-08-02 15:46:24 -0700557 }
558
Adam Powell89e06452010-06-23 20:24:52 -0700559 @Override
560 public Menu getMenu() {
561 return mMenu;
562 }
563
564 @Override
565 public void finish() {
Adam Powell5d279772010-07-27 16:34:07 -0700566 if (mActionMode != this) {
567 // Not the active action mode - no-op
Adam Powell93b6bc32010-07-22 11:36:35 -0700568 return;
569 }
570
Adam Powell6e346362010-07-23 10:18:23 -0700571 mCallback.onDestroyActionMode(this);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800572 mCallback = null;
Adam Powell640a66e2011-04-29 10:18:53 -0700573 animateToMode(false);
Adam Powell0e94b512010-06-29 17:58:20 -0700574
575 // Clear out the context mode views after the animation finishes
Adam Powell640a66e2011-04-29 10:18:53 -0700576 mContextView.closeMode();
Adam Powell5d279772010-07-27 16:34:07 -0700577 mActionMode = null;
Adam Powell07e1f982011-03-24 11:11:15 -0700578
579 if (mWasHiddenBeforeMode) {
580 hide();
581 }
Adam Powell89e06452010-06-23 20:24:52 -0700582 }
583
584 @Override
585 public void invalidate() {
Adam Powell6e346362010-07-23 10:18:23 -0700586 if (mCallback.onPrepareActionMode(this, mMenu)) {
Adam Powell89e06452010-06-23 20:24:52 -0700587 // Refresh content in both context views
588 }
589 }
590
591 @Override
592 public void setCustomView(View view) {
Adam Powell640a66e2011-04-29 10:18:53 -0700593 mContextView.setCustomView(view);
Adam Powell29ed7572010-07-14 16:24:56 -0700594 mCustomView = new WeakReference<View>(view);
Adam Powell89e06452010-06-23 20:24:52 -0700595 }
596
597 @Override
598 public void setSubtitle(CharSequence subtitle) {
Adam Powell640a66e2011-04-29 10:18:53 -0700599 mContextView.setSubtitle(subtitle);
Adam Powell89e06452010-06-23 20:24:52 -0700600 }
601
602 @Override
603 public void setTitle(CharSequence title) {
Adam Powell640a66e2011-04-29 10:18:53 -0700604 mContextView.setTitle(title);
Adam Powell89e06452010-06-23 20:24:52 -0700605 }
Adam Powell29ed7572010-07-14 16:24:56 -0700606
607 @Override
Adam Powellc9ae2a22010-07-28 14:44:21 -0700608 public void setTitle(int resId) {
Adam Powell48e8ac32011-01-14 12:10:24 -0800609 setTitle(mContext.getResources().getString(resId));
Adam Powellc9ae2a22010-07-28 14:44:21 -0700610 }
611
612 @Override
613 public void setSubtitle(int resId) {
Adam Powell48e8ac32011-01-14 12:10:24 -0800614 setSubtitle(mContext.getResources().getString(resId));
Adam Powellc9ae2a22010-07-28 14:44:21 -0700615 }
616
617 @Override
Adam Powell29ed7572010-07-14 16:24:56 -0700618 public CharSequence getTitle() {
Adam Powell640a66e2011-04-29 10:18:53 -0700619 return mContextView.getTitle();
Adam Powell29ed7572010-07-14 16:24:56 -0700620 }
621
622 @Override
623 public CharSequence getSubtitle() {
Adam Powell640a66e2011-04-29 10:18:53 -0700624 return mContextView.getSubtitle();
Adam Powell29ed7572010-07-14 16:24:56 -0700625 }
Adam Powell89e06452010-06-23 20:24:52 -0700626
Adam Powell29ed7572010-07-14 16:24:56 -0700627 @Override
628 public View getCustomView() {
629 return mCustomView != null ? mCustomView.get() : null;
630 }
631
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700632 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800633 if (mCallback != null) {
634 return mCallback.onActionItemClicked(this, item);
635 } else {
636 return false;
637 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700638 }
639
640 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
641 }
642
643 public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800644 if (mCallback == null) {
645 return false;
646 }
647
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700648 if (!subMenu.hasVisibleItems()) {
649 return true;
Adam Powell89e06452010-06-23 20:24:52 -0700650 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700651
Adam Powelldec9dfd2010-08-09 15:27:54 -0700652 new MenuPopupHelper(mContext, subMenu).show();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700653 return true;
654 }
655
656 public void onCloseSubMenu(SubMenuBuilder menu) {
657 }
658
659 public void onMenuModeChange(MenuBuilder menu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800660 if (mCallback == null) {
661 return;
662 }
Adam Powellf6148c52010-08-11 21:10:16 -0700663 invalidate();
Adam Powell640a66e2011-04-29 10:18:53 -0700664 mContextView.showOverflowMenu();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700665 }
Adam Powell661c9082010-07-02 10:09:44 -0700666 }
667
668 /**
669 * @hide
670 */
671 public class TabImpl extends ActionBar.Tab {
Adam Powell2b6230e2010-09-07 17:55:25 -0700672 private ActionBar.TabListener mCallback;
673 private Object mTag;
Adam Powell661c9082010-07-02 10:09:44 -0700674 private Drawable mIcon;
675 private CharSequence mText;
Adam Powell0d8ec1d2011-05-03 14:49:13 -0700676 private int mPosition = -1;
Adam Powell2b6230e2010-09-07 17:55:25 -0700677 private View mCustomView;
Adam Powell661c9082010-07-02 10:09:44 -0700678
679 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700680 public Object getTag() {
681 return mTag;
682 }
683
684 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700685 public Tab setTag(Object tag) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700686 mTag = tag;
Adam Powell9ab97872010-10-26 21:47:29 -0700687 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700688 }
689
690 public ActionBar.TabListener getCallback() {
691 return mCallback;
692 }
693
694 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700695 public Tab setTabListener(ActionBar.TabListener callback) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700696 mCallback = callback;
Adam Powell9ab97872010-10-26 21:47:29 -0700697 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700698 }
699
700 @Override
701 public View getCustomView() {
702 return mCustomView;
703 }
704
705 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700706 public Tab setCustomView(View view) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700707 mCustomView = view;
Adam Powell0d8ec1d2011-05-03 14:49:13 -0700708 if (mPosition >= 0) mActionView.updateTab(mPosition);
Adam Powell9ab97872010-10-26 21:47:29 -0700709 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700710 }
711
712 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800713 public Tab setCustomView(int layoutResId) {
714 return setCustomView(LayoutInflater.from(mContext).inflate(layoutResId, null));
715 }
716
717 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700718 public Drawable getIcon() {
719 return mIcon;
720 }
721
722 @Override
723 public int getPosition() {
724 return mPosition;
725 }
726
727 public void setPosition(int position) {
728 mPosition = position;
729 }
730
731 @Override
732 public CharSequence getText() {
733 return mText;
734 }
735
736 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700737 public Tab setIcon(Drawable icon) {
Adam Powell661c9082010-07-02 10:09:44 -0700738 mIcon = icon;
Adam Powell0d8ec1d2011-05-03 14:49:13 -0700739 if (mPosition >= 0) mActionView.updateTab(mPosition);
Adam Powell9ab97872010-10-26 21:47:29 -0700740 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700741 }
742
743 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800744 public Tab setIcon(int resId) {
745 return setIcon(mContext.getResources().getDrawable(resId));
746 }
747
748 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700749 public Tab setText(CharSequence text) {
Adam Powell661c9082010-07-02 10:09:44 -0700750 mText = text;
Adam Powell0d8ec1d2011-05-03 14:49:13 -0700751 if (mPosition >= 0) mActionView.updateTab(mPosition);
Adam Powell9ab97872010-10-26 21:47:29 -0700752 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700753 }
754
755 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800756 public Tab setText(int resId) {
757 return setText(mContext.getResources().getText(resId));
758 }
759
760 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700761 public void select() {
762 selectTab(this);
Adam Powell89e06452010-06-23 20:24:52 -0700763 }
764 }
Adam Powell9ab97872010-10-26 21:47:29 -0700765
766 @Override
767 public void setCustomView(View view) {
768 mActionView.setCustomNavigationView(view);
769 }
770
771 @Override
772 public void setCustomView(View view, LayoutParams layoutParams) {
773 view.setLayoutParams(layoutParams);
774 mActionView.setCustomNavigationView(view);
775 }
776
777 @Override
Adam Powell8515ee82010-11-30 14:09:55 -0800778 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
Adam Powell9ab97872010-10-26 21:47:29 -0700779 mActionView.setDropdownAdapter(adapter);
780 mActionView.setCallback(callback);
781 }
782
783 @Override
784 public int getSelectedNavigationIndex() {
785 switch (mActionView.getNavigationMode()) {
786 case NAVIGATION_MODE_TABS:
Adam Powell04587962010-11-11 22:15:07 -0800787 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
Adam Powell9ab97872010-10-26 21:47:29 -0700788 case NAVIGATION_MODE_LIST:
789 return mActionView.getDropdownSelectedPosition();
790 default:
791 return -1;
792 }
793 }
794
795 @Override
796 public int getNavigationItemCount() {
797 switch (mActionView.getNavigationMode()) {
798 case NAVIGATION_MODE_TABS:
799 return mTabs.size();
800 case NAVIGATION_MODE_LIST:
801 SpinnerAdapter adapter = mActionView.getDropdownAdapter();
802 return adapter != null ? adapter.getCount() : 0;
803 default:
804 return 0;
805 }
806 }
807
808 @Override
Adam Powell0c24a552010-11-03 16:44:11 -0700809 public int getTabCount() {
810 return mTabs.size();
811 }
812
813 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700814 public void setNavigationMode(int mode) {
Adam Powell0c24a552010-11-03 16:44:11 -0700815 final int oldMode = mActionView.getNavigationMode();
816 switch (oldMode) {
817 case NAVIGATION_MODE_TABS:
818 mSavedTabPosition = getSelectedNavigationIndex();
819 selectTab(null);
Adam Powelldae78242011-04-25 15:23:41 -0700820 if (!mActionView.hasEmbeddedTabs()) {
821 mExternalTabView.setVisibility(View.GONE);
822 }
Adam Powell0c24a552010-11-03 16:44:11 -0700823 break;
824 }
Adam Powell9ab97872010-10-26 21:47:29 -0700825 mActionView.setNavigationMode(mode);
Adam Powell0c24a552010-11-03 16:44:11 -0700826 switch (mode) {
827 case NAVIGATION_MODE_TABS:
Adam Powelldae78242011-04-25 15:23:41 -0700828 if (!mActionView.hasEmbeddedTabs()) {
829 mExternalTabView.setVisibility(View.VISIBLE);
830 }
Adam Powell0c24a552010-11-03 16:44:11 -0700831 if (mSavedTabPosition != INVALID_POSITION) {
832 setSelectedNavigationItem(mSavedTabPosition);
833 mSavedTabPosition = INVALID_POSITION;
834 }
835 break;
836 }
Adam Powell9ab97872010-10-26 21:47:29 -0700837 }
838
839 @Override
840 public Tab getTabAt(int index) {
841 return mTabs.get(index);
842 }
Adam Powell0c24a552010-11-03 16:44:11 -0700843
Adam Powell0c24a552010-11-03 16:44:11 -0700844
Adam Powell1969b872011-03-22 11:52:48 -0700845 @Override
846 public void setIcon(int resId) {
Adam Powell45c515b2011-04-21 18:50:20 -0700847 mActionView.setIcon(resId);
Adam Powell1969b872011-03-22 11:52:48 -0700848 }
Adam Powell0c24a552010-11-03 16:44:11 -0700849
Adam Powell1969b872011-03-22 11:52:48 -0700850 @Override
851 public void setIcon(Drawable icon) {
852 mActionView.setIcon(icon);
853 }
854
855 @Override
856 public void setLogo(int resId) {
Adam Powell45c515b2011-04-21 18:50:20 -0700857 mActionView.setLogo(resId);
Adam Powell1969b872011-03-22 11:52:48 -0700858 }
859
860 @Override
861 public void setLogo(Drawable logo) {
862 mActionView.setLogo(logo);
Adam Powell0c24a552010-11-03 16:44:11 -0700863 }
Adam Powell89e06452010-06-23 20:24:52 -0700864}