PieRenderer.java revision 673da081181c72352d57c9bf97badb2929370685
11373b98135b2854578111dd535e24d39c8853f14Michael Kolb/* 21373b98135b2854578111dd535e24d39c8853f14Michael Kolb * Copyright (C) 2012 The Android Open Source Project 31373b98135b2854578111dd535e24d39c8853f14Michael Kolb * 41373b98135b2854578111dd535e24d39c8853f14Michael Kolb * Licensed under the Apache License, Version 2.0 (the "License"); 51373b98135b2854578111dd535e24d39c8853f14Michael Kolb * you may not use this file except in compliance with the License. 61373b98135b2854578111dd535e24d39c8853f14Michael Kolb * You may obtain a copy of the License at 71373b98135b2854578111dd535e24d39c8853f14Michael Kolb * 81373b98135b2854578111dd535e24d39c8853f14Michael Kolb * http://www.apache.org/licenses/LICENSE-2.0 91373b98135b2854578111dd535e24d39c8853f14Michael Kolb * 101373b98135b2854578111dd535e24d39c8853f14Michael Kolb * Unless required by applicable law or agreed to in writing, software 111373b98135b2854578111dd535e24d39c8853f14Michael Kolb * distributed under the License is distributed on an "AS IS" BASIS, 121373b98135b2854578111dd535e24d39c8853f14Michael Kolb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131373b98135b2854578111dd535e24d39c8853f14Michael Kolb * See the License for the specific language governing permissions and 141373b98135b2854578111dd535e24d39c8853f14Michael Kolb * limitations under the License. 151373b98135b2854578111dd535e24d39c8853f14Michael Kolb */ 161373b98135b2854578111dd535e24d39c8853f14Michael Kolb 171373b98135b2854578111dd535e24d39c8853f14Michael Kolbpackage com.android.camera.ui; 181373b98135b2854578111dd535e24d39c8853f14Michael Kolb 19c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolbimport android.annotation.TargetApi; 201373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.content.Context; 211373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.content.res.Resources; 221373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.graphics.Canvas; 231373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.graphics.Color; 241373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.graphics.Paint; 251373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.graphics.Path; 261373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.graphics.Point; 271373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.graphics.PointF; 281373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.graphics.RectF; 291373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.os.Handler; 301373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.os.Message; 31673da081181c72352d57c9bf97badb2929370685Michael Kolbimport android.util.Log; 321373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.view.MotionEvent; 331373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport android.view.View; 34c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolbimport android.view.animation.Animation; 35c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolbimport android.view.animation.Animation.AnimationListener; 36c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolbimport android.view.animation.Transformation; 371373b98135b2854578111dd535e24d39c8853f14Michael Kolb 381373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport com.android.camera.R; 39c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolbimport com.android.gallery3d.common.ApiHelper; 401373b98135b2854578111dd535e24d39c8853f14Michael Kolb 411373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport java.util.ArrayList; 421373b98135b2854578111dd535e24d39c8853f14Michael Kolbimport java.util.List; 431373b98135b2854578111dd535e24d39c8853f14Michael Kolb 448042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolbpublic class PieRenderer extends OverlayRenderer 458042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb implements FocusIndicator { 461373b98135b2854578111dd535e24d39c8853f14Michael Kolb 471373b98135b2854578111dd535e24d39c8853f14Michael Kolb private static final String TAG = "CAM Pie"; 481373b98135b2854578111dd535e24d39c8853f14Michael Kolb 49b986d1e51d776706cb3603a9c386772da6d7cf48Michael Kolb private static final long PIE_FADE_DURATION = 1500; 508042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb // Sometimes continuous autofocus starts and stops several times quickly. 518042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb // These states are used to make sure the animation is run for at least some 528042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb // time. 538042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mState; 548042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private ScaleAnimation mAnimation = new ScaleAnimation(); 558042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private static final int STATE_IDLE = 0; 568042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private static final int STATE_FOCUSING = 1; 578042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private static final int STATE_FINISHING = 2; 588042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private static final int STATE_PIE = 3; 598042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 608042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private Runnable mDisappear = new Disappear(); 618042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private Animation.AnimationListener mEndAction = new EndAction(); 62673da081181c72352d57c9bf97badb2929370685Michael Kolb private static final int SCALING_UP_TIME = 600; 63673da081181c72352d57c9bf97badb2929370685Michael Kolb private static final int SCALING_DOWN_TIME = 100; 648042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private static final int DISAPPEAR_TIMEOUT = 200; 658042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private static final int DIAL_HORIZONTAL = 157; 668042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 674d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb private static final long PIE_OPEN_DELAY = 200; 68673da081181c72352d57c9bf97badb2929370685Michael Kolb private static final long FOCUS_TAP_TIMEOUT = 500; 691373b98135b2854578111dd535e24d39c8853f14Michael Kolb 701373b98135b2854578111dd535e24d39c8853f14Michael Kolb private static final int MSG_OPEN = 2; 711373b98135b2854578111dd535e24d39c8853f14Michael Kolb private static final int MSG_CLOSE = 3; 721373b98135b2854578111dd535e24d39c8853f14Michael Kolb private static final int MSG_SUBMENU = 4; 73a0dd52298b55357a711663180677efa39d35e5abMichael Kolb private static final int MSG_FOCUS_TAP = 5; 741373b98135b2854578111dd535e24d39c8853f14Michael Kolb private static final float PIE_SWEEP = (float)(Math.PI * 2 / 3); 751373b98135b2854578111dd535e24d39c8853f14Michael Kolb // geometry 761373b98135b2854578111dd535e24d39c8853f14Michael Kolb private Point mCenter; 771373b98135b2854578111dd535e24d39c8853f14Michael Kolb private int mRadius; 781373b98135b2854578111dd535e24d39c8853f14Michael Kolb private int mRadiusInc; 791373b98135b2854578111dd535e24d39c8853f14Michael Kolb private int mSlop; 808042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 811373b98135b2854578111dd535e24d39c8853f14Michael Kolb // the detection if touch is inside a slice is offset 821373b98135b2854578111dd535e24d39c8853f14Michael Kolb // inbounds by this amount to allow the selection to show before the 831373b98135b2854578111dd535e24d39c8853f14Michael Kolb // finger covers it 841373b98135b2854578111dd535e24d39c8853f14Michael Kolb private int mTouchOffset; 851373b98135b2854578111dd535e24d39c8853f14Michael Kolb 861373b98135b2854578111dd535e24d39c8853f14Michael Kolb private List<PieItem> mItems; 871373b98135b2854578111dd535e24d39c8853f14Michael Kolb 881373b98135b2854578111dd535e24d39c8853f14Michael Kolb private PieItem mOpenItem; 891373b98135b2854578111dd535e24d39c8853f14Michael Kolb 901373b98135b2854578111dd535e24d39c8853f14Michael Kolb private Paint mNormalPaint; 911373b98135b2854578111dd535e24d39c8853f14Michael Kolb private Paint mSelectedPaint; 921373b98135b2854578111dd535e24d39c8853f14Michael Kolb private Paint mSubPaint; 931373b98135b2854578111dd535e24d39c8853f14Michael Kolb 941373b98135b2854578111dd535e24d39c8853f14Michael Kolb // touch handling 951373b98135b2854578111dd535e24d39c8853f14Michael Kolb private PieItem mCurrentItem; 961373b98135b2854578111dd535e24d39c8853f14Michael Kolb 971373b98135b2854578111dd535e24d39c8853f14Michael Kolb private boolean mAnimating; 98c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb private float mAlpha; 991373b98135b2854578111dd535e24d39c8853f14Michael Kolb 1008042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private Paint mFocusPaint; 101673da081181c72352d57c9bf97badb2929370685Michael Kolb private int mSuccessColor; 102673da081181c72352d57c9bf97badb2929370685Michael Kolb private int mFailColor; 1038042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private Paint mDotPaint; 1048042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mCircleSize; 1058042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mDotRadius; 1068042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mFocusX; 1078042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mFocusY; 1088042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mCenterX; 1098042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mCenterY; 1108042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 1118042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mDialAngle; 1128042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private RectF mCircle; 1138042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private RectF mDial; 1148042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private Point mPoint1; 1158042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private Point mPoint2; 1168042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mStartAnimationAngle; 1178042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private boolean mFocused; 1188042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mInnerOffset; 1198042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mOuterStroke; 1208042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int mInnerStroke; 121a0dd52298b55357a711663180677efa39d35e5abMichael Kolb private boolean mShowFade = true; 122a0dd52298b55357a711663180677efa39d35e5abMichael Kolb private boolean mFocusFromTap; 123a0dd52298b55357a711663180677efa39d35e5abMichael Kolb private boolean mShowItems; 1248042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 1258042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 1261373b98135b2854578111dd535e24d39c8853f14Michael Kolb private Handler mHandler = new Handler() { 1271373b98135b2854578111dd535e24d39c8853f14Michael Kolb public void handleMessage(Message msg) { 1281373b98135b2854578111dd535e24d39c8853f14Michael Kolb switch(msg.what) { 1291373b98135b2854578111dd535e24d39c8853f14Michael Kolb case MSG_OPEN: 130c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb if (mListener != null && !mAnimating) { 1311373b98135b2854578111dd535e24d39c8853f14Michael Kolb mListener.onPieOpened(mCenter.x, mCenter.y); 1321373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 1331373b98135b2854578111dd535e24d39c8853f14Michael Kolb break; 1341373b98135b2854578111dd535e24d39c8853f14Michael Kolb case MSG_CLOSE: 135c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb if (mListener != null && !mAnimating) { 1361373b98135b2854578111dd535e24d39c8853f14Michael Kolb mListener.onPieClosed(); 1371373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 1381373b98135b2854578111dd535e24d39c8853f14Michael Kolb break; 1391373b98135b2854578111dd535e24d39c8853f14Michael Kolb case MSG_SUBMENU: 1401373b98135b2854578111dd535e24d39c8853f14Michael Kolb openCurrentItem(); 1411373b98135b2854578111dd535e24d39c8853f14Michael Kolb break; 142a0dd52298b55357a711663180677efa39d35e5abMichael Kolb case MSG_FOCUS_TAP: 143a0dd52298b55357a711663180677efa39d35e5abMichael Kolb // reset flag 144a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mShowItems = false; 145a0dd52298b55357a711663180677efa39d35e5abMichael Kolb break; 1461373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 1471373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 1481373b98135b2854578111dd535e24d39c8853f14Michael Kolb }; 1491373b98135b2854578111dd535e24d39c8853f14Michael Kolb 1501373b98135b2854578111dd535e24d39c8853f14Michael Kolb private PieListener mListener; 1511373b98135b2854578111dd535e24d39c8853f14Michael Kolb 1521373b98135b2854578111dd535e24d39c8853f14Michael Kolb static public interface PieListener { 1531373b98135b2854578111dd535e24d39c8853f14Michael Kolb public void onPieOpened(int centerX, int centerY); 1541373b98135b2854578111dd535e24d39c8853f14Michael Kolb public void onPieClosed(); 1551373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 1561373b98135b2854578111dd535e24d39c8853f14Michael Kolb 1571373b98135b2854578111dd535e24d39c8853f14Michael Kolb public void setPieListener(PieListener pl) { 1581373b98135b2854578111dd535e24d39c8853f14Michael Kolb mListener = pl; 1591373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 1601373b98135b2854578111dd535e24d39c8853f14Michael Kolb 1611373b98135b2854578111dd535e24d39c8853f14Michael Kolb public PieRenderer(Context context) { 1621373b98135b2854578111dd535e24d39c8853f14Michael Kolb init(context); 1631373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 1641373b98135b2854578111dd535e24d39c8853f14Michael Kolb private void init(Context ctx) { 165ad639dff251233032734106afe4fe51a52be3721Michael Kolb setVisible(false); 1661373b98135b2854578111dd535e24d39c8853f14Michael Kolb mItems = new ArrayList<PieItem>(); 1671373b98135b2854578111dd535e24d39c8853f14Michael Kolb Resources res = ctx.getResources(); 168a521253223897b099995e0af08982b4236ce5861Michael Kolb mRadius = (int) res.getDimensionPixelSize(R.dimen.pie_radius_start); 169eede360bc53b9eb7192b7117447622d6d7a5d220Michael Kolb mCircleSize = mRadius - res.getDimensionPixelSize(R.dimen.focus_radius_offset); 170a521253223897b099995e0af08982b4236ce5861Michael Kolb mRadiusInc = (int) res.getDimensionPixelSize(R.dimen.pie_radius_increment); 171a521253223897b099995e0af08982b4236ce5861Michael Kolb mSlop = (int) res.getDimensionPixelSize(R.dimen.pie_touch_slop); 172a521253223897b099995e0af08982b4236ce5861Michael Kolb mTouchOffset = (int) res.getDimensionPixelSize(R.dimen.pie_touch_offset); 1731373b98135b2854578111dd535e24d39c8853f14Michael Kolb mCenter = new Point(0,0); 1741373b98135b2854578111dd535e24d39c8853f14Michael Kolb mNormalPaint = new Paint(); 1751373b98135b2854578111dd535e24d39c8853f14Michael Kolb mNormalPaint.setColor(Color.argb(0, 0, 0, 0)); 1761373b98135b2854578111dd535e24d39c8853f14Michael Kolb mNormalPaint.setAntiAlias(true); 1771373b98135b2854578111dd535e24d39c8853f14Michael Kolb mSelectedPaint = new Paint(); 178673da081181c72352d57c9bf97badb2929370685Michael Kolb mSelectedPaint.setColor(Color.argb(255, 51, 181, 229)); 1791373b98135b2854578111dd535e24d39c8853f14Michael Kolb mSelectedPaint.setAntiAlias(true); 1801373b98135b2854578111dd535e24d39c8853f14Michael Kolb mSubPaint = new Paint(); 1811373b98135b2854578111dd535e24d39c8853f14Michael Kolb mSubPaint.setAntiAlias(true); 182673da081181c72352d57c9bf97badb2929370685Michael Kolb mSubPaint.setColor(Color.argb(200, 250, 230, 128)); 1838042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusPaint = new Paint(); 1848042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusPaint.setAntiAlias(true); 1858042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusPaint.setColor(Color.WHITE); 1868042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusPaint.setStyle(Paint.Style.STROKE); 187673da081181c72352d57c9bf97badb2929370685Michael Kolb mSuccessColor = Color.GREEN; 188673da081181c72352d57c9bf97badb2929370685Michael Kolb mFailColor = Color.RED; 1898042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mDotPaint = new Paint(); 1908042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mDotPaint.setAntiAlias(true); 191a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mDotPaint.setColor(Color.argb(160, 255, 255, 255)); 1928042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mDotPaint.setStyle(Paint.Style.FILL); 1938042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mCircle = new RectF(); 1948042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mDial = new RectF(); 1958042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mPoint1 = new Point(); 1968042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mPoint2 = new Point(); 1978042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mInnerOffset = res.getDimensionPixelSize(R.dimen.focus_inner_offset); 1988042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mOuterStroke = res.getDimensionPixelSize(R.dimen.focus_outer_stroke); 1998042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mInnerStroke = res.getDimensionPixelSize(R.dimen.focus_inner_stroke); 2008042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mDotRadius = res.getDimensionPixelSize(R.dimen.focus_dot_radius); 201a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mState = STATE_IDLE; 202a0dd52298b55357a711663180677efa39d35e5abMichael Kolb } 2038042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 204a0dd52298b55357a711663180677efa39d35e5abMichael Kolb public void showFade() { 205a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mShowFade = true; 2061373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 2071373b98135b2854578111dd535e24d39c8853f14Michael Kolb 208673da081181c72352d57c9bf97badb2929370685Michael Kolb public boolean showsItems() { 209673da081181c72352d57c9bf97badb2929370685Michael Kolb return mShowItems; 210673da081181c72352d57c9bf97badb2929370685Michael Kolb } 211673da081181c72352d57c9bf97badb2929370685Michael Kolb 2121373b98135b2854578111dd535e24d39c8853f14Michael Kolb public void addItem(PieItem item) { 2131373b98135b2854578111dd535e24d39c8853f14Michael Kolb // add the item to the pie itself 2141373b98135b2854578111dd535e24d39c8853f14Michael Kolb mItems.add(item); 2151373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 2161373b98135b2854578111dd535e24d39c8853f14Michael Kolb 2171373b98135b2854578111dd535e24d39c8853f14Michael Kolb public void removeItem(PieItem item) { 2181373b98135b2854578111dd535e24d39c8853f14Michael Kolb mItems.remove(item); 2191373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 2201373b98135b2854578111dd535e24d39c8853f14Michael Kolb 2211373b98135b2854578111dd535e24d39c8853f14Michael Kolb public void clearItems() { 2221373b98135b2854578111dd535e24d39c8853f14Michael Kolb mItems.clear(); 2231373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 2241373b98135b2854578111dd535e24d39c8853f14Michael Kolb 225c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb public void fade() { 226a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mShowFade = false; 2278042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb setCenter(mCenterX, mCenterY); 228c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb Animation anim = new AlphaAnimation(); 229c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb anim.setFillAfter(true); 230c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb anim.setAnimationListener(new AnimationListener() { 231c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb @Override 232c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb public void onAnimationStart(Animation animation) { 233c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb mAnimating = true; 234c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb update(); 235c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb } 236c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb @Override 237c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb public void onAnimationEnd(Animation animation) { 238c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb show(false); 239d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb resetAnimation(); 240c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb } 241c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb @Override 242c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb public void onAnimationRepeat(Animation animation) { 243c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb } 244c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb }); 245c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb anim.reset(); 246b986d1e51d776706cb3603a9c386772da6d7cf48Michael Kolb anim.setDuration(PIE_FADE_DURATION); 247c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb show(true); 248c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb mOverlay.startAnimation(anim); 249c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb } 250c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb 251d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb private void resetAnimation() { 252d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb mAlpha = 0f; 253d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb mAnimating = false; 254d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb setViewAlpha(mOverlay, 1); 255d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb } 256d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb 2571373b98135b2854578111dd535e24d39c8853f14Michael Kolb /** 2581373b98135b2854578111dd535e24d39c8853f14Michael Kolb * guaranteed has center set 2591373b98135b2854578111dd535e24d39c8853f14Michael Kolb * @param show 2601373b98135b2854578111dd535e24d39c8853f14Michael Kolb */ 2611373b98135b2854578111dd535e24d39c8853f14Michael Kolb private void show(boolean show) { 2621373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (show) { 263d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb if (mAnimating) { 264d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb resetAnimation(); 265d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb } 2668042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mState = STATE_PIE; 2671373b98135b2854578111dd535e24d39c8853f14Michael Kolb // ensure clean state 2681373b98135b2854578111dd535e24d39c8853f14Michael Kolb mAnimating = false; 2691373b98135b2854578111dd535e24d39c8853f14Michael Kolb mCurrentItem = null; 2701373b98135b2854578111dd535e24d39c8853f14Michael Kolb mOpenItem = null; 2711373b98135b2854578111dd535e24d39c8853f14Michael Kolb for (PieItem item : mItems) { 2721373b98135b2854578111dd535e24d39c8853f14Michael Kolb item.setSelected(false); 2731373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 2741373b98135b2854578111dd535e24d39c8853f14Michael Kolb layoutPie(); 275b8c5a15af9e8f1adb1849072a6f5a1830887b43eMichael Kolb } else { 276b8c5a15af9e8f1adb1849072a6f5a1830887b43eMichael Kolb mState = STATE_IDLE; 2771373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 278ad639dff251233032734106afe4fe51a52be3721Michael Kolb setVisible(show); 279ad639dff251233032734106afe4fe51a52be3721Michael Kolb mHandler.sendEmptyMessage(show ? MSG_OPEN : MSG_CLOSE); 2804d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb } 2814d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb 282c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb public void setCenter(int x, int y) { 2831373b98135b2854578111dd535e24d39c8853f14Michael Kolb mCenter.x = x; 2841373b98135b2854578111dd535e24d39c8853f14Michael Kolb mCenter.y = y; 2858042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb // when using the pie menu, align the focus ring 2868042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb alignFocus(x, y); 2878042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 2888042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 2898042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private void setupPie(int x, int y) { 2908042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb // when using the focus ring, align pie items 2918042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mCenter.x = x; 2928042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mCenter.y = y; 2938042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mAnimating = false; 2948042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mCurrentItem = null; 2958042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mOpenItem = null; 2968042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb for (PieItem item : mItems) { 2978042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb item.setSelected(false); 2988042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 2998042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb layoutPie(); 3001373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 3011373b98135b2854578111dd535e24d39c8853f14Michael Kolb 3021373b98135b2854578111dd535e24d39c8853f14Michael Kolb private void layoutPie() { 3031373b98135b2854578111dd535e24d39c8853f14Michael Kolb int rgap = 2; 3041373b98135b2854578111dd535e24d39c8853f14Michael Kolb int inner = mRadius + rgap; 3051373b98135b2854578111dd535e24d39c8853f14Michael Kolb int outer = mRadius + mRadiusInc - rgap; 3061373b98135b2854578111dd535e24d39c8853f14Michael Kolb int gap = 1; 3071373b98135b2854578111dd535e24d39c8853f14Michael Kolb layoutItems(mItems, (float) (Math.PI / 2), inner, outer, gap); 3081373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 3091373b98135b2854578111dd535e24d39c8853f14Michael Kolb 3104d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb private void layoutItems(List<PieItem> items, float centerAngle, int inner, 3114d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb int outer, int gap) { 3121373b98135b2854578111dd535e24d39c8853f14Michael Kolb float emptyangle = PIE_SWEEP / 16; 3131373b98135b2854578111dd535e24d39c8853f14Michael Kolb float sweep = (float) (PIE_SWEEP - 2 * emptyangle) / items.size(); 3141373b98135b2854578111dd535e24d39c8853f14Michael Kolb float angle = centerAngle - PIE_SWEEP / 2 + emptyangle + sweep / 2; 315b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb // check if we have custom geometry 316b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb // first item we find triggers custom sweep for all 317b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb // this allows us to re-use the path 318b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb for (PieItem item : items) { 319b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb if (item.getCenter() >= 0) { 320b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb sweep = item.getSweep(); 321b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb break; 322b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb } 323b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb } 3244d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb Path path = makeSlice(getDegrees(0) - gap, getDegrees(sweep) + gap, 3254d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb outer, inner, mCenter); 3261373b98135b2854578111dd535e24d39c8853f14Michael Kolb for (PieItem item : items) { 3271373b98135b2854578111dd535e24d39c8853f14Michael Kolb // shared between items 3281373b98135b2854578111dd535e24d39c8853f14Michael Kolb item.setPath(path); 3291373b98135b2854578111dd535e24d39c8853f14Michael Kolb View view = item.getView(); 330b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb if (item.getCenter() >= 0) { 331b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb angle = item.getCenter(); 332b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb } 3331373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (view != null) { 3341373b98135b2854578111dd535e24d39c8853f14Michael Kolb view.measure(view.getLayoutParams().width, 3351373b98135b2854578111dd535e24d39c8853f14Michael Kolb view.getLayoutParams().height); 3361373b98135b2854578111dd535e24d39c8853f14Michael Kolb int w = view.getMeasuredWidth(); 3371373b98135b2854578111dd535e24d39c8853f14Michael Kolb int h = view.getMeasuredHeight(); 3381373b98135b2854578111dd535e24d39c8853f14Michael Kolb // move views to outer border 3391373b98135b2854578111dd535e24d39c8853f14Michael Kolb int r = inner + (outer - inner) * 2 / 3; 3401373b98135b2854578111dd535e24d39c8853f14Michael Kolb int x = (int) (r * Math.cos(angle)); 3411373b98135b2854578111dd535e24d39c8853f14Michael Kolb int y = mCenter.y - (int) (r * Math.sin(angle)) - h / 2; 3421373b98135b2854578111dd535e24d39c8853f14Michael Kolb x = mCenter.x + x - w / 2; 3431373b98135b2854578111dd535e24d39c8853f14Michael Kolb view.layout(x, y, x + w, y + h); 3441373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 3451373b98135b2854578111dd535e24d39c8853f14Michael Kolb float itemstart = angle - sweep / 2; 3461373b98135b2854578111dd535e24d39c8853f14Michael Kolb item.setGeometry(itemstart, sweep, inner, outer); 3471373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (item.hasItems()) { 3484d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb layoutItems(item.getItems(), angle, inner, 3494d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb outer + mRadiusInc / 2, gap); 3501373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 3511373b98135b2854578111dd535e24d39c8853f14Michael Kolb angle += sweep; 3521373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 3534d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb } 3541373b98135b2854578111dd535e24d39c8853f14Michael Kolb 3551373b98135b2854578111dd535e24d39c8853f14Michael Kolb private Path makeSlice(float start, float end, int outer, int inner, Point center) { 3561373b98135b2854578111dd535e24d39c8853f14Michael Kolb RectF bb = 3571373b98135b2854578111dd535e24d39c8853f14Michael Kolb new RectF(center.x - outer, center.y - outer, center.x + outer, 3581373b98135b2854578111dd535e24d39c8853f14Michael Kolb center.y + outer); 3591373b98135b2854578111dd535e24d39c8853f14Michael Kolb RectF bbi = 3601373b98135b2854578111dd535e24d39c8853f14Michael Kolb new RectF(center.x - inner, center.y - inner, center.x + inner, 3611373b98135b2854578111dd535e24d39c8853f14Michael Kolb center.y + inner); 3621373b98135b2854578111dd535e24d39c8853f14Michael Kolb Path path = new Path(); 3631373b98135b2854578111dd535e24d39c8853f14Michael Kolb path.arcTo(bb, start, end - start, true); 3641373b98135b2854578111dd535e24d39c8853f14Michael Kolb path.arcTo(bbi, end, start - end); 3651373b98135b2854578111dd535e24d39c8853f14Michael Kolb path.close(); 3661373b98135b2854578111dd535e24d39c8853f14Michael Kolb return path; 3671373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 3681373b98135b2854578111dd535e24d39c8853f14Michael Kolb 3691373b98135b2854578111dd535e24d39c8853f14Michael Kolb /** 3701373b98135b2854578111dd535e24d39c8853f14Michael Kolb * converts a 371b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb * @param angle from 0..PI to Android degrees (clockwise starting at 3 o'clock) 3721373b98135b2854578111dd535e24d39c8853f14Michael Kolb * @return skia angle 3731373b98135b2854578111dd535e24d39c8853f14Michael Kolb */ 3741373b98135b2854578111dd535e24d39c8853f14Michael Kolb private float getDegrees(double angle) { 3751373b98135b2854578111dd535e24d39c8853f14Michael Kolb return (float) (360 - 180 * angle / Math.PI); 3761373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 3771373b98135b2854578111dd535e24d39c8853f14Michael Kolb 3781373b98135b2854578111dd535e24d39c8853f14Michael Kolb @Override 3791373b98135b2854578111dd535e24d39c8853f14Michael Kolb public void onDraw(Canvas canvas) { 3808042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb drawFocus(canvas); 3818042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb if (mState == STATE_FINISHING) return; 382c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb if (mAnimating) { 383c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb setViewAlpha(mOverlay, mAlpha); 384c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb } 385ad639dff251233032734106afe4fe51a52be3721Michael Kolb if (mOpenItem == null) { 386ad639dff251233032734106afe4fe51a52be3721Michael Kolb // draw base menu 387ad639dff251233032734106afe4fe51a52be3721Michael Kolb for (PieItem item : mItems) { 388ad639dff251233032734106afe4fe51a52be3721Michael Kolb drawItem(canvas, item); 389ad639dff251233032734106afe4fe51a52be3721Michael Kolb } 390ad639dff251233032734106afe4fe51a52be3721Michael Kolb } else { 391ad639dff251233032734106afe4fe51a52be3721Michael Kolb for (PieItem inner : mOpenItem.getItems()) { 392ad639dff251233032734106afe4fe51a52be3721Michael Kolb drawItem(canvas, inner); 3931373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 3941373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 3951373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 3961373b98135b2854578111dd535e24d39c8853f14Michael Kolb 3971373b98135b2854578111dd535e24d39c8853f14Michael Kolb private void drawItem(Canvas canvas, PieItem item) { 3981373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (item.getView() != null) { 399673da081181c72352d57c9bf97badb2929370685Michael Kolb if ((mFocusFromTap && (mState == STATE_FOCUSING)) || (mState == STATE_PIE)) { 4001404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb if (item.getPath() != null) { 4011404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb Paint p = item.isSelected() ? mSelectedPaint : mNormalPaint; 4021404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb int state = canvas.save(); 4031404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb float r = getDegrees(item.getStartAngle()); 4041404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb canvas.rotate(r, mCenter.x, mCenter.y); 4051404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb canvas.drawPath(item.getPath(), p); 4061404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb canvas.restoreToCount(state); 4071404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb // draw the item view 4081404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb View view = item.getView(); 4091404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb state = canvas.save(); 4101404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb canvas.translate(view.getX(), view.getY()); 4111404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb view.draw(canvas); 4121404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb canvas.restoreToCount(state); 4131404be918ef3e5e5150c13c5a89a66b83a816846Michael Kolb } 414a0dd52298b55357a711663180677efa39d35e5abMichael Kolb } else if (mState == STATE_FOCUSING && !mFocusFromTap) { 415a0dd52298b55357a711663180677efa39d35e5abMichael Kolb View view = item.getView(); 416a0dd52298b55357a711663180677efa39d35e5abMichael Kolb canvas.drawCircle(view.getLeft() + view.getWidth() / 2, 417a0dd52298b55357a711663180677efa39d35e5abMichael Kolb view.getTop() + view.getHeight() / 2, mDotRadius, 418a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mDotPaint); 4198042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 4201373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4211373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4221373b98135b2854578111dd535e24d39c8853f14Michael Kolb 423c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) 424c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb private void setViewAlpha(View v, float alpha) { 425c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb if (ApiHelper.HAS_VIEW_TRANSFORM_PROPERTIES) { 426c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb v.setAlpha(alpha); 427c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb } 428c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb } 429c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb 4301373b98135b2854578111dd535e24d39c8853f14Michael Kolb // touch handling for pie 4311373b98135b2854578111dd535e24d39c8853f14Michael Kolb 4321373b98135b2854578111dd535e24d39c8853f14Michael Kolb @Override 4331373b98135b2854578111dd535e24d39c8853f14Michael Kolb public boolean onTouchEvent(MotionEvent evt) { 4341373b98135b2854578111dd535e24d39c8853f14Michael Kolb float x = evt.getX(); 4351373b98135b2854578111dd535e24d39c8853f14Michael Kolb float y = evt.getY(); 4361373b98135b2854578111dd535e24d39c8853f14Michael Kolb int action = evt.getActionMasked(); 4371373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (MotionEvent.ACTION_DOWN == action) { 4381373b98135b2854578111dd535e24d39c8853f14Michael Kolb setCenter((int) x, (int) y); 4394d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb show(true); 4401373b98135b2854578111dd535e24d39c8853f14Michael Kolb return true; 4411373b98135b2854578111dd535e24d39c8853f14Michael Kolb } else if (MotionEvent.ACTION_UP == action) { 442673da081181c72352d57c9bf97badb2929370685Michael Kolb if (isVisible() || mShowItems) { 4431373b98135b2854578111dd535e24d39c8853f14Michael Kolb PieItem item = mCurrentItem; 4441373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (!mAnimating) { 4451373b98135b2854578111dd535e24d39c8853f14Michael Kolb deselect(); 4461373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4471373b98135b2854578111dd535e24d39c8853f14Michael Kolb show(false); 4481373b98135b2854578111dd535e24d39c8853f14Michael Kolb if ((item != null) && (item.getView() != null)) { 4491373b98135b2854578111dd535e24d39c8853f14Michael Kolb if ((item == mOpenItem) || !mAnimating) { 4501373b98135b2854578111dd535e24d39c8853f14Michael Kolb item.getView().performClick(); 4511373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4521373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4531373b98135b2854578111dd535e24d39c8853f14Michael Kolb return true; 4541373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4551373b98135b2854578111dd535e24d39c8853f14Michael Kolb } else if (MotionEvent.ACTION_CANCEL == action) { 456673da081181c72352d57c9bf97badb2929370685Michael Kolb if (isVisible() || mShowItems) { 4571373b98135b2854578111dd535e24d39c8853f14Michael Kolb show(false); 4581373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4591373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (!mAnimating) { 4601373b98135b2854578111dd535e24d39c8853f14Michael Kolb deselect(); 4611373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4621373b98135b2854578111dd535e24d39c8853f14Michael Kolb return false; 4631373b98135b2854578111dd535e24d39c8853f14Michael Kolb } else if (MotionEvent.ACTION_MOVE == action) { 4641373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (mAnimating) return false; 465673da081181c72352d57c9bf97badb2929370685Michael Kolb PointF polar = getPolar(x, y, true); 4664d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb if (polar.y < mRadius) { 4674d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb if (mOpenItem != null) { 4684d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb mOpenItem = null; 4694d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb } else if (!mAnimating) { 4701373b98135b2854578111dd535e24d39c8853f14Michael Kolb deselect(); 4711373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4724d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb return false; 4734d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb } 4744d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb PieItem item = findItem(polar); 475d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb if ((item != null) && (mCurrentItem != item)) { 4764d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb onEnter(item); 4771373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4781373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4791373b98135b2854578111dd535e24d39c8853f14Michael Kolb return false; 4801373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4811373b98135b2854578111dd535e24d39c8853f14Michael Kolb 4821373b98135b2854578111dd535e24d39c8853f14Michael Kolb /** 4831373b98135b2854578111dd535e24d39c8853f14Michael Kolb * enter a slice for a view 4841373b98135b2854578111dd535e24d39c8853f14Michael Kolb * updates model only 4851373b98135b2854578111dd535e24d39c8853f14Michael Kolb * @param item 4861373b98135b2854578111dd535e24d39c8853f14Michael Kolb */ 4871373b98135b2854578111dd535e24d39c8853f14Michael Kolb private void onEnter(PieItem item) { 4881373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (mCurrentItem != null) { 4891373b98135b2854578111dd535e24d39c8853f14Michael Kolb mCurrentItem.setSelected(false); 4901373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4912d3af28f91481d7f3887cb0bb9c5d06375baf787Michael Kolb if (item != null && item.isEnabled()) { 4921373b98135b2854578111dd535e24d39c8853f14Michael Kolb item.setSelected(true); 4931373b98135b2854578111dd535e24d39c8853f14Michael Kolb mCurrentItem = item; 4941373b98135b2854578111dd535e24d39c8853f14Michael Kolb if ((mCurrentItem != mOpenItem) && mCurrentItem.hasItems()) { 4951373b98135b2854578111dd535e24d39c8853f14Michael Kolb mHandler.sendEmptyMessageDelayed(MSG_SUBMENU, PIE_OPEN_DELAY); 4961373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 4971373b98135b2854578111dd535e24d39c8853f14Michael Kolb } else { 4981373b98135b2854578111dd535e24d39c8853f14Michael Kolb mCurrentItem = null; 4991373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5001373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5011373b98135b2854578111dd535e24d39c8853f14Michael Kolb 5021373b98135b2854578111dd535e24d39c8853f14Michael Kolb private void deselect() { 5031373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (mCurrentItem != null) { 5041373b98135b2854578111dd535e24d39c8853f14Michael Kolb mCurrentItem.setSelected(false); 5051373b98135b2854578111dd535e24d39c8853f14Michael Kolb mHandler.removeMessages(MSG_SUBMENU); 5061373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5071373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (mOpenItem != null) { 5081373b98135b2854578111dd535e24d39c8853f14Michael Kolb mOpenItem = null; 5091373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5101373b98135b2854578111dd535e24d39c8853f14Michael Kolb mCurrentItem = null; 5111373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5121373b98135b2854578111dd535e24d39c8853f14Michael Kolb 5131373b98135b2854578111dd535e24d39c8853f14Michael Kolb private void openCurrentItem() { 5141373b98135b2854578111dd535e24d39c8853f14Michael Kolb if ((mCurrentItem != null) && mCurrentItem.hasItems()) { 5151373b98135b2854578111dd535e24d39c8853f14Michael Kolb mOpenItem = mCurrentItem; 5161373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5171373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5181373b98135b2854578111dd535e24d39c8853f14Michael Kolb 519673da081181c72352d57c9bf97badb2929370685Michael Kolb private PointF getPolar(float x, float y, boolean useOffset) { 5201373b98135b2854578111dd535e24d39c8853f14Michael Kolb PointF res = new PointF(); 5211373b98135b2854578111dd535e24d39c8853f14Michael Kolb // get angle and radius from x/y 5221373b98135b2854578111dd535e24d39c8853f14Michael Kolb res.x = (float) Math.PI / 2; 5231373b98135b2854578111dd535e24d39c8853f14Michael Kolb x = x - mCenter.x; 5241373b98135b2854578111dd535e24d39c8853f14Michael Kolb y = mCenter.y - y; 525a521253223897b099995e0af08982b4236ce5861Michael Kolb res.y = (float) Math.sqrt(x * x + y * y); 5261373b98135b2854578111dd535e24d39c8853f14Michael Kolb if (x != 0) { 5271373b98135b2854578111dd535e24d39c8853f14Michael Kolb res.x = (float) Math.atan2(y, x); 528b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb if (res.x < 0) { 529b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb res.x = (float) (2 * Math.PI + res.x); 530b5b59b88683823d70faac7b3454519d53c51180bMichael Kolb } 5311373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 532673da081181c72352d57c9bf97badb2929370685Michael Kolb res.y = res.y + (useOffset ? mTouchOffset : 0); 5331373b98135b2854578111dd535e24d39c8853f14Michael Kolb return res; 5341373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5351373b98135b2854578111dd535e24d39c8853f14Michael Kolb 5361373b98135b2854578111dd535e24d39c8853f14Michael Kolb /** 5371373b98135b2854578111dd535e24d39c8853f14Michael Kolb * @param polar x: angle, y: dist 5381373b98135b2854578111dd535e24d39c8853f14Michael Kolb * @return the item at angle/dist or null 5391373b98135b2854578111dd535e24d39c8853f14Michael Kolb */ 5401373b98135b2854578111dd535e24d39c8853f14Michael Kolb private PieItem findItem(PointF polar) { 5411373b98135b2854578111dd535e24d39c8853f14Michael Kolb // find the matching item: 5421373b98135b2854578111dd535e24d39c8853f14Michael Kolb List<PieItem> items = (mOpenItem != null) ? mOpenItem.getItems() : mItems; 5431373b98135b2854578111dd535e24d39c8853f14Michael Kolb for (PieItem item : items) { 544a521253223897b099995e0af08982b4236ce5861Michael Kolb if (inside(polar, item)) { 5451373b98135b2854578111dd535e24d39c8853f14Michael Kolb return item; 5461373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5471373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5481373b98135b2854578111dd535e24d39c8853f14Michael Kolb return null; 5491373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5501373b98135b2854578111dd535e24d39c8853f14Michael Kolb 551a521253223897b099995e0af08982b4236ce5861Michael Kolb private boolean inside(PointF polar, PieItem item) { 552a521253223897b099995e0af08982b4236ce5861Michael Kolb return (item.getInnerRadius() < polar.y) 5531373b98135b2854578111dd535e24d39c8853f14Michael Kolb && (item.getStartAngle() < polar.x) 5541373b98135b2854578111dd535e24d39c8853f14Michael Kolb && (item.getStartAngle() + item.getSweep() > polar.x); 5551373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5561373b98135b2854578111dd535e24d39c8853f14Michael Kolb 5571373b98135b2854578111dd535e24d39c8853f14Michael Kolb @Override 5581373b98135b2854578111dd535e24d39c8853f14Michael Kolb public boolean handlesTouch() { 5591373b98135b2854578111dd535e24d39c8853f14Michael Kolb return true; 5601373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 5611373b98135b2854578111dd535e24d39c8853f14Michael Kolb 5628042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private class AlphaAnimation extends Animation { 5638042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb @Override 5648042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb protected void applyTransformation(float interpolatedTime, Transformation t) { 5658042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mAlpha = 1 - interpolatedTime; 5668042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 5678042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 5688042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 5698042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb // focus specific code 5708042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 5718042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void setFocus(int x, int y) { 572a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mFocusFromTap = true; 573a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mShowItems = true; 5748042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb switch(mOverlay.getOrientation()) { 5758042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb case 0: 5768042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusX = x; 5778042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusY = y; 5788042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb break; 5798042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb case 180: 5808042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusX = getWidth() - x; 5818042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusY = getHeight() - y; 5828042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb break; 5838042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb case 90: 5848042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusX = getWidth() - y; 5858042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusY = x; 5868042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb break; 5878042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb case 270: 5888042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusX = y ; 5898042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusY = getHeight() - x; 5908042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb break; 5918042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 5928042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb setCircle(mFocusX, mFocusY); 5938042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb setupPie(mFocusX, mFocusY); 5948042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 5958042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 5968042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void alignFocus(int x, int y) { 5978042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mOverlay.removeCallbacks(mDisappear); 5988042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mAnimation.cancel(); 5998042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mAnimation.reset(); 6008042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusX = x; 6018042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusY = y; 6028042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mDialAngle = DIAL_HORIZONTAL; 6038042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb setCircle(x, y); 6048042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocused = false; 6058042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6068042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 6078042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public int getSize() { 6088042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb return 2 * mCircleSize; 6098042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6108042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 6118042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private int getRandomRange() { 612673da081181c72352d57c9bf97badb2929370685Michael Kolb return (int)(-60 + 120 * Math.random()); 6138042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6148042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 6151373b98135b2854578111dd535e24d39c8853f14Michael Kolb @Override 6161373b98135b2854578111dd535e24d39c8853f14Michael Kolb public void layout(int l, int t, int r, int b) { 6171373b98135b2854578111dd535e24d39c8853f14Michael Kolb super.layout(l, t, r, b); 6188042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mCenterX = (r - l) / 2; 6198042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mCenterY = (b - t) / 2; 6208042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusX = mCenterX; 6218042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusY = mCenterY; 6228042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb setCircle(mFocusX, mFocusY); 623a0dd52298b55357a711663180677efa39d35e5abMichael Kolb if (mShowFade) { 6248042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb fade(); 6258042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6261373b98135b2854578111dd535e24d39c8853f14Michael Kolb } 6271373b98135b2854578111dd535e24d39c8853f14Michael Kolb 6288042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private void setCircle(int cx, int cy) { 6298042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mCircle.set(cx - mCircleSize, cy - mCircleSize, 6308042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb cx + mCircleSize, cy + mCircleSize); 6318042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mDial.set(cx - mCircleSize + mInnerOffset, cy - mCircleSize + mInnerOffset, 6328042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb cx + mCircleSize - mInnerOffset, cy + mCircleSize - mInnerOffset); 6338042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6348042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 6358042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void drawFocus(Canvas canvas) { 6368042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusPaint.setStrokeWidth(mOuterStroke); 6378042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb canvas.drawCircle((float) mFocusX, (float) mFocusY, (float) mCircleSize, mFocusPaint); 638673da081181c72352d57c9bf97badb2929370685Michael Kolb int color = mFocusPaint.getColor(); 639673da081181c72352d57c9bf97badb2929370685Michael Kolb if (mState == STATE_FINISHING) { 640673da081181c72352d57c9bf97badb2929370685Michael Kolb mFocusPaint.setColor(mFocused ? mSuccessColor : mFailColor); 641673da081181c72352d57c9bf97badb2929370685Michael Kolb } 642673da081181c72352d57c9bf97badb2929370685Michael Kolb mFocusPaint.setStrokeWidth(mInnerStroke); 643673da081181c72352d57c9bf97badb2929370685Michael Kolb canvas.drawArc(mDial, mDialAngle, 45, false, mFocusPaint); 644673da081181c72352d57c9bf97badb2929370685Michael Kolb canvas.drawArc(mDial, mDialAngle + 180, 45, false, mFocusPaint); 645673da081181c72352d57c9bf97badb2929370685Michael Kolb drawLine(canvas, mDialAngle, mFocusPaint); 646673da081181c72352d57c9bf97badb2929370685Michael Kolb drawLine(canvas, mDialAngle + 45, mFocusPaint); 647673da081181c72352d57c9bf97badb2929370685Michael Kolb drawLine(canvas, mDialAngle + 180, mFocusPaint); 648673da081181c72352d57c9bf97badb2929370685Michael Kolb drawLine(canvas, mDialAngle + 225, mFocusPaint); 649673da081181c72352d57c9bf97badb2929370685Michael Kolb mFocusPaint.setColor(color); 6508042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6518042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 6528042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private void drawLine(Canvas canvas, int angle, Paint p) { 6538042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb convertCart(angle, mCircleSize - mInnerOffset, mPoint1); 6548042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb convertCart(angle, mCircleSize - mInnerOffset + mInnerOffset / 3, mPoint2); 6558042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb canvas.drawLine(mPoint1.x + mFocusX, mPoint1.y + mFocusY, 6568042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mPoint2.x + mFocusX, mPoint2.y + mFocusY, p); 6578042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6588042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 6598042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private static void convertCart(int angle, int radius, Point out) { 6608042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb double a = 2 * Math.PI * (angle % 360) / 360; 6618042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb out.x = (int) (radius * Math.cos(a) + 0.5); 6628042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb out.y = (int) (radius * Math.sin(a) + 0.5); 6638042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6648042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 6658042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb @Override 6668042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void showStart() { 667b8c5a15af9e8f1adb1849072a6f5a1830887b43eMichael Kolb if (mAnimating) { 668b8c5a15af9e8f1adb1849072a6f5a1830887b43eMichael Kolb mState = STATE_IDLE; 669d867ac51170831bf4e6021453fdc4468e10087c7Michael Kolb resetAnimation(); 670b8c5a15af9e8f1adb1849072a6f5a1830887b43eMichael Kolb } 6718042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb if (mState == STATE_IDLE) { 672a0dd52298b55357a711663180677efa39d35e5abMichael Kolb if (mFocusFromTap) { 673a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mHandler.removeMessages(MSG_FOCUS_TAP); 674a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_FOCUS_TAP), 675a0dd52298b55357a711663180677efa39d35e5abMichael Kolb FOCUS_TAP_TIMEOUT); 676a0dd52298b55357a711663180677efa39d35e5abMichael Kolb } 677673da081181c72352d57c9bf97badb2929370685Michael Kolb mStartAnimationAngle = 67; 6788042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb int range = getRandomRange(); 679673da081181c72352d57c9bf97badb2929370685Michael Kolb startAnimation(SCALING_UP_TIME, 680673da081181c72352d57c9bf97badb2929370685Michael Kolb false, mStartAnimationAngle, mStartAnimationAngle + range); 6818042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mState = STATE_FOCUSING; 6828042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6838042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6848042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 6858042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb @Override 6868042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void showSuccess(boolean timeout) { 6878042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb if (mState == STATE_FOCUSING) { 688673da081181c72352d57c9bf97badb2929370685Michael Kolb startAnimation(SCALING_DOWN_TIME, 6898042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb timeout, mStartAnimationAngle); 6908042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mState = STATE_FINISHING; 6918042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocused = true; 6928042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6938042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 6948042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 6958042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb @Override 6968042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void showFail(boolean timeout) { 6978042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb if (mState == STATE_FOCUSING) { 698673da081181c72352d57c9bf97badb2929370685Michael Kolb startAnimation(SCALING_DOWN_TIME, 6998042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb timeout, mStartAnimationAngle); 7008042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mState = STATE_FINISHING; 7018042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocused = false; 7028042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7038042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7048042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 7058042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb @Override 7068042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void clear() { 707b986d1e51d776706cb3603a9c386772da6d7cf48Michael Kolb if (mState == STATE_PIE) return; 7088042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mAnimation.cancel(); 7098042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocused = false; 710a0dd52298b55357a711663180677efa39d35e5abMichael Kolb mFocusFromTap = false; 7118042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mOverlay.removeCallbacks(mDisappear); 7128042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mDisappear.run(); 7138042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7148042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 715673da081181c72352d57c9bf97badb2929370685Michael Kolb private void startAnimation(long duration, boolean timeout, 7168042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb float toScale) { 717673da081181c72352d57c9bf97badb2929370685Michael Kolb startAnimation(duration, timeout, mDialAngle, 7188042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb toScale); 7198042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7208042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 721673da081181c72352d57c9bf97badb2929370685Michael Kolb private void startAnimation(long duration, boolean timeout, 7228042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb float fromScale, float toScale) { 7238042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb setVisible(true); 7248042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mAnimation.cancel(); 7258042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mAnimation.reset(); 7268042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mAnimation.setDuration(duration); 7278042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mAnimation.setScale(fromScale, toScale); 7288042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mAnimation.setAnimationListener(timeout ? mEndAction : null); 7298042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mOverlay.startAnimation(mAnimation); 7308042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb update(); 7318042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7328042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 7338042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private class EndAction implements Animation.AnimationListener { 7348042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb @Override 7358042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void onAnimationEnd(Animation animation) { 7368042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb // Keep the focus indicator for some time. 7378042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mOverlay.postDelayed(mDisappear, DISAPPEAR_TIMEOUT); 7388042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7398042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 7408042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb @Override 7418042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void onAnimationRepeat(Animation animation) { 7428042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7438042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 7448042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb @Override 7458042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void onAnimationStart(Animation animation) { 7468042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7478042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7488042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 7498042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private class Disappear implements Runnable { 7508042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb @Override 7518042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void run() { 7528042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb setVisible(false); 7538042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusX = mCenterX; 7548042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocusY = mCenterY; 7558042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mState = STATE_IDLE; 7568042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb setCircle(mFocusX, mFocusY); 7578042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb setupPie(mFocusX, mFocusY); 7588042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFocused = false; 7598042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7608042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7618042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 7628042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private class ScaleAnimation extends Animation { 7638042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private float mFrom = 1f; 7648042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb private float mTo = 1f; 7658042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 7668042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public ScaleAnimation() { 7678042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb setFillAfter(true); 7688042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7698042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 7708042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb public void setScale(float from, float to) { 7718042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mFrom = from; 7728042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mTo = to; 7738042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb } 7748042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb 775c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb @Override 776c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb protected void applyTransformation(float interpolatedTime, Transformation t) { 7778042e7045f3e11dd49d40eebe603eb5fe12d711aMichael Kolb mDialAngle = (int)(mFrom + (mTo - mFrom) * interpolatedTime); 778c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb } 779c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb } 780c605826581f2ef1640828af82dbf26a70d4c7c78Michael Kolb 7811373b98135b2854578111dd535e24d39c8853f14Michael Kolb} 782