ActionBarView.java revision 89edde3efad66063ff6108475976352c0c4e5fdb
1/*
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.widget;
18
19import com.android.internal.R;
20import com.android.internal.view.menu.ActionMenuItem;
21import com.android.internal.view.menu.ActionMenuView;
22import com.android.internal.view.menu.MenuBuilder;
23
24import android.app.ActionBar;
25import android.app.ActionBar.NavigationCallback;
26import android.app.Activity;
27import android.content.Context;
28import android.content.pm.ApplicationInfo;
29import android.content.pm.PackageManager;
30import android.content.res.TypedArray;
31import android.graphics.PorterDuff;
32import android.graphics.PorterDuffColorFilter;
33import android.graphics.drawable.Drawable;
34import android.text.TextUtils.TruncateAt;
35import android.util.AttributeSet;
36import android.util.DisplayMetrics;
37import android.view.ActionMode;
38import android.view.Gravity;
39import android.view.LayoutInflater;
40import android.view.Menu;
41import android.view.View;
42import android.view.ViewGroup;
43import android.widget.AdapterView;
44import android.widget.HorizontalScrollView;
45import android.widget.ImageView;
46import android.widget.LinearLayout;
47import android.widget.Spinner;
48import android.widget.SpinnerAdapter;
49import android.widget.TextView;
50
51/**
52 * @hide
53 */
54public class ActionBarView extends ViewGroup {
55    private static final String TAG = "ActionBarView";
56
57    /**
58     * Display options applied by default
59     */
60    public static final int DISPLAY_DEFAULT = 0;
61
62    /**
63     * Display options that require re-layout as opposed to a simple invalidate
64     */
65    private static final int DISPLAY_RELAYOUT_MASK =
66            ActionBar.DISPLAY_HIDE_HOME |
67            ActionBar.DISPLAY_USE_LOGO;
68
69    private final int mContentHeight;
70
71    private int mNavigationMode;
72    private int mDisplayOptions;
73    private CharSequence mTitle;
74    private CharSequence mSubtitle;
75    private Drawable mIcon;
76    private Drawable mLogo;
77    private Drawable mDivider;
78
79    private ImageView mIconView;
80    private ImageView mLogoView;
81    private LinearLayout mTitleLayout;
82    private TextView mTitleView;
83    private TextView mSubtitleView;
84    private Spinner mSpinner;
85    private HorizontalScrollView mTabScrollView;
86    private LinearLayout mTabLayout;
87    private View mCustomNavView;
88
89    private int mTitleStyleRes;
90    private int mSubtitleStyleRes;
91
92    private boolean mShowMenu;
93    private boolean mUserTitle;
94
95    private MenuBuilder mOptionsMenu;
96    private ActionMenuView mMenuView;
97
98    private ActionBarContextView mContextView;
99
100    private ActionMenuItem mLogoNavItem;
101
102    private NavigationCallback mCallback;
103
104    private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
105            new AdapterView.OnItemSelectedListener() {
106        public void onItemSelected(AdapterView parent, View view, int position, long id) {
107            if (mCallback != null) {
108                mCallback.onNavigationItemSelected(position, id);
109            }
110        }
111        public void onNothingSelected(AdapterView parent) {
112            // Do nothing
113        }
114    };
115
116    private OnClickListener mHomeClickListener = null;
117
118    private OnClickListener mTabClickListener = null;
119
120    public ActionBarView(Context context, AttributeSet attrs) {
121        super(context, attrs);
122
123        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar);
124
125        final int colorFilter = a.getColor(R.styleable.ActionBar_colorFilter, 0);
126
127        if (colorFilter != 0) {
128            final Drawable d = getBackground();
129            d.setDither(true);
130            d.setColorFilter(new PorterDuffColorFilter(colorFilter, PorterDuff.Mode.OVERLAY));
131        }
132
133        ApplicationInfo info = context.getApplicationInfo();
134        PackageManager pm = context.getPackageManager();
135        mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode,
136                ActionBar.NAVIGATION_MODE_STANDARD);
137        mTitle = a.getText(R.styleable.ActionBar_title);
138        mSubtitle = a.getText(R.styleable.ActionBar_subtitle);
139        mDisplayOptions = a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT);
140
141        mLogo = a.getDrawable(R.styleable.ActionBar_logo);
142        if (mLogo == null) {
143            mLogo = info.loadLogo(pm);
144        }
145        mIcon = a.getDrawable(R.styleable.ActionBar_icon);
146        if (mIcon == null) {
147            mIcon = info.loadIcon(pm);
148        }
149
150        Drawable background = a.getDrawable(R.styleable.ActionBar_background);
151        if (background != null) {
152            setBackgroundDrawable(background);
153        }
154
155        mTitleStyleRes = a.getResourceId(R.styleable.ActionBar_titleTextStyle, 0);
156        mSubtitleStyleRes = a.getResourceId(R.styleable.ActionBar_subtitleTextStyle, 0);
157
158        final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0);
159        if (customNavId != 0) {
160            LayoutInflater inflater = LayoutInflater.from(context);
161            mCustomNavView = (View) inflater.inflate(customNavId, null);
162            mNavigationMode = ActionBar.NAVIGATION_MODE_CUSTOM;
163        }
164
165        mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
166
167        mDivider = a.getDrawable(R.styleable.ActionBar_divider);
168
169        a.recycle();
170
171        if (mLogo != null || mIcon != null || mTitle != null) {
172            mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
173            mHomeClickListener = new OnClickListener() {
174                public void onClick(View v) {
175                    Context context = getContext();
176                    if (context instanceof Activity) {
177                        Activity activity = (Activity) context;
178                        activity.onOptionsItemSelected(mLogoNavItem);
179                    }
180                }
181            };
182        }
183    }
184
185    @Override
186    public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
187        // No starting an action mode for an action bar child! (Where would it go?)
188        return null;
189    }
190
191    public void setCallback(NavigationCallback callback) {
192        mCallback = callback;
193    }
194
195    public void setMenu(Menu menu) {
196        MenuBuilder builder = (MenuBuilder) menu;
197        mOptionsMenu = builder;
198        if (mMenuView != null) {
199            removeView(mMenuView);
200        }
201        final ActionMenuView menuView = (ActionMenuView) builder.getMenuView(
202                MenuBuilder.TYPE_ACTION_BUTTON, null);
203        final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
204                LayoutParams.MATCH_PARENT);
205        menuView.setLayoutParams(layoutParams);
206        addView(menuView);
207        mMenuView = menuView;
208    }
209
210    public boolean showOverflowMenu() {
211        if (mMenuView != null) {
212            return mMenuView.showOverflowMenu();
213        }
214        return false;
215    }
216
217    public void postShowOverflowMenu() {
218        post(new Runnable() {
219            public void run() {
220                showOverflowMenu();
221            }
222        });
223    }
224
225    public boolean hideOverflowMenu() {
226        if (mMenuView != null) {
227            return mMenuView.hideOverflowMenu();
228        }
229        return false;
230    }
231
232    public boolean isOverflowMenuShowing() {
233        if (mMenuView != null) {
234            return mMenuView.isOverflowMenuShowing();
235        }
236        return false;
237    }
238
239    public boolean isOverflowReserved() {
240        return mMenuView != null && mMenuView.isOverflowReserved();
241    }
242
243    public void setCustomNavigationView(View view) {
244        mCustomNavView = view;
245        if (view != null) {
246            setNavigationMode(ActionBar.NAVIGATION_MODE_CUSTOM);
247        }
248    }
249
250    public CharSequence getTitle() {
251        return mTitle;
252    }
253
254    /**
255     * Set the action bar title. This will always replace or override window titles.
256     * @param title Title to set
257     *
258     * @see #setWindowTitle(CharSequence)
259     */
260    public void setTitle(CharSequence title) {
261        mUserTitle = true;
262        setTitleImpl(title);
263    }
264
265    /**
266     * Set the window title. A window title will always be replaced or overridden by a user title.
267     * @param title Title to set
268     *
269     * @see #setTitle(CharSequence)
270     */
271    public void setWindowTitle(CharSequence title) {
272        if (!mUserTitle) {
273            setTitleImpl(title);
274        }
275    }
276
277    private void setTitleImpl(CharSequence title) {
278        mTitle = title;
279        if (mTitleView != null) {
280            mTitleView.setText(title);
281        }
282        if (mLogoNavItem != null) {
283            mLogoNavItem.setTitle(title);
284        }
285    }
286
287    public CharSequence getSubtitle() {
288        return mSubtitle;
289    }
290
291    public void setSubtitle(CharSequence subtitle) {
292        mSubtitle = subtitle;
293        if (mSubtitleView != null) {
294            mSubtitleView.setText(subtitle);
295        }
296    }
297
298    public void setDisplayOptions(int options) {
299        final int flagsChanged = options ^ mDisplayOptions;
300        mDisplayOptions = options;
301        if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
302            final int vis = (options & ActionBar.DISPLAY_HIDE_HOME) != 0 ? GONE : VISIBLE;
303            if (mLogoView != null) {
304                mLogoView.setVisibility(vis);
305            }
306            if (mIconView != null) {
307                mIconView.setVisibility(vis);
308            }
309
310            requestLayout();
311        } else {
312            invalidate();
313        }
314    }
315
316    public void setNavigationMode(int mode) {
317        final int oldMode = mNavigationMode;
318        if (mode != oldMode) {
319            switch (oldMode) {
320            case ActionBar.NAVIGATION_MODE_STANDARD:
321                if (mTitleLayout != null) {
322                    removeView(mTitleLayout);
323                    mTitleLayout = null;
324                    mTitleView = null;
325                    mSubtitleView = null;
326                }
327                break;
328            case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
329                if (mSpinner != null) {
330                    removeView(mSpinner);
331                    mSpinner = null;
332                }
333                break;
334            case ActionBar.NAVIGATION_MODE_CUSTOM:
335                if (mCustomNavView != null) {
336                    removeView(mCustomNavView);
337                    mCustomNavView = null;
338                }
339                break;
340            case ActionBar.NAVIGATION_MODE_TABS:
341                if (mTabLayout != null) {
342                    removeView(mTabScrollView);
343                    mTabLayout = null;
344                    mTabScrollView = null;
345                }
346            }
347
348            switch (mode) {
349            case ActionBar.NAVIGATION_MODE_STANDARD:
350                initTitle();
351                break;
352            case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
353                mSpinner = new Spinner(mContext, null,
354                        com.android.internal.R.attr.actionDropDownStyle);
355                mSpinner.setOnItemSelectedListener(mNavItemSelectedListener);
356                addView(mSpinner);
357                break;
358            case ActionBar.NAVIGATION_MODE_CUSTOM:
359                addView(mCustomNavView);
360                break;
361            case ActionBar.NAVIGATION_MODE_TABS:
362                mTabScrollView = new HorizontalScrollView(getContext());
363                mTabLayout = new LinearLayout(getContext(), null,
364                        com.android.internal.R.attr.actionBarTabBarStyle);
365                mTabScrollView.addView(mTabLayout);
366                addView(mTabScrollView);
367                break;
368            }
369            mNavigationMode = mode;
370            requestLayout();
371        }
372    }
373
374    public void setDropdownAdapter(SpinnerAdapter adapter) {
375        mSpinner.setAdapter(adapter);
376    }
377
378    public void setDropdownSelectedPosition(int position) {
379        mSpinner.setSelection(position);
380    }
381
382    public int getDropdownSelectedPosition() {
383        return mSpinner.getSelectedItemPosition();
384    }
385
386    public View getCustomNavigationView() {
387        return mCustomNavView;
388    }
389
390    public int getNavigationMode() {
391        return mNavigationMode;
392    }
393
394    public int getDisplayOptions() {
395        return mDisplayOptions;
396    }
397
398    private TabView createTabView(ActionBar.Tab tab) {
399        final TabView tabView = new TabView(getContext(), tab);
400        tabView.setFocusable(true);
401
402        if (mTabClickListener == null) {
403            mTabClickListener = new TabClickListener();
404        }
405        tabView.setOnClickListener(mTabClickListener);
406        return tabView;
407    }
408
409    public void addTab(ActionBar.Tab tab) {
410        final boolean isFirst = mTabLayout.getChildCount() == 0;
411        View tabView = createTabView(tab);
412        mTabLayout.addView(tabView);
413        if (isFirst) {
414            tabView.setSelected(true);
415        }
416    }
417
418    public void addTab(ActionBar.Tab tab, int position) {
419        final boolean isFirst = mTabLayout.getChildCount() == 0;
420        final TabView tabView = createTabView(tab);
421        mTabLayout.addView(tabView, position);
422        if (isFirst) {
423            tabView.setSelected(true);
424        }
425    }
426
427    public void removeTabAt(int position) {
428        mTabLayout.removeViewAt(position);
429    }
430
431    @Override
432    protected LayoutParams generateDefaultLayoutParams() {
433        // Used by custom nav views if they don't supply layout params. Everything else
434        // added to an ActionBarView should have them already.
435        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
436    }
437
438    @Override
439    protected void onFinishInflate() {
440        super.onFinishInflate();
441
442        if ((mDisplayOptions & ActionBar.DISPLAY_HIDE_HOME) == 0) {
443            if (mLogo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
444                mLogoView = new ImageView(getContext(), null,
445                        com.android.internal.R.attr.actionButtonStyle);
446                mLogoView.setAdjustViewBounds(true);
447                mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
448                        LayoutParams.MATCH_PARENT));
449                mLogoView.setImageDrawable(mLogo);
450                mLogoView.setClickable(true);
451                mLogoView.setFocusable(true);
452                mLogoView.setOnClickListener(mHomeClickListener);
453                addView(mLogoView);
454            } else if (mIcon != null) {
455                mIconView = new ImageView(getContext(), null,
456                        com.android.internal.R.attr.actionButtonStyle);
457                mIconView.setAdjustViewBounds(true);
458                mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
459                        LayoutParams.MATCH_PARENT));
460                mIconView.setImageDrawable(mIcon);
461                mIconView.setClickable(true);
462                mIconView.setFocusable(true);
463                mIconView.setOnClickListener(mHomeClickListener);
464                addView(mIconView);
465            }
466        }
467
468        switch (mNavigationMode) {
469        case ActionBar.NAVIGATION_MODE_STANDARD:
470            if (mLogoView == null) {
471                initTitle();
472            }
473            break;
474
475        case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
476            throw new UnsupportedOperationException(
477                    "Inflating dropdown list navigation isn't supported yet!");
478
479        case ActionBar.NAVIGATION_MODE_TABS:
480            throw new UnsupportedOperationException(
481                    "Inflating tab navigation isn't supported yet!");
482
483        case ActionBar.NAVIGATION_MODE_CUSTOM:
484            if (mCustomNavView != null) {
485                addView(mCustomNavView);
486            }
487            break;
488        }
489    }
490
491    private void initTitle() {
492        LayoutInflater inflater = LayoutInflater.from(getContext());
493        mTitleLayout = (LinearLayout) inflater.inflate(R.layout.action_bar_title_item, null);
494        mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title);
495        mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
496
497        if (mTitleStyleRes != 0) {
498            mTitleView.setTextAppearance(mContext, mTitleStyleRes);
499        }
500        if (mTitle != null) {
501            mTitleView.setText(mTitle);
502        }
503
504        if (mSubtitleStyleRes != 0) {
505            mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes);
506        }
507        if (mSubtitle != null) {
508            mSubtitleView.setText(mSubtitle);
509            mSubtitleView.setVisibility(VISIBLE);
510        }
511
512        addView(mTitleLayout);
513    }
514
515    public void setTabSelected(int position) {
516        final int tabCount = mTabLayout.getChildCount();
517        for (int i = 0; i < tabCount; i++) {
518            final View child = mTabLayout.getChildAt(i);
519            child.setSelected(i == position);
520        }
521    }
522
523    public void setContextView(ActionBarContextView view) {
524        mContextView = view;
525    }
526
527    @Override
528    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
529        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
530        if (widthMode != MeasureSpec.EXACTLY) {
531            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
532                    "with android:layout_width=\"match_parent\" (or fill_parent)");
533        }
534
535        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
536        if (heightMode != MeasureSpec.AT_MOST) {
537            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
538                    "with android:layout_height=\"wrap_content\"");
539        }
540
541        int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
542
543        int maxHeight = mContentHeight > 0 ?
544                mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
545
546        final int verticalPadding = getPaddingTop() + getPaddingBottom();
547        int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
548        final int height = maxHeight - verticalPadding;
549        final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
550
551        if (mLogoView != null && mLogoView.getVisibility() != GONE) {
552            availableWidth = measureChildView(mLogoView, availableWidth, childSpecHeight, 0);
553        }
554        if (mIconView != null && mIconView.getVisibility() != GONE) {
555            availableWidth = measureChildView(mIconView, availableWidth, childSpecHeight, 0);
556        }
557
558        if (mMenuView != null) {
559            availableWidth = measureChildView(mMenuView, availableWidth,
560                    childSpecHeight, 0);
561        }
562
563        switch (mNavigationMode) {
564        case ActionBar.NAVIGATION_MODE_STANDARD:
565            if (mTitleLayout != null) {
566                measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
567            }
568            break;
569        case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
570            if (mSpinner != null) {
571                mSpinner.measure(
572                        MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
573                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
574            }
575            break;
576        case ActionBar.NAVIGATION_MODE_CUSTOM:
577            if (mCustomNavView != null) {
578                LayoutParams lp = mCustomNavView.getLayoutParams();
579                final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
580                        MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
581                final int customNavWidth = lp.width >= 0 ?
582                        Math.min(lp.width, availableWidth) : availableWidth;
583
584                // If the action bar is wrapping to its content height, don't allow a custom
585                // view to MATCH_PARENT.
586                int customNavHeightMode;
587                if (mContentHeight <= 0) {
588                    customNavHeightMode = MeasureSpec.AT_MOST;
589                } else {
590                    customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
591                            MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
592                }
593                final int customNavHeight = lp.height >= 0 ?
594                        Math.min(lp.height, height) : height;
595                mCustomNavView.measure(
596                        MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode),
597                        MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode));
598            }
599            break;
600        case ActionBar.NAVIGATION_MODE_TABS:
601            if (mTabScrollView != null) {
602                mTabScrollView.measure(
603                        MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
604                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
605            }
606            break;
607        }
608
609        if (mContentHeight <= 0) {
610            int measuredHeight = 0;
611            final int count = getChildCount();
612            for (int i = 0; i < count; i++) {
613                View v = getChildAt(i);
614                int paddedViewHeight = v.getMeasuredHeight() + verticalPadding;
615                if (paddedViewHeight > measuredHeight) {
616                    measuredHeight = paddedViewHeight;
617                }
618            }
619            setMeasuredDimension(contentWidth, measuredHeight);
620        } else {
621            setMeasuredDimension(contentWidth, maxHeight);
622        }
623
624        if (mContextView != null) {
625            mContextView.setHeight(getMeasuredHeight());
626        }
627    }
628
629    private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
630        child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
631                childSpecHeight);
632
633        availableWidth -= child.getMeasuredWidth();
634        availableWidth -= spacing;
635
636        return availableWidth;
637    }
638
639    @Override
640    protected void onLayout(boolean changed, int l, int t, int r, int b) {
641        int x = getPaddingLeft();
642        final int y = getPaddingTop();
643        final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
644
645        if (mLogoView != null && mLogoView.getVisibility() != GONE) {
646            x += positionChild(mLogoView, x, y, contentHeight);
647        }
648        if (mIconView != null && mIconView.getVisibility() != GONE) {
649            x += positionChild(mIconView, x, y, contentHeight);
650        }
651
652        switch (mNavigationMode) {
653        case ActionBar.NAVIGATION_MODE_STANDARD:
654            if (mTitleLayout != null) {
655                x += positionChild(mTitleLayout, x, y, contentHeight);
656            }
657            break;
658        case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
659            if (mSpinner != null) {
660                x += positionChild(mSpinner, x, y, contentHeight);
661            }
662            break;
663        case ActionBar.NAVIGATION_MODE_CUSTOM:
664            if (mCustomNavView != null) {
665                x += positionChild(mCustomNavView, x, y, contentHeight);
666            }
667            break;
668        case ActionBar.NAVIGATION_MODE_TABS:
669            if (mTabScrollView != null) {
670                x += positionChild(mTabScrollView, x, y, contentHeight);
671            }
672        }
673
674        x = r - l - getPaddingRight();
675
676        if (mMenuView != null) {
677            x -= positionChildInverse(mMenuView, x, y, contentHeight);
678        }
679    }
680
681    private int positionChild(View child, int x, int y, int contentHeight) {
682        int childWidth = child.getMeasuredWidth();
683        int childHeight = child.getMeasuredHeight();
684        int childTop = y + (contentHeight - childHeight) / 2;
685
686        child.layout(x, childTop, x + childWidth, childTop + childHeight);
687
688        return childWidth;
689    }
690
691    private int positionChildInverse(View child, int x, int y, int contentHeight) {
692        int childWidth = child.getMeasuredWidth();
693        int childHeight = child.getMeasuredHeight();
694        int childTop = y + (contentHeight - childHeight) / 2;
695
696        child.layout(x - childWidth, childTop, x, childTop + childHeight);
697
698        return childWidth;
699    }
700
701    private static class TabView extends LinearLayout {
702        private ActionBar.Tab mTab;
703
704        public TabView(Context context, ActionBar.Tab tab) {
705            super(context, null, com.android.internal.R.attr.actionBarTabStyle);
706            mTab = tab;
707
708            final View custom = tab.getCustomView();
709            if (custom != null) {
710                addView(custom);
711            } else {
712                // TODO Style tabs based on the theme
713
714                final Drawable icon = tab.getIcon();
715                final CharSequence text = tab.getText();
716
717                if (icon != null) {
718                    ImageView iconView = new ImageView(context);
719                    iconView.setImageDrawable(icon);
720                    LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
721                            LayoutParams.WRAP_CONTENT);
722                    lp.gravity = Gravity.CENTER_VERTICAL;
723                    iconView.setLayoutParams(lp);
724                    addView(iconView);
725                }
726
727                if (text != null) {
728                    TextView textView = new TextView(context, null,
729                            com.android.internal.R.attr.actionBarTabTextStyle);
730                    textView.setText(text);
731                    textView.setSingleLine();
732                    textView.setEllipsize(TruncateAt.END);
733                    LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
734                            LayoutParams.WRAP_CONTENT);
735                    lp.gravity = Gravity.CENTER_VERTICAL;
736                    textView.setLayoutParams(lp);
737                    addView(textView);
738                }
739            }
740
741            setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
742                    LayoutParams.MATCH_PARENT, 1));
743        }
744
745        public ActionBar.Tab getTab() {
746            return mTab;
747        }
748    }
749
750    private class TabClickListener implements OnClickListener {
751        public void onClick(View view) {
752            TabView tabView = (TabView) view;
753            tabView.getTab().select();
754            final int tabCount = mTabLayout.getChildCount();
755            for (int i = 0; i < tabCount; i++) {
756                final View child = mTabLayout.getChildAt(i);
757                child.setSelected(child == view);
758            }
759        }
760    }
761}
762