Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6bfab4e4 authored by Alan Viverette's avatar Alan Viverette Committed by Android (Google) Code Review
Browse files

Merge "Clean up TabWidget"

parents 99ba7ad7 7eb09d15
Loading
Loading
Loading
Loading
+102 −93
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

package android.widget;

import android.R;
import com.android.internal.R;

import android.annotation.DrawableRes;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -33,14 +35,16 @@ import android.view.accessibility.AccessibilityEvent;
/**
 *
 * Displays a list of tab labels representing each page in the parent's tab
 * collection. The container object for this widget is
 * {@link android.widget.TabHost TabHost}. When the user selects a tab, this
 * object sends a message to the parent container, TabHost, to tell it to switch
 * the displayed page. You typically won't use many methods directly on this
 * object. The container TabHost is used to add labels, add the callback
 * handler, and manage callbacks. You might call this object to iterate the list
 * of tabs, or to tweak the layout of the tab list, but most methods should be
 * called on the containing TabHost object.
 * collection.
 * <p>
 * The container object for this widget is {@link android.widget.TabHost TabHost}.
 * When the user selects a tab, this object sends a message to the parent
 * container, TabHost, to tell it to switch the displayed page. You typically
 * won't use many methods directly on this object. The container TabHost is
 * used to add labels, add the callback handler, and manage callbacks. You
 * might call this object to iterate the list of tabs, or to tweak the layout
 * of the tab list, but most methods should be called on the containing TabHost
 * object.
 *
 * @attr ref android.R.styleable#TabWidget_divider
 * @attr ref android.R.styleable#TabWidget_tabStripEnabled
@@ -48,6 +52,8 @@ import android.view.accessibility.AccessibilityEvent;
 * @attr ref android.R.styleable#TabWidget_tabStripRight
 */
public class TabWidget extends LinearLayout implements OnFocusChangeListener {
    private final Rect mBounds = new Rect();

    private OnTabSelectionChanged mSelectionChangedListener;

    // This value will be set to 0 as soon as the first tab is added to TabHost.
@@ -59,9 +65,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
    private boolean mDrawBottomStrips = true;
    private boolean mStripMoved;

    private final Rect mBounds = new Rect();

    // When positive, the widths and heights of tabs will be imposed so that they fit in parent
    // When positive, the widths and heights of tabs will be imposed so that
    // they fit in parent.
    private int mImposedTabsHeight = -1;
    private int[] mImposedTabWidths;

@@ -81,20 +86,48 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
        super(context, attrs, defStyleAttr, defStyleRes);

        final TypedArray a = context.obtainStyledAttributes(
                attrs, com.android.internal.R.styleable.TabWidget, defStyleAttr, defStyleRes);
                attrs, R.styleable.TabWidget, defStyleAttr, defStyleRes);

        mDrawBottomStrips = a.getBoolean(R.styleable.TabWidget_tabStripEnabled, mDrawBottomStrips);

        // Tests the target SDK version, as set in the Manifest. Could not be
        // set using styles.xml in a values-v? directory which targets the
        // current platform SDK version instead.
        final boolean isTargetSdkDonutOrLower =
                context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT;

        setStripEnabled(a.getBoolean(R.styleable.TabWidget_tabStripEnabled, true));
        setLeftStripDrawable(a.getDrawable(R.styleable.TabWidget_tabStripLeft));
        setRightStripDrawable(a.getDrawable(R.styleable.TabWidget_tabStripRight));
        final boolean hasExplicitLeft = a.hasValueOrEmpty(R.styleable.TabWidget_tabStripLeft);
        if (hasExplicitLeft) {
            mLeftStrip = a.getDrawable(R.styleable.TabWidget_tabStripLeft);
        } else if (isTargetSdkDonutOrLower) {
            mLeftStrip = context.getDrawable(R.drawable.tab_bottom_left_v4);
        } else {
            mLeftStrip = context.getDrawable(R.drawable.tab_bottom_left);
        }

        final boolean hasExplicitRight = a.hasValueOrEmpty(R.styleable.TabWidget_tabStripRight);
        if (hasExplicitRight) {
            mRightStrip = a.getDrawable(R.styleable.TabWidget_tabStripRight);
        } else if (isTargetSdkDonutOrLower) {
            mRightStrip = context.getDrawable(R.drawable.tab_bottom_right_v4);
        } else {
            mRightStrip = context.getDrawable(R.drawable.tab_bottom_right);
        }

        a.recycle();

        initTabWidget();
        setChildrenDrawingOrderEnabled(true);

        // Deal with focus, as we don't want the focus to go by default
        // to a tab other than the current tab
        setFocusable(true);
        setOnFocusChangeListener(this);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mStripMoved = true;

        super.onSizeChanged(w, h, oldw, oldh);
    }

