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