124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller/*
224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller * Copyright (C) 2009 The Android Open Source Project
324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller *
424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller * Licensed under the Apache License, Version 2.0 (the "License");
524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller * you may not use this file except in compliance with the License.
624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller * You may obtain a copy of the License at
724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller *
824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller *      http://www.apache.org/licenses/LICENSE-2.0
924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller *
1024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller * Unless required by applicable law or agreed to in writing, software
1124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller * distributed under the License is distributed on an "AS IS" BASIS,
1224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller * See the License for the specific language governing permissions and
1424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller * limitations under the License.
1524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller */
1624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
1724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerpackage com.android.internal.widget;
1824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
1924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.content.Context;
2024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.content.res.Resources;
2124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.content.res.TypedArray;
2224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.graphics.Rect;
23753401aa471d2fb87ab937c2b02b182ebc215c3aJim Millerimport android.graphics.drawable.Drawable;
24723a725e790d269f32980116e775d3d7f0037865Jeff Sharkeyimport android.os.UserHandle;
2524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.os.Vibrator;
26723a725e790d269f32980116e775d3d7f0037865Jeff Sharkeyimport android.provider.Settings;
2724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.util.AttributeSet;
2824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.util.Log;
2924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.view.Gravity;
3024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.view.MotionEvent;
3124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.view.View;
3224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.view.ViewGroup;
33521d400b230bee5e7b9748f26832c0d0275b8253Jim Millerimport android.view.animation.AlphaAnimation;
34521d400b230bee5e7b9748f26832c0d0275b8253Jim Millerimport android.view.animation.Animation;
35521d400b230bee5e7b9748f26832c0d0275b8253Jim Millerimport android.view.animation.LinearInterpolator;
36521d400b230bee5e7b9748f26832c0d0275b8253Jim Millerimport android.view.animation.TranslateAnimation;
37521d400b230bee5e7b9748f26832c0d0275b8253Jim Millerimport android.view.animation.Animation.AnimationListener;
3824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.widget.ImageView;
3924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.widget.TextView;
4024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport android.widget.ImageView.ScaleType;
4192c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller
4224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerimport com.android.internal.R;
4324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
4424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller/**
4524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller * A special widget containing two Sliders and a threshold for each.  Moving either slider beyond
46425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller * the threshold will cause the registered OnTriggerListener.onTrigger() to be called with
474df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller * whichHandle being {@link OnTriggerListener#LEFT_HANDLE} or {@link OnTriggerListener#RIGHT_HANDLE}
48425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller * Equivalently, selecting a tab will result in a call to
494df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller * {@link OnTriggerListener#onGrabbedStateChange(View, int)} with one of these two states. Releasing
504df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller * the tab will result in whichHandle being {@link OnTriggerListener#NO_HANDLE}.
5124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller *
5224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller */
5324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Millerpublic class SlidingTab extends ViewGroup {
5424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private static final String LOG_TAG = "SlidingTab";
5524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private static final boolean DBG = false;
5624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private static final int HORIZONTAL = 0; // as defined in attrs.xml
5724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private static final int VERTICAL = 1;
5824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
5924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    // TODO: Make these configurable
604df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller    private static final float THRESHOLD = 2.0f / 3.0f;
6124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private static final long VIBRATE_SHORT = 30;
6224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private static final long VIBRATE_LONG = 40;
63521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller    private static final int TRACKING_MARGIN = 50;
64521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller    private static final int ANIM_DURATION = 250; // Time for most animations (in ms)
65521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller    private static final int ANIM_TARGET_TIME = 500; // Time to show targets (in ms)
664f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    private boolean mHoldLeftOnTransition = true;
674f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    private boolean mHoldRightOnTransition = true;
6824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
6924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private OnTriggerListener mOnTriggerListener;
7024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private int mGrabbedState = OnTriggerListener.NO_HANDLE;
7124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private boolean mTriggered = false;
7224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private Vibrator mVibrator;
7392c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller    private final float mDensity; // used to scale dimensions for bitmaps.
7424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
7524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
7624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Either {@link #HORIZONTAL} or {@link #VERTICAL}.
7724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
7892c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller    private final int mOrientation;
7924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
8092c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller    private final Slider mLeftSlider;
8192c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller    private final Slider mRightSlider;
8224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private Slider mCurrentSlider;
8324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private boolean mTracking;
844df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller    private float mThreshold;
8524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private Slider mOtherSlider;
8624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private boolean mAnimating;
8792c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller    private final Rect mTmpRect;
8824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
8924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
904f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller     * Listener used to reset the view when the current animation completes.
914f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller     */
924f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    private final AnimationListener mAnimationDoneListener = new AnimationListener() {
934f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        public void onAnimationStart(Animation animation) {
944f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller
954f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        }
964f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller
974f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        public void onAnimationRepeat(Animation animation) {
984f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller
994f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        }
1004f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller
1014f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        public void onAnimationEnd(Animation animation) {
1024f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller            onAnimationDone();
1034f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        }
1044f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    };
1054f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller
1064f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    /**
10724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Interface definition for a callback to be invoked when a tab is triggered
1084df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller     * by moving it beyond a threshold.
10924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
11024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    public interface OnTriggerListener {
11124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        /**
11224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * The interface was triggered because the user let go of the handle without reaching the
1134df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller         * threshold.
11424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         */
11524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        public static final int NO_HANDLE = 0;
11624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
11724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        /**
11824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * The interface was triggered because the user grabbed the left handle and moved it past
1194df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller         * the threshold.
12024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         */
12124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        public static final int LEFT_HANDLE = 1;
12224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
12324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        /**
12424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * The interface was triggered because the user grabbed the right handle and moved it past
1254df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller         * the threshold.
12624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         */
12724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        public static final int RIGHT_HANDLE = 2;
12824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
12924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        /**
1304df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller         * Called when the user moves a handle beyond the threshold.
13124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         *
13224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param v The view that was triggered.
13324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param whichHandle  Which "dial handle" the user grabbed,
13424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         *        either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}.
13524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         */
13624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void onTrigger(View v, int whichHandle);
13724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
13824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        /**
13924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * Called when the "grabbed state" changes (i.e. when the user either grabs or releases
14024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * one of the handles.)
14124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         *
14224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param v the view that was triggered
14324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param grabbedState the new state: {@link #NO_HANDLE}, {@link #LEFT_HANDLE},
14424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * or {@link #RIGHT_HANDLE}.
14524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         */
14624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void onGrabbedStateChange(View v, int grabbedState);
14724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
14824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
14924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
150425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller     * Simple container class for all things pertinent to a slider.
15124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * A slider consists of 3 Views:
152425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller     *
15324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * {@link #tab} is the tab shown on the screen in the default state.
15424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * {@link #text} is the view revealed as the user slides the tab out.
15524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * {@link #target} is the target the user must drag the slider past to trigger the slider.
15624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     *
15724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
15824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private static class Slider {
15924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        /**
16024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * Tab alignment - determines which side the tab should be drawn on
16124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         */
16224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        public static final int ALIGN_LEFT = 0;
16324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        public static final int ALIGN_RIGHT = 1;
16424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        public static final int ALIGN_TOP = 2;
16524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        public static final int ALIGN_BOTTOM = 3;
166521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        public static final int ALIGN_UNKNOWN = 4;
16724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
16824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        /**
16924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * States for the view.
17024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         */
17124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        private static final int STATE_NORMAL = 0;
17224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        private static final int STATE_PRESSED = 1;
17324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        private static final int STATE_ACTIVE = 2;
17424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
17524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        private final ImageView tab;
17624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        private final TextView text;
17724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        private final ImageView target;
1784df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller        private int currentState = STATE_NORMAL;
179521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        private int alignment = ALIGN_UNKNOWN;
180521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        private int alignment_value;
18124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
18224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        /**
18324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * Constructor
184425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller         *
18524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param parent the container view of this one
18624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param tabId drawable for the tab
18724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param barId drawable for the bar
18824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param targetId drawable for the target
18924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         */
19024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        Slider(ViewGroup parent, int tabId, int barId, int targetId) {
19124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            // Create tab
19224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            tab = new ImageView(parent.getContext());
19324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            tab.setBackgroundResource(tabId);
19424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            tab.setScaleType(ScaleType.CENTER);
19524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            tab.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
19624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    LayoutParams.WRAP_CONTENT));
19724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
19824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            // Create hint TextView
19924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            text = new TextView(parent.getContext());
20024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            text.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
201980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy                    LayoutParams.MATCH_PARENT));
20224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            text.setBackgroundResource(barId);
20324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            text.setTextAppearance(parent.getContext(), R.style.TextAppearance_SlidingTabNormal);
20424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            // hint.setSingleLine();  // Hmm.. this causes the text to disappear off-screen
20524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
20624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            // Create target
20724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            target = new ImageView(parent.getContext());
20824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            target.setImageResource(targetId);
20924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            target.setScaleType(ScaleType.CENTER);
21024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            target.setLayoutParams(
21124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
21224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            target.setVisibility(View.INVISIBLE);
21324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
21424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            parent.addView(target); // this needs to be first - relies on painter's algorithm
21524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            parent.addView(tab);
21624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            parent.addView(text);
21724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
21824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
21924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void setIcon(int iconId) {
22024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            tab.setImageResource(iconId);
22124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
222425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller
22324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void setTabBackgroundResource(int tabId) {
22424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            tab.setBackgroundResource(tabId);
22524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
226425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller
22724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void setBarBackgroundResource(int barId) {
22824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            text.setBackgroundResource(barId);
22924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
230425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller
23124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void setHintText(int resId) {
232425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller            text.setText(resId);
23324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
23424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
23524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void hide() {
236521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            boolean horiz = alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT;
237521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int dx = horiz ? (alignment == ALIGN_LEFT ? alignment_value - tab.getRight()
238521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    : alignment_value - tab.getLeft()) : 0;
239521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int dy = horiz ? 0 : (alignment == ALIGN_TOP ? alignment_value - tab.getBottom()
240521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    : alignment_value - tab.getTop());
241521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
242521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            Animation trans = new TranslateAnimation(0, dx, 0, dy);
243521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            trans.setDuration(ANIM_DURATION);
244521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            trans.setFillAfter(true);
245521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            tab.startAnimation(trans);
246521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            text.startAnimation(trans);
24724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            target.setVisibility(View.INVISIBLE);
24824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
24924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
250521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        void show(boolean animate) {
251521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            text.setVisibility(View.VISIBLE);
252521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            tab.setVisibility(View.VISIBLE);
253521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            //target.setVisibility(View.INVISIBLE);
254521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            if (animate) {
255521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                boolean horiz = alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT;
256521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                int dx = horiz ? (alignment == ALIGN_LEFT ? tab.getWidth() : -tab.getWidth()) : 0;
257521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                int dy = horiz ? 0: (alignment == ALIGN_TOP ? tab.getHeight() : -tab.getHeight());
258521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
259521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                Animation trans = new TranslateAnimation(-dx, 0, -dy, 0);
260521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                trans.setDuration(ANIM_DURATION);
261521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                tab.startAnimation(trans);
262521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                text.startAnimation(trans);
263521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            }
264521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        }
265521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
26624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void setState(int state) {
26724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            text.setPressed(state == STATE_PRESSED);
26824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            tab.setPressed(state == STATE_PRESSED);
26924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            if (state == STATE_ACTIVE) {
27024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                final int[] activeState = new int[] {com.android.internal.R.attr.state_active};
27124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                if (text.getBackground().isStateful()) {
27224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    text.getBackground().setState(activeState);
27324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                }
27424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                if (tab.getBackground().isStateful()) {
27524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    tab.getBackground().setState(activeState);
27624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                }
27724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabActive);
27824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            } else {
27924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
28024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            }
2814df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller            currentState = state;
28224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
28324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
28424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void showTarget() {
285521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            AlphaAnimation alphaAnim = new AlphaAnimation(0.0f, 1.0f);
286521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            alphaAnim.setDuration(ANIM_TARGET_TIME);
287521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            target.startAnimation(alphaAnim);
28824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            target.setVisibility(View.VISIBLE);
28924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
29024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
291521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        void reset(boolean animate) {
29224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            setState(STATE_NORMAL);
29324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            text.setVisibility(View.VISIBLE);
29424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            text.setTextAppearance(text.getContext(), R.style.TextAppearance_SlidingTabNormal);
29524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            tab.setVisibility(View.VISIBLE);
29624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            target.setVisibility(View.INVISIBLE);
297521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            final boolean horiz = alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT;
298521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int dx = horiz ? (alignment == ALIGN_LEFT ?  alignment_value - tab.getLeft()
299521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    : alignment_value - tab.getRight()) : 0;
300521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int dy = horiz ? 0 : (alignment == ALIGN_TOP ? alignment_value - tab.getTop()
301521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    : alignment_value - tab.getBottom());
302521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            if (animate) {
303521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                TranslateAnimation trans = new TranslateAnimation(0, dx, 0, dy);
304521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                trans.setDuration(ANIM_DURATION);
305521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                trans.setFillAfter(false);
306521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                text.startAnimation(trans);
307521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                tab.startAnimation(trans);
308521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            } else {
309521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                if (horiz) {
310521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    text.offsetLeftAndRight(dx);
311521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    tab.offsetLeftAndRight(dx);
312521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                } else {
313521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    text.offsetTopAndBottom(dy);
314521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    tab.offsetTopAndBottom(dy);
315521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                }
3164f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                text.clearAnimation();
3174f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                tab.clearAnimation();
3184f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                target.clearAnimation();
319521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            }
32024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
32124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
32224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void setTarget(int targetId) {
32324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            target.setImageResource(targetId);
32424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
32524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
32624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        /**
32724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * Layout the given widgets within the parent.
32824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         *
32924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param l the parent's left border
33024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param t the parent's top border
33124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param r the parent's right border
33224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param b the parent's bottom border
33324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         * @param alignment which side to align the widget to
33424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller         */
33524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        void layout(int l, int t, int r, int b, int alignment) {
336521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            this.alignment = alignment;
337753401aa471d2fb87ab937c2b02b182ebc215c3aJim Miller            final Drawable tabBackground = tab.getBackground();
338753401aa471d2fb87ab937c2b02b182ebc215c3aJim Miller            final int handleWidth = tabBackground.getIntrinsicWidth();
339753401aa471d2fb87ab937c2b02b182ebc215c3aJim Miller            final int handleHeight = tabBackground.getIntrinsicHeight();
340753401aa471d2fb87ab937c2b02b182ebc215c3aJim Miller            final Drawable targetDrawable = target.getDrawable();
341753401aa471d2fb87ab937c2b02b182ebc215c3aJim Miller            final int targetWidth = targetDrawable.getIntrinsicWidth();
342753401aa471d2fb87ab937c2b02b182ebc215c3aJim Miller            final int targetHeight = targetDrawable.getIntrinsicHeight();
34324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            final int parentWidth = r - l;
34424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            final int parentHeight = b - t;
34524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
3464df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller            final int leftTarget = (int) (THRESHOLD * parentWidth) - targetWidth + handleWidth / 2;
3474df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller            final int rightTarget = (int) ((1.0f - THRESHOLD) * parentWidth) - handleWidth / 2;
34824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            final int left = (parentWidth - handleWidth) / 2;
34924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            final int right = left + handleWidth;
35024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
35124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            if (alignment == ALIGN_LEFT || alignment == ALIGN_RIGHT) {
35224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                // horizontal
35324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                final int targetTop = (parentHeight - targetHeight) / 2;
35424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                final int targetBottom = targetTop + targetHeight;
35524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                final int top = (parentHeight - handleHeight) / 2;
35624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                final int bottom = (parentHeight + handleHeight) / 2;
35724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                if (alignment == ALIGN_LEFT) {
35824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    tab.layout(0, top, handleWidth, bottom);
35924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    text.layout(0 - parentWidth, top, 0, bottom);
36024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    text.setGravity(Gravity.RIGHT);
36124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    target.layout(leftTarget, targetTop, leftTarget + targetWidth, targetBottom);
362521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    alignment_value = l;
36324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                } else {
36424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    tab.layout(parentWidth - handleWidth, top, parentWidth, bottom);
36524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    text.layout(parentWidth, top, parentWidth + parentWidth, bottom);
36624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    target.layout(rightTarget, targetTop, rightTarget + targetWidth, targetBottom);
36724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    text.setGravity(Gravity.TOP);
368521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    alignment_value = r;
36924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                }
37024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            } else {
37124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                // vertical
37224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                final int targetLeft = (parentWidth - targetWidth) / 2;
37324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                final int targetRight = (parentWidth + targetWidth) / 2;
3744df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller                final int top = (int) (THRESHOLD * parentHeight) + handleHeight / 2 - targetHeight;
3754df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller                final int bottom = (int) ((1.0f - THRESHOLD) * parentHeight) - handleHeight / 2;
37624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                if (alignment == ALIGN_TOP) {
37724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    tab.layout(left, 0, right, handleHeight);
37824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    text.layout(left, 0 - parentHeight, right, 0);
37924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    target.layout(targetLeft, top, targetRight, top + targetHeight);
380521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    alignment_value = t;
38124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                } else {
38224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    tab.layout(left, parentHeight - handleHeight, right, parentHeight);
38324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    text.layout(left, parentHeight, right, parentHeight + parentHeight);
38424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    target.layout(targetLeft, bottom, targetRight, bottom + targetHeight);
385521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    alignment_value = b;
38624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                }
38724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            }
38824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
38924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
3904df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller        public void updateDrawableStates() {
3914df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller            setState(currentState);
3924df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller        }
3934df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller
3944811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        /**
3954811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller         * Ensure all the dependent widgets are measured.
3964811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller         */
3974811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        public void measure() {
3984811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller            tab.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
3994811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
4004811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller            text.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
4014811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
4024811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        }
4034811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller
4044811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        /**
4054811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller         * Get the measured tab width. Must be called after {@link Slider#measure()}.
4064811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller         * @return
4074811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller         */
40824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        public int getTabWidth() {
4094811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller            return tab.getMeasuredWidth();
41024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
41124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
4124811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        /**
4134811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller         * Get the measured tab width. Must be called after {@link Slider#measure()}.
4144811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller         * @return
4154811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller         */
41624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        public int getTabHeight() {
4174811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller            return tab.getMeasuredHeight();
41824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
419521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
4208b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        /**
421f76a50ce8fdc6aea22cabc77b2977a1a15a79630Ken Wakasa         * Start animating the slider. Note we need two animations since a ValueAnimator
4228b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller         * keeps internal state of the invalidation region which is just the view being animated.
4232cd1e6eda90170114e0795b13f65f964296cf2f2Jim Miller         *
4248b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller         * @param anim1
4258b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller         * @param anim2
4268b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller         */
4278b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        public void startAnimation(Animation anim1, Animation anim2) {
4288b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller            tab.startAnimation(anim1);
4298b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller            text.startAnimation(anim2);
4304f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        }
4314f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller
4324f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        public void hideTarget() {
4334f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller            target.clearAnimation();
4344f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller            target.setVisibility(View.INVISIBLE);
435521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        }
43624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
43724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
43824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    public SlidingTab(Context context) {
43924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        this(context, null);
44024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
44124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
44224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
44324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Constructor used when this widget is created from a layout file.
44424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
44524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    public SlidingTab(Context context, AttributeSet attrs) {
44624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        super(context, attrs);
44724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
448521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        // Allocate a temporary once that can be used everywhere.
449521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        mTmpRect = new Rect();
450521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
45124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingTab);
45224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mOrientation = a.getInt(R.styleable.SlidingTab_orientation, HORIZONTAL);
45324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        a.recycle();
45424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
45524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        Resources r = getResources();
45624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mDensity = r.getDisplayMetrics().density;
45724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        if (DBG) log("- Density: " + mDensity);
45824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
459425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller        mLeftSlider = new Slider(this,
460425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller                R.drawable.jog_tab_left_generic,
46124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                R.drawable.jog_tab_bar_left_generic,
46224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                R.drawable.jog_tab_target_gray);
463425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller        mRightSlider = new Slider(this,
464425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller                R.drawable.jog_tab_right_generic,
46524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                R.drawable.jog_tab_bar_right_generic,
46624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                R.drawable.jog_tab_target_gray);
46724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
46824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        // setBackgroundColor(0x80808080);
46924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
47024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
47124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    @Override
47224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
47324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
47424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        int widthSpecSize =  MeasureSpec.getSize(widthMeasureSpec);
47524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
47624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
47724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
47824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
4793747f3f41fa228e958d39f3cbf2781fb8062f3e7Jim Miller        if (DBG) {
4803747f3f41fa228e958d39f3cbf2781fb8062f3e7Jim Miller            if (widthSpecMode == MeasureSpec.UNSPECIFIED
4813747f3f41fa228e958d39f3cbf2781fb8062f3e7Jim Miller                    || heightSpecMode == MeasureSpec.UNSPECIFIED) {
4823747f3f41fa228e958d39f3cbf2781fb8062f3e7Jim Miller                Log.e("SlidingTab", "SlidingTab cannot have UNSPECIFIED MeasureSpec"
4833747f3f41fa228e958d39f3cbf2781fb8062f3e7Jim Miller                        +"(wspec=" + widthSpecMode + ", hspec=" + heightSpecMode + ")",
4843747f3f41fa228e958d39f3cbf2781fb8062f3e7Jim Miller                        new RuntimeException(LOG_TAG + "stack:"));
4853747f3f41fa228e958d39f3cbf2781fb8062f3e7Jim Miller            }
48624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
48724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
4884811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        mLeftSlider.measure();
4894811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        mRightSlider.measure();
4904811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        final int leftTabWidth = mLeftSlider.getTabWidth();
4914811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        final int rightTabWidth = mRightSlider.getTabWidth();
4924811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        final int leftTabHeight = mLeftSlider.getTabHeight();
4934811d62d5f07a1ffbf085d5e424e2b54d0e7ebfdJim Miller        final int rightTabHeight = mRightSlider.getTabHeight();
49424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        final int width;
49524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        final int height;
49624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        if (isHorizontal()) {
49724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            width = Math.max(widthSpecSize, leftTabWidth + rightTabWidth);
49824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            height = Math.max(leftTabHeight, rightTabHeight);
49924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        } else {
50024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            width = Math.max(leftTabWidth, rightTabHeight);
50124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            height = Math.max(heightSpecSize, leftTabHeight + rightTabHeight);
50224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
50324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        setMeasuredDimension(width, height);
50424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
50524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
50624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    @Override
50724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    public boolean onInterceptTouchEvent(MotionEvent event) {
50824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        final int action = event.getAction();
50924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        final float x = event.getX();
51024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        final float y = event.getY();
51124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
51224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        if (mAnimating) {
51324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            return false;
51424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
51524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
51624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        View leftHandle = mLeftSlider.tab;
517521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        leftHandle.getHitRect(mTmpRect);
518521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        boolean leftHit = mTmpRect.contains((int) x, (int) y);
51924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
52024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        View rightHandle = mRightSlider.tab;
521521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        rightHandle.getHitRect(mTmpRect);
522521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        boolean rightHit = mTmpRect.contains((int)x, (int) y);
52324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
52424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        if (!mTracking && !(leftHit || rightHit)) {
52524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            return false;
52624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
52724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
52824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        switch (action) {
52924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            case MotionEvent.ACTION_DOWN: {
53024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                mTracking = true;
53124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                mTriggered = false;
53224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                vibrate(VIBRATE_SHORT);
53324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                if (leftHit) {
53424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    mCurrentSlider = mLeftSlider;
53524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    mOtherSlider = mRightSlider;
5364df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller                    mThreshold = isHorizontal() ? THRESHOLD : 1.0f - THRESHOLD;
53724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    setGrabbedState(OnTriggerListener.LEFT_HANDLE);
53824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                } else {
53924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    mCurrentSlider = mRightSlider;
54024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    mOtherSlider = mLeftSlider;
5414df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller                    mThreshold = isHorizontal() ? 1.0f - THRESHOLD : THRESHOLD;
54224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    setGrabbedState(OnTriggerListener.RIGHT_HANDLE);
54324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                }
54424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                mCurrentSlider.setState(Slider.STATE_PRESSED);
54524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                mCurrentSlider.showTarget();
54624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                mOtherSlider.hide();
54724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                break;
54824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            }
54924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
55024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
55124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        return true;
55224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
55324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
554d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller    /**
555d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller     * Reset the tabs to their original state and stop any existing animation.
556d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller     * Animate them back into place if animate is true.
557d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller     *
558d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller     * @param animate
559d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller     */
560d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller    public void reset(boolean animate) {
561d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller        mLeftSlider.reset(animate);
562d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller        mRightSlider.reset(animate);
563966a8c78598bdba1e8993428b5b1eef4d97ae501Jim Miller        if (!animate) {
564966a8c78598bdba1e8993428b5b1eef4d97ae501Jim Miller            mAnimating = false;
565966a8c78598bdba1e8993428b5b1eef4d97ae501Jim Miller        }
566d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller    }
567d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller
56824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    @Override
5694f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    public void setVisibility(int visibility) {
5704f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        // Clear animations so sliders don't continue to animate when we show the widget again.
5714f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        if (visibility != getVisibility() && visibility == View.INVISIBLE) {
572d8a3a8957b9d71ab75584b0cc98324fd70cc527cJim Miller           reset(false);
5734f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        }
5744f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        super.setVisibility(visibility);
5754f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    }
5764f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller
5774f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    @Override
57824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    public boolean onTouchEvent(MotionEvent event) {
57924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        if (mTracking) {
58024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            final int action = event.getAction();
58124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            final float x = event.getX();
58224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            final float y = event.getY();
583521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
58424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            switch (action) {
58524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                case MotionEvent.ACTION_MOVE:
586521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                    if (withinView(x, y, this) ) {
587521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                        moveHandle(x, y);
588521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                        float position = isHorizontal() ? x : y;
589521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                        float target = mThreshold * (isHorizontal() ? getWidth() : getHeight());
590521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                        boolean thresholdReached;
591521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                        if (isHorizontal()) {
592521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                            thresholdReached = mCurrentSlider == mLeftSlider ?
593521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                                    position > target : position < target;
594521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                        } else {
595521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                            thresholdReached = mCurrentSlider == mLeftSlider ?
596521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                                    position < target : position > target;
597521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                        }
598521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                        if (!mTriggered && thresholdReached) {
599521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                            mTriggered = true;
600521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                            mTracking = false;
601521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                            mCurrentSlider.setState(Slider.STATE_ACTIVE);
6024f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                            boolean isLeft = mCurrentSlider == mLeftSlider;
6034f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                            dispatchTriggerEvent(isLeft ?
604521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                                OnTriggerListener.LEFT_HANDLE : OnTriggerListener.RIGHT_HANDLE);
605521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
6064f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                            startAnimating(isLeft ? mHoldLeftOnTransition : mHoldRightOnTransition);
607521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                            setGrabbedState(OnTriggerListener.NO_HANDLE);
608521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller                        }
60924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                        break;
61024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    }
61124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    // Intentionally fall through - we're outside tracking rectangle
61224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
61324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                case MotionEvent.ACTION_UP:
61424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                case MotionEvent.ACTION_CANCEL:
61592c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller                    cancelGrab();
61624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                    break;
61724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            }
61824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
61924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
62024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        return mTracking || super.onTouchEvent(event);
62124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
62224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
62392c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller    private void cancelGrab() {
62492c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        mTracking = false;
62592c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        mTriggered = false;
62692c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        mOtherSlider.show(true);
62792c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        mCurrentSlider.reset(false);
62892c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        mCurrentSlider.hideTarget();
62992c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        mCurrentSlider = null;
63092c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        mOtherSlider = null;
63192c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        setGrabbedState(OnTriggerListener.NO_HANDLE);
63292c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller    }
63392c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller
6344f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    void startAnimating(final boolean holdAfter) {
635521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        mAnimating = true;
6368b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        final Animation trans1;
6378b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        final Animation trans2;
6384f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        final Slider slider = mCurrentSlider;
6394f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        final Slider other = mOtherSlider;
6404f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        final int dx;
6414f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        final int dy;
642521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        if (isHorizontal()) {
643521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int right = slider.tab.getRight();
644521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int width = slider.tab.getWidth();
645521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int left = slider.tab.getLeft();
646521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int viewWidth = getWidth();
6474f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller            int holdOffset = holdAfter ? 0 : width; // how much of tab to show at the end of anim
6484f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller            dx =  slider == mRightSlider ? - (right + viewWidth - holdOffset)
6494f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                    : (viewWidth - left) + viewWidth - holdOffset;
650521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            dy = 0;
651521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        } else {
652521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int top = slider.tab.getTop();
653521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int bottom = slider.tab.getBottom();
654521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int height = slider.tab.getHeight();
655521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            int viewHeight = getHeight();
6564f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller            int holdOffset = holdAfter ? 0 : height; // how much of tab to show at end of anim
657521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            dx = 0;
6584f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller            dy =  slider == mRightSlider ? (top + viewHeight - holdOffset)
6594f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                    : - ((viewHeight - bottom) + viewHeight - holdOffset);
660521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        }
6618b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        trans1 = new TranslateAnimation(0, dx, 0, dy);
6628b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        trans1.setDuration(ANIM_DURATION);
6638b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        trans1.setInterpolator(new LinearInterpolator());
6648b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        trans1.setFillAfter(true);
6658b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        trans2 = new TranslateAnimation(0, dx, 0, dy);
6668b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        trans2.setDuration(ANIM_DURATION);
6678b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        trans2.setInterpolator(new LinearInterpolator());
6688b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        trans2.setFillAfter(true);
6698b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller
6708b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        trans1.setAnimationListener(new AnimationListener() {
671521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            public void onAnimationEnd(Animation animation) {
6724f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                Animation anim;
6734f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                if (holdAfter) {
6744f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                    anim = new TranslateAnimation(dx, dx, dy, dy);
6754f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                    anim.setDuration(1000); // plenty of time for transitions
6764f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                    mAnimating = false;
6774f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                } else {
6784f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                    anim = new AlphaAnimation(0.5f, 1.0f);
6794f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                    anim.setDuration(ANIM_DURATION);
6804f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                    resetView();
6814f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                }
6824f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller                anim.setAnimationListener(mAnimationDoneListener);
6832cd1e6eda90170114e0795b13f65f964296cf2f2Jim Miller
6848b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller                /* Animation can be the same for these since the animation just holds */
6858b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller                mLeftSlider.startAnimation(anim, anim);
6868b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller                mRightSlider.startAnimation(anim, anim);
687521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            }
688521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
689521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            public void onAnimationRepeat(Animation animation) {
690521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
691521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            }
692521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
693521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            public void onAnimationStart(Animation animation) {
694521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
695521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            }
696521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
697521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        });
698521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
6994f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        slider.hideTarget();
7008b63ab664ff5068d022c080ce04995a0bfdd7030Jim Miller        slider.startAnimation(trans1, trans2);
701521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller    }
702521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
7034f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    private void onAnimationDone() {
7044f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        resetView();
7054f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        mAnimating = false;
7064f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    }
7074f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller
708521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller    private boolean withinView(final float x, final float y, final View view) {
709521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        return isHorizontal() && y > - TRACKING_MARGIN && y < TRACKING_MARGIN + view.getHeight()
710521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller            || !isHorizontal() && x > -TRACKING_MARGIN && x < TRACKING_MARGIN + view.getWidth();
711521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller    }
712521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller
71324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private boolean isHorizontal() {
71424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        return mOrientation == HORIZONTAL;
71524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
71624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
71724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private void resetView() {
718521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        mLeftSlider.reset(false);
719521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        mRightSlider.reset(false);
720521d400b230bee5e7b9748f26832c0d0275b8253Jim Miller        // onLayout(true, getLeft(), getTop(), getLeft() + getWidth(), getTop() + getHeight());
72124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
72224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
72324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    @Override
72424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    protected void onLayout(boolean changed, int l, int t, int r, int b) {
72524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        if (!changed) return;
72624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
72724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        // Center the widgets in the view
72824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mLeftSlider.layout(l, t, r, b, isHorizontal() ? Slider.ALIGN_LEFT : Slider.ALIGN_BOTTOM);
72924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mRightSlider.layout(l, t, r, b, isHorizontal() ? Slider.ALIGN_RIGHT : Slider.ALIGN_TOP);
73024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
73124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
73224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private void moveHandle(float x, float y) {
73324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        final View handle = mCurrentSlider.tab;
73424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        final View content = mCurrentSlider.text;
73524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        if (isHorizontal()) {
73624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            int deltaX = (int) x - handle.getLeft() - (handle.getWidth() / 2);
73724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            handle.offsetLeftAndRight(deltaX);
73824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            content.offsetLeftAndRight(deltaX);
73924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        } else {
74024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            int deltaY = (int) y - handle.getTop() - (handle.getHeight() / 2);
74124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            handle.offsetTopAndBottom(deltaY);
74224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            content.offsetTopAndBottom(deltaY);
74324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
74424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        invalidate(); // TODO: be more conservative about what we're invalidating
74524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
74624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
74724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
74824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Sets the left handle icon to a given resource.
74924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     *
75024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * The resource should refer to a Drawable object, or use 0 to remove
75124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * the icon.
75224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     *
75324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * @param iconId the resource ID of the icon drawable
75424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * @param targetId the resource of the target drawable
75524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * @param barId the resource of the bar drawable (stateful)
756425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller     * @param tabId the resource of the
75724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
75824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    public void setLeftTabResources(int iconId, int targetId, int barId, int tabId) {
75924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mLeftSlider.setIcon(iconId);
760425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller        mLeftSlider.setTarget(targetId);
76124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mLeftSlider.setBarBackgroundResource(barId);
76224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mLeftSlider.setTabBackgroundResource(tabId);
7634df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller        mLeftSlider.updateDrawableStates();
76424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
76524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
76624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
76724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Sets the left handle hint text to a given resource string.
76824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     *
76924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * @param resId
77024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
77124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    public void setLeftHintText(int resId) {
772425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller        if (isHorizontal()) {
773425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller            mLeftSlider.setHintText(resId);
774425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller        }
77524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
77624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
77724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
77824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Sets the right handle icon to a given resource.
77924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     *
78024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * The resource should refer to a Drawable object, or use 0 to remove
78124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * the icon.
78224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     *
78324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * @param iconId the resource ID of the icon drawable
78424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * @param targetId the resource of the target drawable
78524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * @param barId the resource of the bar drawable (stateful)
786425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller     * @param tabId the resource of the
78724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
78824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    public void setRightTabResources(int iconId, int targetId, int barId, int tabId) {
78924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mRightSlider.setIcon(iconId);
790425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller        mRightSlider.setTarget(targetId);
79124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mRightSlider.setBarBackgroundResource(barId);
79224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mRightSlider.setTabBackgroundResource(tabId);
7934df2c5433bb530fae6191a0298a6d494ca03eaa7Jim Miller        mRightSlider.updateDrawableStates();
79424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
79524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
79624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
79724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Sets the left handle hint text to a given resource string.
79824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     *
79924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * @param resId
80024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
80124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    public void setRightHintText(int resId) {
802425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller        if (isHorizontal()) {
803425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller            mRightSlider.setHintText(resId);
804425ca595dcc37ddb7a9f96310e5b800f424811a6Jim Miller        }
80524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
80624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
8074f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    public void setHoldAfterTrigger(boolean holdLeft, boolean holdRight) {
8084f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        mHoldLeftOnTransition = holdLeft;
8094f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller        mHoldRightOnTransition = holdRight;
8104f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller    }
8114f01d4a4da7754dbe6a49cca8f94e81104acb87fJim Miller
81224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
81324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Triggers haptic feedback.
81424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
81524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private synchronized void vibrate(long duration) {
816723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey        final boolean hapticEnabled = Settings.System.getIntForUser(
817723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey                mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1,
818723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey                UserHandle.USER_CURRENT) != 0;
819723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey        if (hapticEnabled) {
820723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey            if (mVibrator == null) {
821723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey                mVibrator = (android.os.Vibrator) getContext()
822723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey                        .getSystemService(Context.VIBRATOR_SERVICE);
823723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey            }
824723a725e790d269f32980116e775d3d7f0037865Jeff Sharkey            mVibrator.vibrate(duration);
82524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
82624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
82724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
82824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
82924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Registers a callback to be invoked when the user triggers an event.
83024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     *
83124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * @param listener the OnDialTriggerListener to attach to this view
83224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
83324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    public void setOnTriggerListener(OnTriggerListener listener) {
83424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        mOnTriggerListener = listener;
83524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
83624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
83724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
83824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Dispatches a trigger event to listener. Ignored if a listener is not set.
83924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * @param whichHandle the handle that triggered the event.
84024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
84124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private void dispatchTriggerEvent(int whichHandle) {
84224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        vibrate(VIBRATE_LONG);
84324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        if (mOnTriggerListener != null) {
84424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            mOnTriggerListener.onTrigger(this, whichHandle);
84524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
84624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
84724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
84892c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller    @Override
84992c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller    protected void onVisibilityChanged(View changedView, int visibility) {
85092c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        super.onVisibilityChanged(changedView, visibility);
85192c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        // When visibility changes and the user has a tab selected, unselect it and
85292c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        // make sure their callback gets called.
85392c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        if (changedView == this && visibility != VISIBLE
85492c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller                && mGrabbedState != OnTriggerListener.NO_HANDLE) {
85592c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller            cancelGrab();
85692c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller        }
85792c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller    }
85892c1571f0a5202f742d3318d5f852dc5e395d19cJim Miller
85924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    /**
86024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * Sets the current grabbed state, and dispatches a grabbed state change
86124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     * event to our listener.
86224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller     */
86324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private void setGrabbedState(int newState) {
86424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        if (newState != mGrabbedState) {
86524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            mGrabbedState = newState;
86624ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            if (mOnTriggerListener != null) {
86724ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller                mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
86824ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller            }
86924ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        }
87024ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
87124ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller
87224ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    private void log(String msg) {
87324ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller        Log.d(LOG_TAG, msg);
87424ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller    }
87524ccf3c59077d81b0dd3b314822ff7dab215c165Jim Miller}
876