blob: 57df259acca9677aae7ed9fe1fb7e815c8fde97b [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 Powelldae78242011-04-25 15:23:41 -070045import android.view.ViewGroup;
Adam Powelle6ec7322010-12-07 15:29:26 -080046import android.view.Window;
Adam Powell45f1e082010-12-10 14:20:13 -080047import android.view.animation.DecelerateInterpolator;
Adam Powelldae78242011-04-25 15:23:41 -070048import android.widget.HorizontalScrollView;
Adam Powell89e06452010-06-23 20:24:52 -070049import android.widget.LinearLayout;
50import 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 Powell89e06452010-06-23 20:24:52 -070064 private static final int NORMAL_VIEW = 0;
65 private static final int CONTEXT_VIEW = 1;
Adam Powell661c9082010-07-02 10:09:44 -070066
Adam Powelldec9dfd2010-08-09 15:27:54 -070067 private Context mContext;
Adam Powell661c9082010-07-02 10:09:44 -070068 private Activity mActivity;
Adam Powelldec9dfd2010-08-09 15:27:54 -070069 private Dialog mDialog;
Adam Powell661c9082010-07-02 10:09:44 -070070
Adam Powell01feaee2011-02-10 15:05:05 -080071 private ActionBarContainer mContainerView;
Adam Powell89e06452010-06-23 20:24:52 -070072 private ActionBarView mActionView;
73 private ActionBarContextView mUpperContextView;
Adam Powell9b4bee02011-04-27 19:24:47 -070074 private LinearLayout mLowerView;
Adam Powelle6ec7322010-12-07 15:29:26 -080075 private View mContentView;
Adam Powelldae78242011-04-25 15:23:41 -070076 private ViewGroup mExternalTabView;
Adam Powell661c9082010-07-02 10:09:44 -070077
78 private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
79
Adam Powell661c9082010-07-02 10:09:44 -070080 private TabImpl mSelectedTab;
Adam Powell0c24a552010-11-03 16:44:11 -070081 private int mSavedTabPosition = INVALID_POSITION;
Adam Powell89e06452010-06-23 20:24:52 -070082
Adam Powell5d279772010-07-27 16:34:07 -070083 private ActionMode mActionMode;
Adam Powell89e06452010-06-23 20:24:52 -070084
Adam Powell8515ee82010-11-30 14:09:55 -080085 private boolean mLastMenuVisibility;
86 private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
87 new ArrayList<OnMenuVisibilityListener>();
88
Adam Powell89e06452010-06-23 20:24:52 -070089 private static final int CONTEXT_DISPLAY_NORMAL = 0;
90 private static final int CONTEXT_DISPLAY_SPLIT = 1;
91
Adam Powell0c24a552010-11-03 16:44:11 -070092 private static final int INVALID_POSITION = -1;
93
Adam Powell89e06452010-06-23 20:24:52 -070094 private int mContextDisplayMode;
Adam Powell0e94b512010-06-29 17:58:20 -070095
96 final Handler mHandler = new Handler();
Adam Powelld8b3f2e2010-12-02 13:37:03 -080097
Adam Powell07e1f982011-03-24 11:11:15 -070098 private Animator mCurrentShowAnim;
99 private Animator mCurrentModeAnim;
Adam Powell50efbed2011-02-08 16:20:15 -0800100 private boolean mShowHideAnimationEnabled;
Adam Powell07e1f982011-03-24 11:11:15 -0700101 boolean mWasHiddenBeforeMode;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800102
Adam Powell45f1e082010-12-10 14:20:13 -0800103 private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator();
104
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800105 final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
Adam Powell07e1f982011-03-24 11:11:15 -0700106 new AnimatorListenerAdapter() { // NORMAL_VIEW
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800107 @Override
108 public void onAnimationEnd(Animator animation) {
Adam Powell9b4bee02011-04-27 19:24:47 -0700109 if (mLowerView != null) {
110 mLowerView.removeAllViews();
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800111 }
Adam Powell07e1f982011-03-24 11:11:15 -0700112 mCurrentModeAnim = null;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800113 hideAllExcept(NORMAL_VIEW);
114 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800115 },
Adam Powell07e1f982011-03-24 11:11:15 -0700116 new AnimatorListenerAdapter() { // CONTEXT_VIEW
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800117 @Override
118 public void onAnimationEnd(Animator animation) {
Adam Powell07e1f982011-03-24 11:11:15 -0700119 mCurrentModeAnim = null;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800120 hideAllExcept(CONTEXT_VIEW);
121 }
Adam Powell0e94b512010-06-29 17:58:20 -0700122 }
Adam Powell0e94b512010-06-29 17:58:20 -0700123 };
124
Adam Powell07e1f982011-03-24 11:11:15 -0700125 final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
Adam Powelle6ec7322010-12-07 15:29:26 -0800126 @Override
127 public void onAnimationEnd(Animator animation) {
128 if (mContentView != null) {
129 mContentView.setTranslationY(0);
130 }
131 mContainerView.setVisibility(View.GONE);
Adam Powell01feaee2011-02-10 15:05:05 -0800132 mContainerView.setTransitioning(false);
Adam Powell07e1f982011-03-24 11:11:15 -0700133 mCurrentShowAnim = null;
Adam Powelle6ec7322010-12-07 15:29:26 -0800134 }
135 };
136
Adam Powell07e1f982011-03-24 11:11:15 -0700137 final AnimatorListener mShowListener = new AnimatorListenerAdapter() {
Adam Powelle6ec7322010-12-07 15:29:26 -0800138 @Override
139 public void onAnimationEnd(Animator animation) {
Adam Powell07e1f982011-03-24 11:11:15 -0700140 mCurrentShowAnim = null;
Adam Powell45f1e082010-12-10 14:20:13 -0800141 mContainerView.requestLayout();
Adam Powelle6ec7322010-12-07 15:29:26 -0800142 }
Adam Powelle6ec7322010-12-07 15:29:26 -0800143 };
144
Adam Powell661c9082010-07-02 10:09:44 -0700145 public ActionBarImpl(Activity activity) {
Adam Powell661c9082010-07-02 10:09:44 -0700146 mActivity = activity;
Adam Powelle6ec7322010-12-07 15:29:26 -0800147 Window window = activity.getWindow();
148 View decor = window.getDecorView();
149 init(decor);
150 if (!mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) {
151 mContentView = decor.findViewById(android.R.id.content);
152 }
Adam Powelldec9dfd2010-08-09 15:27:54 -0700153 }
154
155 public ActionBarImpl(Dialog dialog) {
156 mDialog = dialog;
157 init(dialog.getWindow().getDecorView());
158 }
159
160 private void init(View decor) {
161 mContext = decor.getContext();
Adam Powell89e06452010-06-23 20:24:52 -0700162 mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
163 mUpperContextView = (ActionBarContextView) decor.findViewById(
164 com.android.internal.R.id.action_context_bar);
Adam Powell9b4bee02011-04-27 19:24:47 -0700165 mLowerView = (LinearLayout) decor.findViewById(
Adam Powell89e06452010-06-23 20:24:52 -0700166 com.android.internal.R.id.lower_action_context_bar);
Adam Powell01feaee2011-02-10 15:05:05 -0800167 mContainerView = (ActionBarContainer) decor.findViewById(
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800168 com.android.internal.R.id.action_bar_container);
Steve Block08f194b2010-08-24 18:20:48 +0100169
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800170 if (mActionView == null || mUpperContextView == null || mContainerView == null) {
Adam Powell89e06452010-06-23 20:24:52 -0700171 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
172 "with a compatible window decor layout");
173 }
Adam Powell0e94b512010-06-29 17:58:20 -0700174
Steve Block08f194b2010-08-24 18:20:48 +0100175 mActionView.setContextView(mUpperContextView);
Adam Powell9b4bee02011-04-27 19:24:47 -0700176 mContextDisplayMode = mActionView.isSplitActionBar() ?
177 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
Adam Powelldae78242011-04-25 15:23:41 -0700178
179 if (!mActionView.hasEmbeddedTabs()) {
180 HorizontalScrollView tabScroller = new HorizontalScrollView(mContext);
181 ViewGroup tabContainer = mActionView.createTabContainer();
182 tabScroller.setHorizontalFadingEdgeEnabled(true);
183 tabScroller.addView(tabContainer);
184 tabScroller.setVisibility(getNavigationMode() == NAVIGATION_MODE_TABS ?
185 View.VISIBLE : View.GONE);
186 mActionView.setExternalTabLayout(tabContainer);
187 mContainerView.setTabContainer(tabScroller);
188 mExternalTabView = tabScroller;
189 }
Adam Powell89e06452010-06-23 20:24:52 -0700190 }
191
Adam Powell50efbed2011-02-08 16:20:15 -0800192 /**
193 * Enables or disables animation between show/hide states.
194 * If animation is disabled using this method, animations in progress
195 * will be finished.
196 *
197 * @param enabled true to animate, false to not animate.
198 */
199 public void setShowHideAnimationEnabled(boolean enabled) {
200 mShowHideAnimationEnabled = enabled;
Adam Powell07e1f982011-03-24 11:11:15 -0700201 if (!enabled && mCurrentShowAnim != null) {
202 mCurrentShowAnim.end();
Adam Powell50efbed2011-02-08 16:20:15 -0800203 }
204 }
205
Adam Powell8515ee82010-11-30 14:09:55 -0800206 public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
207 mMenuVisibilityListeners.add(listener);
208 }
209
210 public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
211 mMenuVisibilityListeners.remove(listener);
212 }
213
214 public void dispatchMenuVisibilityChanged(boolean isVisible) {
215 if (isVisible == mLastMenuVisibility) {
216 return;
217 }
218 mLastMenuVisibility = isVisible;
219
220 final int count = mMenuVisibilityListeners.size();
221 for (int i = 0; i < count; i++) {
222 mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
223 }
224 }
225
Adam Powella66c7b02010-07-28 15:28:25 -0700226 @Override
Adam Powell3f476b32011-01-03 19:25:36 -0800227 public void setCustomView(int resId) {
228 setCustomView(LayoutInflater.from(mContext).inflate(resId, mActionView, false));
229 }
230
231 @Override
232 public void setDisplayUseLogoEnabled(boolean useLogo) {
233 setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
234 }
235
236 @Override
237 public void setDisplayShowHomeEnabled(boolean showHome) {
238 setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
239 }
240
241 @Override
242 public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
243 setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
244 }
245
246 @Override
247 public void setDisplayShowTitleEnabled(boolean showTitle) {
248 setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
249 }
250
251 @Override
252 public void setDisplayShowCustomEnabled(boolean showCustom) {
253 setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
254 }
255
256 @Override
Adam Powelldae78242011-04-25 15:23:41 -0700257 public void setDisplayDisableHomeEnabled(boolean disableHome) {
258 setDisplayOptions(disableHome ? DISPLAY_DISABLE_HOME : 0, DISPLAY_DISABLE_HOME);
259 }
260
261 @Override
Adam Powella66c7b02010-07-28 15:28:25 -0700262 public void setTitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700263 setTitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700264 }
265
266 @Override
267 public void setSubtitle(int resId) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700268 setSubtitle(mContext.getString(resId));
Adam Powella66c7b02010-07-28 15:28:25 -0700269 }
270
Adam Powell17809772010-07-21 13:25:11 -0700271 public void setSelectedNavigationItem(int position) {
272 switch (mActionView.getNavigationMode()) {
273 case NAVIGATION_MODE_TABS:
274 selectTab(mTabs.get(position));
275 break;
Adam Powell9ab97872010-10-26 21:47:29 -0700276 case NAVIGATION_MODE_LIST:
Adam Powell17809772010-07-21 13:25:11 -0700277 mActionView.setDropdownSelectedPosition(position);
278 break;
279 default:
280 throw new IllegalStateException(
Adam Powell9ab97872010-10-26 21:47:29 -0700281 "setSelectedNavigationIndex not valid for current navigation mode");
Adam Powell17809772010-07-21 13:25:11 -0700282 }
283 }
284
Adam Powell9ab97872010-10-26 21:47:29 -0700285 public void removeAllTabs() {
286 cleanupTabs();
Adam Powell17809772010-07-21 13:25:11 -0700287 }
288
Adam Powell661c9082010-07-02 10:09:44 -0700289 private void cleanupTabs() {
290 if (mSelectedTab != null) {
291 selectTab(null);
292 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700293 mTabs.clear();
Adam Powell0c24a552010-11-03 16:44:11 -0700294 mActionView.removeAllTabs();
295 mSavedTabPosition = INVALID_POSITION;
Adam Powell661c9082010-07-02 10:09:44 -0700296 }
297
Adam Powell0e94b512010-06-29 17:58:20 -0700298 public void setTitle(CharSequence title) {
299 mActionView.setTitle(title);
300 }
301
302 public void setSubtitle(CharSequence subtitle) {
303 mActionView.setSubtitle(subtitle);
304 }
305
Adam Powell89e06452010-06-23 20:24:52 -0700306 public void setDisplayOptions(int options) {
307 mActionView.setDisplayOptions(options);
308 }
Adam Powell0e94b512010-06-29 17:58:20 -0700309
Adam Powell89e06452010-06-23 20:24:52 -0700310 public void setDisplayOptions(int options, int mask) {
311 final int current = mActionView.getDisplayOptions();
312 mActionView.setDisplayOptions((options & mask) | (current & ~mask));
313 }
314
315 public void setBackgroundDrawable(Drawable d) {
Adam Powelle8c1e5c2010-12-13 10:49:32 -0800316 mContainerView.setBackgroundDrawable(d);
Adam Powell89e06452010-06-23 20:24:52 -0700317 }
318
Adam Powellef704442010-11-16 14:48:22 -0800319 public View getCustomView() {
Adam Powell89e06452010-06-23 20:24:52 -0700320 return mActionView.getCustomNavigationView();
321 }
322
323 public CharSequence getTitle() {
324 return mActionView.getTitle();
325 }
326
327 public CharSequence getSubtitle() {
328 return mActionView.getSubtitle();
329 }
330
331 public int getNavigationMode() {
332 return mActionView.getNavigationMode();
333 }
334
335 public int getDisplayOptions() {
336 return mActionView.getDisplayOptions();
337 }
338
Adam Powell5d279772010-07-27 16:34:07 -0700339 public ActionMode startActionMode(ActionMode.Callback callback) {
340 if (mActionMode != null) {
341 mActionMode.finish();
Adam Powell6e346362010-07-23 10:18:23 -0700342 }
Adam Powell3461b322010-07-14 11:34:43 -0700343
Adam Powella1e63582011-01-18 16:51:22 -0800344 mUpperContextView.killMode();
Adam Powell5d279772010-07-27 16:34:07 -0700345 ActionMode mode = new ActionModeImpl(callback);
Adam Powell6e346362010-07-23 10:18:23 -0700346 if (callback.onCreateActionMode(mode, mode.getMenu())) {
Adam Powell07e1f982011-03-24 11:11:15 -0700347 mWasHiddenBeforeMode = !isShowing();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700348 mode.invalidate();
349 mUpperContextView.initForMode(mode);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800350 animateTo(CONTEXT_VIEW);
Adam Powell9b4bee02011-04-27 19:24:47 -0700351 if (mLowerView != null) {
Adam Powell89e06452010-06-23 20:24:52 -0700352 // TODO animate this
Adam Powell9b4bee02011-04-27 19:24:47 -0700353 mLowerView.setVisibility(View.VISIBLE);
Adam Powell89e06452010-06-23 20:24:52 -0700354 }
Adam Powell5d279772010-07-27 16:34:07 -0700355 mActionMode = mode;
Adam Powellac695c62010-07-20 18:19:27 -0700356 return mode;
Adam Powell89e06452010-06-23 20:24:52 -0700357 }
Adam Powellac695c62010-07-20 18:19:27 -0700358 return null;
Adam Powell89e06452010-06-23 20:24:52 -0700359 }
360
Adam Powell661c9082010-07-02 10:09:44 -0700361 private void configureTab(Tab tab, int position) {
362 final TabImpl tabi = (TabImpl) tab;
Adam Powell2b6230e2010-09-07 17:55:25 -0700363 final ActionBar.TabListener callback = tabi.getCallback();
364
365 if (callback == null) {
366 throw new IllegalStateException("Action Bar Tab must have a Callback");
367 }
Adam Powell661c9082010-07-02 10:09:44 -0700368
369 tabi.setPosition(position);
370 mTabs.add(position, tabi);
371
Adam Powell81b89442010-11-02 17:58:56 -0700372 final int count = mTabs.size();
373 for (int i = position + 1; i < count; i++) {
374 mTabs.get(i).setPosition(i);
Adam Powell661c9082010-07-02 10:09:44 -0700375 }
Adam Powell661c9082010-07-02 10:09:44 -0700376 }
377
378 @Override
379 public void addTab(Tab tab) {
Adam Powell81b89442010-11-02 17:58:56 -0700380 addTab(tab, mTabs.isEmpty());
Adam Powell661c9082010-07-02 10:09:44 -0700381 }
382
383 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700384 public void addTab(Tab tab, int position) {
Adam Powell81b89442010-11-02 17:58:56 -0700385 addTab(tab, position, mTabs.isEmpty());
386 }
387
388 @Override
389 public void addTab(Tab tab, boolean setSelected) {
390 mActionView.addTab(tab, setSelected);
391 configureTab(tab, mTabs.size());
392 if (setSelected) {
393 selectTab(tab);
394 }
395 }
396
397 @Override
398 public void addTab(Tab tab, int position, boolean setSelected) {
399 mActionView.addTab(tab, position, setSelected);
Adam Powell661c9082010-07-02 10:09:44 -0700400 configureTab(tab, position);
Adam Powell81b89442010-11-02 17:58:56 -0700401 if (setSelected) {
402 selectTab(tab);
403 }
Adam Powell661c9082010-07-02 10:09:44 -0700404 }
405
406 @Override
407 public Tab newTab() {
408 return new TabImpl();
409 }
410
411 @Override
412 public void removeTab(Tab tab) {
413 removeTabAt(tab.getPosition());
414 }
415
416 @Override
417 public void removeTabAt(int position) {
Adam Powell0c24a552010-11-03 16:44:11 -0700418 int selectedTabPosition = mSelectedTab != null
419 ? mSelectedTab.getPosition() : mSavedTabPosition;
Adam Powell661c9082010-07-02 10:09:44 -0700420 mActionView.removeTabAt(position);
421 mTabs.remove(position);
422
423 final int newTabCount = mTabs.size();
424 for (int i = position; i < newTabCount; i++) {
425 mTabs.get(i).setPosition(i);
426 }
427
Adam Powell0c24a552010-11-03 16:44:11 -0700428 if (selectedTabPosition == position) {
429 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
430 }
Adam Powell661c9082010-07-02 10:09:44 -0700431 }
432
433 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700434 public void selectTab(Tab tab) {
Adam Powell0c24a552010-11-03 16:44:11 -0700435 if (getNavigationMode() != NAVIGATION_MODE_TABS) {
436 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
437 return;
438 }
439
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800440 final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction()
Adam Powell0c24a552010-11-03 16:44:11 -0700441 .disallowAddToBackStack();
Adam Powell7f9b9052010-10-19 16:56:07 -0700442
443 if (mSelectedTab == tab) {
444 if (mSelectedTab != null) {
445 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
446 }
447 } else {
448 mActionView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
449 if (mSelectedTab != null) {
450 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
451 }
452 mSelectedTab = (TabImpl) tab;
453 if (mSelectedTab != null) {
454 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
455 }
Adam Powell2b6230e2010-09-07 17:55:25 -0700456 }
457
458 if (!trans.isEmpty()) {
459 trans.commit();
460 }
461 }
462
463 @Override
464 public Tab getSelectedTab() {
465 return mSelectedTab;
Adam Powell661c9082010-07-02 10:09:44 -0700466 }
467
Adam Powell6b336f82010-08-10 20:13:01 -0700468 @Override
469 public int getHeight() {
470 return mActionView.getHeight();
471 }
472
473 @Override
474 public void show() {
Adam Powell07e1f982011-03-24 11:11:15 -0700475 show(true);
476 }
477
478 void show(boolean markHiddenBeforeMode) {
479 if (mCurrentShowAnim != null) {
480 mCurrentShowAnim.end();
Adam Powell45f1e082010-12-10 14:20:13 -0800481 }
Adam Powelld76cee22011-01-31 15:05:05 -0800482 if (mContainerView.getVisibility() == View.VISIBLE) {
Adam Powell07e1f982011-03-24 11:11:15 -0700483 if (markHiddenBeforeMode) mWasHiddenBeforeMode = false;
Adam Powelld76cee22011-01-31 15:05:05 -0800484 return;
485 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800486 mContainerView.setVisibility(View.VISIBLE);
Adam Powell50efbed2011-02-08 16:20:15 -0800487
488 if (mShowHideAnimationEnabled) {
489 mContainerView.setAlpha(0);
490 AnimatorSet anim = new AnimatorSet();
491 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1));
492 if (mContentView != null) {
493 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
494 -mContainerView.getHeight(), 0));
495 mContainerView.setTranslationY(-mContainerView.getHeight());
496 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
497 }
498 anim.addListener(mShowListener);
Adam Powell07e1f982011-03-24 11:11:15 -0700499 mCurrentShowAnim = anim;
Adam Powell50efbed2011-02-08 16:20:15 -0800500 anim.start();
501 } else {
Adam Powelld8145042011-03-24 14:18:27 -0700502 mContainerView.setAlpha(1);
503 mContainerView.setTranslationY(0);
Adam Powell50efbed2011-02-08 16:20:15 -0800504 mShowListener.onAnimationEnd(null);
Adam Powelle6ec7322010-12-07 15:29:26 -0800505 }
Adam Powell6b336f82010-08-10 20:13:01 -0700506 }
507
508 @Override
509 public void hide() {
Adam Powell07e1f982011-03-24 11:11:15 -0700510 if (mCurrentShowAnim != null) {
511 mCurrentShowAnim.end();
Adam Powelle6ec7322010-12-07 15:29:26 -0800512 }
513 if (mContainerView.getVisibility() == View.GONE) {
514 return;
515 }
Adam Powell50efbed2011-02-08 16:20:15 -0800516
517 if (mShowHideAnimationEnabled) {
518 mContainerView.setAlpha(1);
Adam Powell01feaee2011-02-10 15:05:05 -0800519 mContainerView.setTransitioning(true);
Adam Powell50efbed2011-02-08 16:20:15 -0800520 AnimatorSet anim = new AnimatorSet();
521 AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0));
522 if (mContentView != null) {
523 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
524 0, -mContainerView.getHeight()));
525 b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
526 -mContainerView.getHeight()));
527 }
528 anim.addListener(mHideListener);
Adam Powell07e1f982011-03-24 11:11:15 -0700529 mCurrentShowAnim = anim;
Adam Powell50efbed2011-02-08 16:20:15 -0800530 anim.start();
531 } else {
532 mHideListener.onAnimationEnd(null);
Adam Powelle6ec7322010-12-07 15:29:26 -0800533 }
Adam Powell6b336f82010-08-10 20:13:01 -0700534 }
535
536 public boolean isShowing() {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800537 return mContainerView.getVisibility() == View.VISIBLE;
538 }
539
Adam Powell07e1f982011-03-24 11:11:15 -0700540 long animateTo(int viewIndex) {
541 show(false);
542 if (mCurrentModeAnim != null) {
543 mCurrentModeAnim.end();
544 }
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800545
546 AnimatorSet set = new AnimatorSet();
547
548 final View targetChild = mContainerView.getChildAt(viewIndex);
549 targetChild.setVisibility(View.VISIBLE);
Adam Powell07e1f982011-03-24 11:11:15 -0700550 targetChild.setAlpha(0);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800551 AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800552
553 final int count = mContainerView.getChildCount();
554 for (int i = 0; i < count; i++) {
555 final View child = mContainerView.getChildAt(i);
Adam Powelldae78242011-04-25 15:23:41 -0700556 if (i == viewIndex || child == mContainerView.getTabContainer()) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800557 continue;
558 }
559
560 if (child.getVisibility() != View.GONE) {
Adam Powell45f1e082010-12-10 14:20:13 -0800561 Animator a = ObjectAnimator.ofFloat(child, "alpha", 0);
562 a.setInterpolator(sFadeOutInterpolator);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800563 b.with(a);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800564 }
565 }
566
567 set.addListener(mAfterAnimation[viewIndex]);
568
Adam Powell07e1f982011-03-24 11:11:15 -0700569 mCurrentModeAnim = set;
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800570 set.start();
571 return set.getDuration();
572 }
573
574 private void hideAllExcept(int viewIndex) {
575 final int count = mContainerView.getChildCount();
576 for (int i = 0; i < count; i++) {
577 mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE);
578 }
Adam Powell6b336f82010-08-10 20:13:01 -0700579 }
580
Adam Powell89e06452010-06-23 20:24:52 -0700581 /**
582 * @hide
583 */
Adam Powell5d279772010-07-27 16:34:07 -0700584 public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
Adam Powell6e346362010-07-23 10:18:23 -0700585 private ActionMode.Callback mCallback;
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700586 private MenuBuilder mMenu;
Adam Powell29ed7572010-07-14 16:24:56 -0700587 private WeakReference<View> mCustomView;
Adam Powell89e06452010-06-23 20:24:52 -0700588
Adam Powell5d279772010-07-27 16:34:07 -0700589 public ActionModeImpl(ActionMode.Callback callback) {
Adam Powell89e06452010-06-23 20:24:52 -0700590 mCallback = callback;
Adam Powell4d9861e2010-08-17 11:14:40 -0700591 mMenu = new MenuBuilder(mActionView.getContext())
592 .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700593 mMenu.setCallback(this);
Adam Powell89e06452010-06-23 20:24:52 -0700594 }
Adam Powell9168f0b2010-08-02 15:46:24 -0700595
596 @Override
597 public MenuInflater getMenuInflater() {
Adam Powell4d9861e2010-08-17 11:14:40 -0700598 return new MenuInflater(mContext);
Adam Powell9168f0b2010-08-02 15:46:24 -0700599 }
600
Adam Powell89e06452010-06-23 20:24:52 -0700601 @Override
602 public Menu getMenu() {
603 return mMenu;
604 }
605
606 @Override
607 public void finish() {
Adam Powell5d279772010-07-27 16:34:07 -0700608 if (mActionMode != this) {
609 // Not the active action mode - no-op
Adam Powell93b6bc32010-07-22 11:36:35 -0700610 return;
611 }
612
Adam Powell6e346362010-07-23 10:18:23 -0700613 mCallback.onDestroyActionMode(this);
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800614 mCallback = null;
615 animateTo(NORMAL_VIEW);
Adam Powell0e94b512010-06-29 17:58:20 -0700616
617 // Clear out the context mode views after the animation finishes
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800618 mUpperContextView.closeMode();
Adam Powell9b4bee02011-04-27 19:24:47 -0700619 if (mLowerView != null && mLowerView.getVisibility() != View.GONE) {
Adam Powell89e06452010-06-23 20:24:52 -0700620 // TODO Animate this
Adam Powell9b4bee02011-04-27 19:24:47 -0700621 mLowerView.setVisibility(View.GONE);
Adam Powell89e06452010-06-23 20:24:52 -0700622 }
Adam Powell5d279772010-07-27 16:34:07 -0700623 mActionMode = null;
Adam Powell07e1f982011-03-24 11:11:15 -0700624
625 if (mWasHiddenBeforeMode) {
626 hide();
627 }
Adam Powell89e06452010-06-23 20:24:52 -0700628 }
629
630 @Override
631 public void invalidate() {
Adam Powell6e346362010-07-23 10:18:23 -0700632 if (mCallback.onPrepareActionMode(this, mMenu)) {
Adam Powell89e06452010-06-23 20:24:52 -0700633 // Refresh content in both context views
634 }
635 }
636
637 @Override
638 public void setCustomView(View view) {
639 mUpperContextView.setCustomView(view);
Adam Powell29ed7572010-07-14 16:24:56 -0700640 mCustomView = new WeakReference<View>(view);
Adam Powell89e06452010-06-23 20:24:52 -0700641 }
642
643 @Override
644 public void setSubtitle(CharSequence subtitle) {
645 mUpperContextView.setSubtitle(subtitle);
646 }
647
648 @Override
649 public void setTitle(CharSequence title) {
650 mUpperContextView.setTitle(title);
651 }
Adam Powell29ed7572010-07-14 16:24:56 -0700652
653 @Override
Adam Powellc9ae2a22010-07-28 14:44:21 -0700654 public void setTitle(int resId) {
Adam Powell48e8ac32011-01-14 12:10:24 -0800655 setTitle(mContext.getResources().getString(resId));
Adam Powellc9ae2a22010-07-28 14:44:21 -0700656 }
657
658 @Override
659 public void setSubtitle(int resId) {
Adam Powell48e8ac32011-01-14 12:10:24 -0800660 setSubtitle(mContext.getResources().getString(resId));
Adam Powellc9ae2a22010-07-28 14:44:21 -0700661 }
662
663 @Override
Adam Powell29ed7572010-07-14 16:24:56 -0700664 public CharSequence getTitle() {
665 return mUpperContextView.getTitle();
666 }
667
668 @Override
669 public CharSequence getSubtitle() {
670 return mUpperContextView.getSubtitle();
671 }
Adam Powell89e06452010-06-23 20:24:52 -0700672
Adam Powell29ed7572010-07-14 16:24:56 -0700673 @Override
674 public View getCustomView() {
675 return mCustomView != null ? mCustomView.get() : null;
676 }
677
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700678 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800679 if (mCallback != null) {
680 return mCallback.onActionItemClicked(this, item);
681 } else {
682 return false;
683 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700684 }
685
686 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
687 }
688
689 public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800690 if (mCallback == null) {
691 return false;
692 }
693
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700694 if (!subMenu.hasVisibleItems()) {
695 return true;
Adam Powell89e06452010-06-23 20:24:52 -0700696 }
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700697
Adam Powelldec9dfd2010-08-09 15:27:54 -0700698 new MenuPopupHelper(mContext, subMenu).show();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700699 return true;
700 }
701
702 public void onCloseSubMenu(SubMenuBuilder menu) {
703 }
704
705 public void onMenuModeChange(MenuBuilder menu) {
Adam Powelld8b3f2e2010-12-02 13:37:03 -0800706 if (mCallback == null) {
707 return;
708 }
Adam Powellf6148c52010-08-11 21:10:16 -0700709 invalidate();
Adam Powell696cba52011-03-29 10:38:16 -0700710 mUpperContextView.showOverflowMenu();
Adam Powell2c9c9fe2010-07-16 10:17:57 -0700711 }
Adam Powell661c9082010-07-02 10:09:44 -0700712 }
713
714 /**
715 * @hide
716 */
717 public class TabImpl extends ActionBar.Tab {
Adam Powell2b6230e2010-09-07 17:55:25 -0700718 private ActionBar.TabListener mCallback;
719 private Object mTag;
Adam Powell661c9082010-07-02 10:09:44 -0700720 private Drawable mIcon;
721 private CharSequence mText;
722 private int mPosition;
Adam Powell2b6230e2010-09-07 17:55:25 -0700723 private View mCustomView;
Adam Powell661c9082010-07-02 10:09:44 -0700724
725 @Override
Adam Powell2b6230e2010-09-07 17:55:25 -0700726 public Object getTag() {
727 return mTag;
728 }
729
730 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700731 public Tab setTag(Object tag) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700732 mTag = tag;
Adam Powell9ab97872010-10-26 21:47:29 -0700733 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700734 }
735
736 public ActionBar.TabListener getCallback() {
737 return mCallback;
738 }
739
740 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700741 public Tab setTabListener(ActionBar.TabListener callback) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700742 mCallback = callback;
Adam Powell9ab97872010-10-26 21:47:29 -0700743 return this;
Adam Powell2b6230e2010-09-07 17:55:25 -0700744 }
745
746 @Override
747 public View getCustomView() {
748 return mCustomView;
749 }
750
751 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700752 public Tab setCustomView(View view) {
Adam Powell2b6230e2010-09-07 17:55:25 -0700753 mCustomView = view;
Adam Powell9ab97872010-10-26 21:47:29 -0700754 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700755 }
756
757 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800758 public Tab setCustomView(int layoutResId) {
759 return setCustomView(LayoutInflater.from(mContext).inflate(layoutResId, null));
760 }
761
762 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700763 public Drawable getIcon() {
764 return mIcon;
765 }
766
767 @Override
768 public int getPosition() {
769 return mPosition;
770 }
771
772 public void setPosition(int position) {
773 mPosition = position;
774 }
775
776 @Override
777 public CharSequence getText() {
778 return mText;
779 }
780
781 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700782 public Tab setIcon(Drawable icon) {
Adam Powell661c9082010-07-02 10:09:44 -0700783 mIcon = icon;
Adam Powell9ab97872010-10-26 21:47:29 -0700784 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700785 }
786
787 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800788 public Tab setIcon(int resId) {
789 return setIcon(mContext.getResources().getDrawable(resId));
790 }
791
792 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700793 public Tab setText(CharSequence text) {
Adam Powell661c9082010-07-02 10:09:44 -0700794 mText = text;
Adam Powell9ab97872010-10-26 21:47:29 -0700795 return this;
Adam Powell661c9082010-07-02 10:09:44 -0700796 }
797
798 @Override
Adam Powell32555f32010-11-17 13:49:22 -0800799 public Tab setText(int resId) {
800 return setText(mContext.getResources().getText(resId));
801 }
802
803 @Override
Adam Powell661c9082010-07-02 10:09:44 -0700804 public void select() {
805 selectTab(this);
Adam Powell89e06452010-06-23 20:24:52 -0700806 }
807 }
Adam Powell9ab97872010-10-26 21:47:29 -0700808
809 @Override
810 public void setCustomView(View view) {
811 mActionView.setCustomNavigationView(view);
812 }
813
814 @Override
815 public void setCustomView(View view, LayoutParams layoutParams) {
816 view.setLayoutParams(layoutParams);
817 mActionView.setCustomNavigationView(view);
818 }
819
820 @Override
Adam Powell8515ee82010-11-30 14:09:55 -0800821 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
Adam Powell9ab97872010-10-26 21:47:29 -0700822 mActionView.setDropdownAdapter(adapter);
823 mActionView.setCallback(callback);
824 }
825
826 @Override
827 public int getSelectedNavigationIndex() {
828 switch (mActionView.getNavigationMode()) {
829 case NAVIGATION_MODE_TABS:
Adam Powell04587962010-11-11 22:15:07 -0800830 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
Adam Powell9ab97872010-10-26 21:47:29 -0700831 case NAVIGATION_MODE_LIST:
832 return mActionView.getDropdownSelectedPosition();
833 default:
834 return -1;
835 }
836 }
837
838 @Override
839 public int getNavigationItemCount() {
840 switch (mActionView.getNavigationMode()) {
841 case NAVIGATION_MODE_TABS:
842 return mTabs.size();
843 case NAVIGATION_MODE_LIST:
844 SpinnerAdapter adapter = mActionView.getDropdownAdapter();
845 return adapter != null ? adapter.getCount() : 0;
846 default:
847 return 0;
848 }
849 }
850
851 @Override
Adam Powell0c24a552010-11-03 16:44:11 -0700852 public int getTabCount() {
853 return mTabs.size();
854 }
855
856 @Override
Adam Powell9ab97872010-10-26 21:47:29 -0700857 public void setNavigationMode(int mode) {
Adam Powell0c24a552010-11-03 16:44:11 -0700858 final int oldMode = mActionView.getNavigationMode();
859 switch (oldMode) {
860 case NAVIGATION_MODE_TABS:
861 mSavedTabPosition = getSelectedNavigationIndex();
862 selectTab(null);
Adam Powelldae78242011-04-25 15:23:41 -0700863 if (!mActionView.hasEmbeddedTabs()) {
864 mExternalTabView.setVisibility(View.GONE);
865 }
Adam Powell0c24a552010-11-03 16:44:11 -0700866 break;
867 }
Adam Powell9ab97872010-10-26 21:47:29 -0700868 mActionView.setNavigationMode(mode);
Adam Powell0c24a552010-11-03 16:44:11 -0700869 switch (mode) {
870 case NAVIGATION_MODE_TABS:
Adam Powelldae78242011-04-25 15:23:41 -0700871 if (!mActionView.hasEmbeddedTabs()) {
872 mExternalTabView.setVisibility(View.VISIBLE);
873 }
Adam Powell0c24a552010-11-03 16:44:11 -0700874 if (mSavedTabPosition != INVALID_POSITION) {
875 setSelectedNavigationItem(mSavedTabPosition);
876 mSavedTabPosition = INVALID_POSITION;
877 }
878 break;
879 }
Adam Powell9ab97872010-10-26 21:47:29 -0700880 }
881
882 @Override
883 public Tab getTabAt(int index) {
884 return mTabs.get(index);
885 }
Adam Powell0c24a552010-11-03 16:44:11 -0700886
Adam Powell0c24a552010-11-03 16:44:11 -0700887
Adam Powell1969b872011-03-22 11:52:48 -0700888 @Override
889 public void setIcon(int resId) {
Adam Powell45c515b2011-04-21 18:50:20 -0700890 mActionView.setIcon(resId);
Adam Powell1969b872011-03-22 11:52:48 -0700891 }
Adam Powell0c24a552010-11-03 16:44:11 -0700892
Adam Powell1969b872011-03-22 11:52:48 -0700893 @Override
894 public void setIcon(Drawable icon) {
895 mActionView.setIcon(icon);
896 }
897
898 @Override
899 public void setLogo(int resId) {
Adam Powell45c515b2011-04-21 18:50:20 -0700900 mActionView.setLogo(resId);
Adam Powell1969b872011-03-22 11:52:48 -0700901 }
902
903 @Override
904 public void setLogo(Drawable logo) {
905 mActionView.setLogo(logo);
Adam Powell0c24a552010-11-03 16:44:11 -0700906 }
Adam Powell89e06452010-06-23 20:24:52 -0700907}