@@ -115,44 +148,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
        }
    }

    private void initTabWidget() {
        setChildrenDrawingOrderEnabled(true);

        final Context context = mContext;

        // Tests the target Sdk version, as set in the Manifest. Could not be set using styles.xml
        // in a values-v? directory which targets the current platform Sdk version instead.
        if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
            // Donut apps get old color scheme
            if (mLeftStrip == null) {
                mLeftStrip = context.getDrawable(
                        com.android.internal.R.drawable.tab_bottom_left_v4);
            }
            if (mRightStrip == null) {
                mRightStrip = context.getDrawable(
                        com.android.internal.R.drawable.tab_bottom_right_v4);
            }
        } else {
            // Use modern color scheme for Eclair and beyond
            if (mLeftStrip == null) {
                mLeftStrip = context.getDrawable(
                        com.android.internal.R.drawable.tab_bottom_left);
            }
            if (mRightStrip == null) {
                mRightStrip = context.getDrawable(
                        com.android.internal.R.drawable.tab_bottom_right);
            }
        }

        // Deal with focus, as we don't want the focus to go by default
        // to a tab other than the current tab
        setFocusable(true);
        setOnFocusChangeListener(this);
    }

    @Override
    void measureChildBeforeLayout(View child, int childIndex,
            int widthMeasureSpec, int totalWidth,
    void measureChildBeforeLayout(View child, int childIndex, int widthMeasureSpec, int totalWidth,
            int heightMeasureSpec, int totalHeight) {
        if (!isMeasureWithLargestChildEnabled() && mImposedTabsHeight >= 0) {
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -209,7 +206,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
            }
        }

        // Measure again, this time with imposed tab widths and respecting initial spec request
        // Measure again, this time with imposed tab widths and respecting
        // initial spec request.
        super.measureHorizontal(widthMeasureSpec, heightMeasureSpec);
    }

@@ -225,7 +223,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {

    /**
     * Returns the number of tab indicator views.
     * @return the number of tab indicator views.
     *
     * @return the number of tab indicator views
     */
    public int getTabCount() {
        return getChildCount();
@@ -233,59 +232,70 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {

    /**
     * Sets the drawable to use as a divider between the tab indicators.
     *
     * @param drawable the divider drawable
     * @attr ref android.R.styleable#TabWidget_divider
     */
    @Override
    public void setDividerDrawable(Drawable drawable) {
    public void setDividerDrawable(@Nullable Drawable drawable) {
        super.setDividerDrawable(drawable);
    }

    /**
     * Sets the drawable to use as a divider between the tab indicators.
     * @param resId the resource identifier of the drawable to use as a
     * divider.
     *
     * @param resId the resource identifier of the drawable to use as a divider
     * @attr ref android.R.styleable#TabWidget_divider
     */
    public void setDividerDrawable(@DrawableRes int resId) {
        setDividerDrawable(mContext.getDrawable(resId));
    }

    /**
     * Sets the drawable to use as the left part of the strip below the
     * tab indicators.
     * Sets the drawable to use as the left part of the strip below the tab
     * indicators.
     *
     * @param drawable the left strip drawable
     * @attr ref android.R.styleable#TabWidget_tabStripLeft
     */
    public void setLeftStripDrawable(Drawable drawable) {
    public void setLeftStripDrawable(@Nullable Drawable drawable) {
        mLeftStrip = drawable;
        requestLayout();
        invalidate();
    }

    /**
     * Sets the drawable to use as the left part of the strip below the
     * tab indicators.
     * @param resId the resource identifier of the drawable to use as the
     * left strip drawable
     * Sets the drawable to use as the left part of the strip below the tab
     * indicators.
     *
     * @param resId the resource identifier of the drawable to use as the left
     *              strip drawable
     * @attr ref android.R.styleable#TabWidget_tabStripLeft
     */
    public void setLeftStripDrawable(@DrawableRes int resId) {
        setLeftStripDrawable(mContext.getDrawable(resId));
    }

    /**
     * Sets the drawable to use as the right part of the strip below the
     * tab indicators.
     * Sets the drawable to use as the right part of the strip below the tab
     * indicators.
     *
     * @param drawable the right strip drawable
     * @attr ref android.R.styleable#TabWidget_tabStripRight
     */
    public void setRightStripDrawable(Drawable drawable) {
    public void setRightStripDrawable(@Nullable Drawable drawable) {
        mRightStrip = drawable;
        requestLayout();
        invalidate();
    }

    /**
     * Sets the drawable to use as the right part of the strip below the
     * tab indicators.
     * @param resId the resource identifier of the drawable to use as the
     * right strip drawable
     * Sets the drawable to use as the right part of the strip below the tab
     * indicators.
     *
     * @param resId the resource identifier of the drawable to use as the right
     *              strip drawable
     * @attr ref android.R.styleable#TabWidget_tabStripRight
     */
    public void setRightStripDrawable(@DrawableRes int resId) {
        setRightStripDrawable(mContext.getDrawable(resId));
@@ -360,13 +370,14 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {

    /**
     * Sets the current tab.
     * <p>
     * This method is used to bring a tab to the front of the Widget,
     * and is used to post to the rest of the UI that a different tab
     * has been brought to the foreground.
     *
     * <p>
     * Note, this is separate from the traditional "focus" that is
     * employed from the view logic.
     *
     * <p>
     * For instance, if we have a list in a tabbed view, a user may be
     * navigating up and down the list, moving the UI focus (orange
     * highlighting) through the list items.  The cursor movement does
@@ -374,15 +385,14 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
     * scrolled through is all on the same tab.  The selected tab only
     * changes when we navigate between tabs (moving from the list view
     * to the next tabbed view, in this example).
     *
     * <p>
     * To move both the focus AND the selected tab at once, please use
     * {@link #setCurrentTab}. Normally, the view logic takes care of
     * adjusting the focus, so unless you're circumventing the UI,
     * you'll probably just focus your interest here.
     *
     *  @param index The tab that you want to indicate as the selected
     *  tab (tab brought to the front of the widget)
     *
     * @param index the index of the tab that you want to indicate as the
     *              selected tab (tab brought to the front of the widget)
     * @see #focusCurrentTab
     */
    public void setCurrentTab(int index) {
@@ -473,7 +483,7 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {

        final int count = getTabCount();
        for (int i = 0; i < count; i++) {
            View child = getChildTabViewAt(i);
            final View child = getChildTabViewAt(i);
            child.setEnabled(enabled);
        }
    }
@@ -482,8 +492,7 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
    public void addView(View child) {
        if (child.getLayoutParams() == null) {
            final LinearLayout.LayoutParams lp = new LayoutParams(
                    0,
                    ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
                    0, ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
            lp.setMargins(0, 0, 0, 0);
            child.setLayoutParams(lp);
        }
@@ -507,13 +516,13 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
    }

    /**
     * Provides a way for {@link TabHost} to be notified that the user clicked on a tab indicator.
     * Provides a way for {@link TabHost} to be notified that the user clicked
     * on a tab indicator.
     */
    void setTabSelectionListener(OnTabSelectionChanged listener) {
        mSelectionChangedListener = listener;
    }

    /** {@inheritDoc} */
    public void onFocusChange(View v, boolean hasFocus) {
        if (v == this && hasFocus && getTabCount() > 0) {
            getChildTabViewAt(mSelectedTab).requestFocus();
@@ -540,7 +549,6 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {

    // registered with each tab indicator so we can notify tab host
    private class TabClickListener implements OnClickListener {

        private final int mTabIndex;

        private TabClickListener(int tabIndex) {
@@ -553,17 +561,18 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
    }

    /**
     * Let {@link TabHost} know that the user clicked on a tab indicator.
     * Lets {@link TabHost} know that the user clicked on a tab indicator.
     */
    static interface OnTabSelectionChanged {
    interface OnTabSelectionChanged {
        /**
         * Informs the TabHost which tab was selected. It also indicates
         * if the tab was clicked/pressed or just focused into.
         *
         * @param tabIndex index of the tab that was selected
         * @param clicked whether the selection changed due to a touch/click
         * or due to focus entering the tab through navigation. Pass true
         * if it was due to a press/click and false otherwise.
         * @param clicked whether the selection changed due to a touch/click or
         *                due to focus entering the tab through navigation.
         *                {@code true} if it was due to a press/click and
         *                {@code false} otherwise.
         */
        void onTabSelectionChanged(int tabIndex, boolean clicked);
    }