18872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb/* 28872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Copyright (C) 2012 The Android Open Source Project 38872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * 48872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Licensed under the Apache License, Version 2.0 (the "License"); 58872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * you may not use this file except in compliance with the License. 68872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * You may obtain a copy of the License at 78872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * 88872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * http://www.apache.org/licenses/LICENSE-2.0 98872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * 108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * Unless required by applicable law or agreed to in writing, software 118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * distributed under the License is distributed on an "AS IS" BASIS, 128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * See the License for the specific language governing permissions and 148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * limitations under the License. 158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */ 168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 178872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbpackage com.android.camera.ui; 188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 191b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liuimport android.animation.Animator; 201b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liuimport android.animation.Animator.AnimatorListener; 211b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liuimport android.animation.ValueAnimator; 228872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.content.Context; 238872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.content.res.Resources; 248872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.graphics.Canvas; 258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.graphics.Color; 268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.graphics.Paint; 278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.graphics.Path; 288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.graphics.Point; 298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.graphics.PointF; 308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.graphics.RectF; 318872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.os.Handler; 328872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.os.Message; 330f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolbimport android.util.FloatMath; 348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.view.MotionEvent; 358872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.view.ViewConfiguration; 368872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.view.animation.Animation; 378872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbimport android.view.animation.Transformation; 388872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 3910f4ba0198904a3d7679771ce845c847d940226fMichael Kolbimport com.android.camera.drawable.TextDrawable; 4054d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberlingimport com.android.camera.ui.ProgressRenderer.VisibilityListener; 418e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberlingimport com.android.camera2.R; 428872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 4354d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberlingimport java.util.ArrayList; 4454d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberlingimport java.util.List; 4554d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling 46e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling/** 47e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * An overlay renderer that is used to display focus state and progress state. 48e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling */ 498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolbpublic class PieRenderer extends OverlayRenderer 508872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb implements FocusIndicator { 518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 52e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling private static final String TAG = "PieRenderer"; 538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 548872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // Sometimes continuous autofocus starts and stops several times quickly. 558872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // These states are used to make sure the animation is run for at least some 568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // time. 578872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private volatile int mState; 588872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private ScaleAnimation mAnimation = new ScaleAnimation(); 598872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final int STATE_IDLE = 0; 608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final int STATE_FOCUSING = 1; 618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final int STATE_FINISHING = 2; 628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final int STATE_PIE = 8; 638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 643bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private static final float MATH_PI_2 = (float)(Math.PI / 2); 653bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 668872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private Runnable mDisappear = new Disappear(); 678872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private Animation.AnimationListener mEndAction = new EndAction(); 688872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final int SCALING_UP_TIME = 600; 698872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final int SCALING_DOWN_TIME = 100; 708872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final int DISAPPEAR_TIMEOUT = 200; 718872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final int DIAL_HORIZONTAL = 157; 72ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb // fade out timings 73ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb private static final int PIE_FADE_OUT_DURATION = 600; 748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final long PIE_FADE_IN_DURATION = 200; 768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final long PIE_XFADE_DURATION = 200; 778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final long PIE_SELECT_FADE_DURATION = 300; 783bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private static final long PIE_OPEN_SUB_DELAY = 400; 79ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb private static final long PIE_SLICE_DURATION = 80; 808872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final int MSG_OPEN = 0; 828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static final int MSG_CLOSE = 1; 833bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private static final int MSG_OPENSUBMENU = 2; 843daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb 853daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb protected static float CENTER = (float) Math.PI / 2; 86f465110e4b8ed787589e052e5ac746c588c5ac8fMichael Kolb protected static float RAD24 = (float)(24 * Math.PI / 180); 873daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb protected static final float SWEEP_SLICE = 0.14f; 883daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb protected static final float SWEEP_ARC = 0.23f; 893daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb 908872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // geometry 918872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mRadius; 923daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb private int mRadiusInc; 938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 948872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // the detection if touch is inside a slice is offset 958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // inbounds by this amount to allow the selection to show before the 968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // finger covers it 978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mTouchOffset; 988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 993bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private List<PieItem> mOpen; 1008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private Paint mSelectedPaint; 1028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private Paint mSubPaint; 1033bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private Paint mMenuArcPaint; 1048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // touch handling 1068872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private PieItem mCurrentItem; 1078872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private Paint mFocusPaint; 1098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mSuccessColor; 1108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mFailColor; 1118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mCircleSize; 1128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mFocusX; 1138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mFocusY; 1148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mCenterX; 1158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mCenterY; 1163daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb private int mArcCenterY; 1173daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb private int mSliceCenterY; 1183bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private int mPieCenterX; 1193bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private int mPieCenterY; 1203daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb private int mSliceRadius; 1213bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private int mArcRadius; 1223bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private int mArcOffset; 1238872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1248872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mDialAngle; 1258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private RectF mCircle; 1268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private RectF mDial; 1278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private Point mPoint1; 1288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private Point mPoint2; 1298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mStartAnimationAngle; 1308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private boolean mFocused; 1318872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mInnerOffset; 1328872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mOuterStroke; 1338872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mInnerStroke; 1348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private boolean mTapMode; 1358872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private boolean mBlockFocus; 1368872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int mTouchSlopSquared; 1378872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private Point mDown; 1388872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private boolean mOpening; 1391b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu private ValueAnimator mXFade; 1401b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu private ValueAnimator mFadeIn; 1411b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu private ValueAnimator mFadeOut; 1421b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu private ValueAnimator mSlice; 1438872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private volatile boolean mFocusCancelled; 1443daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb private PointF mPolar = new PointF(); 14510f4ba0198904a3d7679771ce845c847d940226fMichael Kolb private TextDrawable mLabel; 1460f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb private int mDeadZone; 1470f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb private int mAngleZone; 1480f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb private float mCenterAngle; 1493daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb 150e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling private ProgressRenderer mProgressRenderer; 1518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1528872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private Handler mHandler = new Handler() { 1538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void handleMessage(Message msg) { 1548872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb switch(msg.what) { 1558872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb case MSG_OPEN: 1568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mListener != null) { 1573bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mListener.onPieOpened(mPieCenterX, mPieCenterY); 1588872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1598872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb break; 1608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb case MSG_CLOSE: 1618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mListener != null) { 1628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mListener.onPieClosed(); 1638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1648872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb break; 1653bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb case MSG_OPENSUBMENU: 1663bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb onEnterOpen(); 1673bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb break; 1688872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1693bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 1708872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1718872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb }; 1728872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private PieListener mListener; 1748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb static public interface PieListener { 1768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void onPieOpened(int centerX, int centerY); 1778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void onPieClosed(); 1788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1798872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1808872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void setPieListener(PieListener pl) { 1818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mListener = pl; 1828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1838872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1848872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public PieRenderer(Context context) { 1858872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb init(context); 1868872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 1878872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 1888872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void init(Context ctx) { 1898872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb setVisible(false); 1903bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mOpen = new ArrayList<PieItem>(); 1913bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mOpen.add(new PieItem(null, 0)); 1928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb Resources res = ctx.getResources(); 1938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mRadius = (int) res.getDimensionPixelSize(R.dimen.pie_radius_start); 1943daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb mRadiusInc = (int) res.getDimensionPixelSize(R.dimen.pie_radius_increment); 1958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mCircleSize = mRadius - res.getDimensionPixelSize(R.dimen.focus_radius_offset); 1968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mTouchOffset = (int) res.getDimensionPixelSize(R.dimen.pie_touch_offset); 1978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mSelectedPaint = new Paint(); 1988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mSelectedPaint.setColor(Color.argb(255, 51, 181, 229)); 1998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mSelectedPaint.setAntiAlias(true); 2008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mSubPaint = new Paint(); 2018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mSubPaint.setAntiAlias(true); 2028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mSubPaint.setColor(Color.argb(200, 250, 230, 128)); 2038872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusPaint = new Paint(); 2048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusPaint.setAntiAlias(true); 2058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusPaint.setColor(Color.WHITE); 2068872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusPaint.setStyle(Paint.Style.STROKE); 2078872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mSuccessColor = Color.GREEN; 2088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFailColor = Color.RED; 2098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mCircle = new RectF(); 2108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mDial = new RectF(); 2118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mPoint1 = new Point(); 2128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mPoint2 = new Point(); 2138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mInnerOffset = res.getDimensionPixelSize(R.dimen.focus_inner_offset); 2148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mOuterStroke = res.getDimensionPixelSize(R.dimen.focus_outer_stroke); 2158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mInnerStroke = res.getDimensionPixelSize(R.dimen.focus_inner_stroke); 2168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mState = STATE_IDLE; 2178872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mBlockFocus = false; 2188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mTouchSlopSquared = ViewConfiguration.get(ctx).getScaledTouchSlop(); 2198872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mTouchSlopSquared = mTouchSlopSquared * mTouchSlopSquared; 2208872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mDown = new Point(); 2213bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mMenuArcPaint = new Paint(); 2223bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mMenuArcPaint.setAntiAlias(true); 2233bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mMenuArcPaint.setColor(Color.argb(140, 255, 255, 255)); 2243bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mMenuArcPaint.setStrokeWidth(10); 2253bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mMenuArcPaint.setStyle(Paint.Style.STROKE); 2263daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb mSliceRadius = res.getDimensionPixelSize(R.dimen.pie_item_radius); 2273bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mArcRadius = res.getDimensionPixelSize(R.dimen.pie_arc_radius); 2283bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mArcOffset = res.getDimensionPixelSize(R.dimen.pie_arc_offset); 22910f4ba0198904a3d7679771ce845c847d940226fMichael Kolb mLabel = new TextDrawable(res); 230f465110e4b8ed787589e052e5ac746c588c5ac8fMichael Kolb mLabel.setDropShadow(true); 2310f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb mDeadZone = res.getDimensionPixelSize(R.dimen.pie_deadzone_width); 2320f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb mAngleZone = res.getDimensionPixelSize(R.dimen.pie_anglezone_width); 233e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling mProgressRenderer = new ProgressRenderer(ctx); 2343bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 2353bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 2363bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private PieItem getRoot() { 2373bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb return mOpen.get(0); 2388872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 2398872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 2408872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public boolean showsItems() { 2418872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return mTapMode; 2428872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 2438872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 2448872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void addItem(PieItem item) { 2458872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // add the item to the pie itself 2463bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb getRoot().addItem(item); 2478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 2488872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 2498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void clearItems() { 2503bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb getRoot().clearItems(); 2518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 2528872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 2538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void showInCenter() { 2548872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if ((mState == STATE_PIE) && isVisible()) { 2558872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mTapMode = false; 2568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb show(false); 2578872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else { 2588872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mState != STATE_IDLE) { 2598872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb cancelFocus(); 2608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 2618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mState = STATE_PIE; 2623bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb resetPieCenter(); 2633bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb setCenter(mPieCenterX, mPieCenterY); 2648872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mTapMode = true; 2658872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb show(true); 2668872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 2678872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 2688872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 2698872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void hide() { 2708872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb show(false); 2718872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 2728872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 2738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb /** 2748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * guaranteed has center set 2758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * @param show 2768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */ 2778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void show(boolean show) { 2788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (show) { 2790233bade51dfcce5fa1f49b5c2e200a719feab22Michael Kolb if (mXFade != null) { 2800233bade51dfcce5fa1f49b5c2e200a719feab22Michael Kolb mXFade.cancel(); 2810233bade51dfcce5fa1f49b5c2e200a719feab22Michael Kolb } 2828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mState = STATE_PIE; 2838872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // ensure clean state 2848872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mCurrentItem = null; 2853bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb PieItem root = getRoot(); 2863bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb for (PieItem openItem : mOpen) { 2873bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (openItem.hasItems()) { 2883bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb for (PieItem item : openItem.getItems()) { 2893bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb item.setSelected(false); 2903bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 2913bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 2928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 29310f4ba0198904a3d7679771ce845c847d940226fMichael Kolb mLabel.setText(""); 2943bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mOpen.clear(); 2953bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mOpen.add(root); 2968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb layoutPie(); 2978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb fadeIn(); 2988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else { 2998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mState = STATE_IDLE; 3008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mTapMode = false; 3018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mXFade != null) { 3028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mXFade.cancel(); 3038872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 3049e012f853e3eb5c9d36c84351961f588eef4788fMichael Kolb if (mLabel != null) { 3059e012f853e3eb5c9d36c84351961f588eef4788fMichael Kolb mLabel.setText(""); 3069e012f853e3eb5c9d36c84351961f588eef4788fMichael Kolb } 3078872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 3088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb setVisible(show); 3098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mHandler.sendEmptyMessage(show ? MSG_OPEN : MSG_CLOSE); 3108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 3118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 312fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu public boolean isOpen() { 313fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu return mState == STATE_PIE && isVisible(); 314fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu } 315fb57df15a87f95ce8b2f861e54d960602912e03cDoris Liu 316e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling public void setProgress(int percent) { 317e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling mProgressRenderer.setProgress(percent); 318e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling } 319e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling 3208872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void fadeIn() { 3211b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mFadeIn = new ValueAnimator(); 3221b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mFadeIn.setFloatValues(0f, 1f); 3238872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFadeIn.setDuration(PIE_FADE_IN_DURATION); 3241b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu // linear interpolation 3251b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mFadeIn.setInterpolator(null); 3261b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mFadeIn.addListener(new AnimatorListener() { 3278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 3281b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationStart(Animator animation) { 3298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 3308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 3318872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 3321b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationEnd(Animator animation) { 3338872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFadeIn = null; 3348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 3358872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 3368872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 3371b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationRepeat(Animator animation) { 3381b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu } 3391b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu 3401b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu @Override 3411b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationCancel(Animator arg0) { 3428872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 3438872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb }); 3441b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mFadeIn.start(); 3458872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 3468872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 3478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void setCenter(int x, int y) { 3483bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mPieCenterX = x; 3493bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mPieCenterY = y; 3500f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb mSliceCenterY = y + mSliceRadius - mArcOffset; 3513daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb mArcCenterY = y - mArcOffset + mArcRadius; 3523bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 3533bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 3543bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb @Override 3553bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb public void layout(int l, int t, int r, int b) { 3563bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb super.layout(l, t, r, b); 3573bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mCenterX = (r - l) / 2; 3583bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mCenterY = (b - t) / 2; 3593bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 3603bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mFocusX = mCenterX; 3613bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mFocusY = mCenterY; 3623bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb resetPieCenter(); 3633bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb setCircle(mFocusX, mFocusY); 3643bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (isVisible() && mState == STATE_PIE) { 3653bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb setCenter(mPieCenterX, mPieCenterY); 3663bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb layoutPie(); 3673bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 3683bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 3693bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 3703bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private void resetPieCenter() { 3713bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mPieCenterX = mCenterX; 372f465110e4b8ed787589e052e5ac746c588c5ac8fMichael Kolb mPieCenterY = (int) (getHeight() - 2.5f * mDeadZone); 3738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 3748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 3758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void layoutPie() { 3760f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb mCenterAngle = getCenterAngle(); 3773daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb layoutItems(0, getRoot().getItems()); 37860e938e0caed26441e0ab784344fd161954dc8abMichael Kolb layoutLabel(getLevel()); 37910f4ba0198904a3d7679771ce845c847d940226fMichael Kolb } 38010f4ba0198904a3d7679771ce845c847d940226fMichael Kolb 38110f4ba0198904a3d7679771ce845c847d940226fMichael Kolb private void layoutLabel(int level) { 3820f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb int x = mPieCenterX - (int) (FloatMath.sin(mCenterAngle - CENTER) 3830f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb * (mArcRadius + (level + 2) * mRadiusInc)); 38410f4ba0198904a3d7679771ce845c847d940226fMichael Kolb int y = mArcCenterY - mArcRadius - (level + 2) * mRadiusInc; 38510f4ba0198904a3d7679771ce845c847d940226fMichael Kolb int w = mLabel.getIntrinsicWidth(); 38610f4ba0198904a3d7679771ce845c847d940226fMichael Kolb int h = mLabel.getIntrinsicHeight(); 38710f4ba0198904a3d7679771ce845c847d940226fMichael Kolb mLabel.setBounds(x - w/2, y - h/2, x + w/2, y + h/2); 3883daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb } 3893daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb 3903daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb private void layoutItems(int level, List<PieItem> items) { 3913daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb int extend = 1; 3923daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb Path path = makeSlice(getDegrees(0) + extend, getDegrees(SWEEP_ARC) - extend, 3933daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb mArcRadius, mArcRadius + mRadiusInc + mRadiusInc / 4, 3943daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb mPieCenterX, mArcCenterY - level * mRadiusInc); 395b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb final int count = items.size(); 396b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb int pos = 0; 3978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb for (PieItem item : items) { 3988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // shared between items 3998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb item.setPath(path); 400b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb float angle = getArcCenter(item, pos, count); 4018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb int w = item.getIntrinsicWidth(); 4028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb int h = item.getIntrinsicHeight(); 4038872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // move views to outer border 4043daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb int r = mArcRadius + mRadiusInc * 2 / 3; 4058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb int x = (int) (r * Math.cos(angle)); 4063daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb int y = mArcCenterY - (level * mRadiusInc) - (int) (r * Math.sin(angle)) - h / 2; 4073daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb x = mPieCenterX + x - w / 2; 4088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb item.setBounds(x, y, x + w, y + h); 4093daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb item.setLevel(level); 4108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (item.hasItems()) { 4113daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb layoutItems(level + 1, item.getItems()); 4128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 413b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb pos++; 4148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 4158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 4168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 4173daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb private Path makeSlice(float start, float end, int inner, int outer, int cx, int cy) { 4188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb RectF bb = 4193daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb new RectF(cx - outer, cy - outer, cx + outer, 4203daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb cy + outer); 4218872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb RectF bbi = 4223daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb new RectF(cx - inner, cy - inner, cx + inner, 4233daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb cy + inner); 4248872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb Path path = new Path(); 4258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb path.arcTo(bb, start, end - start, true); 4268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb path.arcTo(bbi, end, start - end); 4278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb path.close(); 4288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return path; 4298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 4308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 431b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb private float getArcCenter(PieItem item, int pos, int count) { 432b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb return getCenter(pos, count, SWEEP_ARC); 4333daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb } 4343daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb 435b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb private float getSliceCenter(PieItem item, int pos, int count) { 4360f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb float center = (getCenterAngle() - CENTER) * 0.5f + CENTER; 437b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb return center + (count - 1) * SWEEP_SLICE / 2f 438b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb - pos * SWEEP_SLICE; 4393daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb } 4403daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb 4413daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb private float getCenter(int pos, int count, float sweep) { 4420f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb return mCenterAngle + (count - 1) * sweep / 2f - pos * sweep; 4430f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb } 4440f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb 4450f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb private float getCenterAngle() { 4460f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb float center = CENTER; 4470f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb if (mPieCenterX < mDeadZone + mAngleZone) { 448f465110e4b8ed787589e052e5ac746c588c5ac8fMichael Kolb center = CENTER - (mAngleZone - mPieCenterX + mDeadZone) * RAD24 4490f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb / (float) mAngleZone; 4500f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb } else if (mPieCenterX > getWidth() - mDeadZone - mAngleZone) { 451f465110e4b8ed787589e052e5ac746c588c5ac8fMichael Kolb center = CENTER + (mPieCenterX - (getWidth() - mDeadZone - mAngleZone)) * RAD24 4520f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb / (float) mAngleZone; 4530f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb } 4540f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb return center; 4553daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb } 4563daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb 4578872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb /** 4588872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * converts a 4598872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * @param angle from 0..PI to Android degrees (clockwise starting at 3 o'clock) 4608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * @return skia angle 4618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */ 4628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private float getDegrees(double angle) { 4638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return (float) (360 - 180 * angle / Math.PI); 4648872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 4658872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 466ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb private void startFadeOut(final PieItem item) { 467ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb if (mFadeIn != null) { 468ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb mFadeIn.cancel(); 469ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } 470ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb if (mXFade != null) { 471ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb mXFade.cancel(); 4728872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 4731b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mFadeOut = new ValueAnimator(); 4741b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mFadeOut.setFloatValues(1f, 0f); 475ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb mFadeOut.setDuration(PIE_FADE_OUT_DURATION); 4761b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mFadeOut.addListener(new AnimatorListener() { 477ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb @Override 4781b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationStart(Animator animator) { 479ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } 480ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb 481ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb @Override 4821b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationEnd(Animator animator) { 483ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb item.performClick(); 484ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb mFadeOut = null; 485ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb deselect(); 486ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb show(false); 487ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb mOverlay.setAlpha(1); 488ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } 489ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb 490ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb @Override 4911b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationRepeat(Animator animator) { 4921b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu } 4931b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu 4941b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu @Override 4951b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationCancel(Animator animator) { 496ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } 4971b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu 498ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb }); 4991b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mFadeOut.start(); 5008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 5018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 5023bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb // root does not count 5033bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private boolean hasOpenItem() { 5043bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb return mOpen.size() > 1; 5053bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 5063bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 5073bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb // pop an item of the open item stack 5083bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private PieItem closeOpenItem() { 5093bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb PieItem item = getOpenItem(); 5103bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mOpen.remove(mOpen.size() -1); 5113bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb return item; 5123bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 5133bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 5143bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private PieItem getOpenItem() { 5153bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb return mOpen.get(mOpen.size() - 1); 5163bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 5173bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 5183bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb // return the children either the root or parent of the current open item 5193bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private PieItem getParent() { 5203bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb return mOpen.get(Math.max(0, mOpen.size() - 2)); 5213bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 5223bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 5233bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private int getLevel() { 5243bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb return mOpen.size() - 1; 5253bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 5263bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 5278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 5288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void onDraw(Canvas canvas) { 529e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling mProgressRenderer.onDraw(canvas, mFocusX, mFocusY); 530e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling 5318872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb float alpha = 1; 5328872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mXFade != null) { 5331b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu alpha = (Float) mXFade.getAnimatedValue(); 5348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else if (mFadeIn != null) { 5351b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu alpha = (Float) mFadeIn.getAnimatedValue(); 536ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } else if (mFadeOut != null) { 5371b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu alpha = (Float) mFadeOut.getAnimatedValue(); 5388872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 5398872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb int state = canvas.save(); 5408872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mFadeIn != null) { 5418872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb float sf = 0.9f + alpha * 0.1f; 5423bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb canvas.scale(sf, sf, mPieCenterX, mPieCenterY); 5433bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 5443bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (mState != STATE_PIE) { 5453bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb drawFocus(canvas); 5468872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 5478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mState == STATE_FINISHING) { 5488872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.restoreToCount(state); 5498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return; 5508872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 5519e012f853e3eb5c9d36c84351961f588eef4788fMichael Kolb if (mState != STATE_PIE) return; 5523bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (!hasOpenItem() || (mXFade != null)) { 5538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // draw base menu 5543daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb drawArc(canvas, getLevel(), getParent()); 555b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb List<PieItem> items = getParent().getItems(); 556b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb final int count = items.size(); 557b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb int pos = 0; 5583bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb for (PieItem item : getParent().getItems()) { 559b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb drawItem(Math.max(0, mOpen.size() - 2), pos, count, canvas, item, alpha); 560b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb pos++; 5618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 56210f4ba0198904a3d7679771ce845c847d940226fMichael Kolb mLabel.draw(canvas); 5638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 5643bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (hasOpenItem()) { 5653bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb int level = getLevel(); 5663daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb drawArc(canvas, level, getOpenItem()); 567b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb List<PieItem> items = getOpenItem().getItems(); 568b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb final int count = items.size(); 569b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb int pos = 0; 570b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb for (PieItem inner : items) { 571ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb if (mFadeOut != null) { 572b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb drawItem(level, pos, count, canvas, inner, alpha); 573ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } else { 574b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb drawItem(level, pos, count, canvas, inner, (mXFade != null) ? (1 - 0.5f * alpha) : 1); 575ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } 576b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb pos++; 5778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 57810f4ba0198904a3d7679771ce845c847d940226fMichael Kolb mLabel.draw(canvas); 5798872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 5808872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.restoreToCount(state); 5818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 5828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 5833daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb private void drawArc(Canvas canvas, int level, PieItem item) { 5843bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb // arc 5853bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (mState == STATE_PIE) { 586b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb final int count = item.getItems().size(); 587b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb float start = mCenterAngle + (count * SWEEP_ARC / 2f); 588b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb float end = mCenterAngle - (count * SWEEP_ARC / 2f); 5893daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb int cy = mArcCenterY - level * mRadiusInc; 5903daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb canvas.drawArc(new RectF(mPieCenterX - mArcRadius, cy - mArcRadius, 5913daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb mPieCenterX + mArcRadius, cy + mArcRadius), 5923daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb getDegrees(end), getDegrees(start) - getDegrees(end), false, mMenuArcPaint); 5933bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 5943bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 5953daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb 596b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb private void drawItem(int level, int pos, int count, Canvas canvas, PieItem item, float alpha) { 5978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mState == STATE_PIE) { 5988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (item.getPath() != null) { 5993daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb int y = mArcCenterY - level * mRadiusInc; 6008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (item.isSelected()) { 6018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb Paint p = mSelectedPaint; 6028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb int state = canvas.save(); 603ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb float angle = 0; 604ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb if (mSlice != null) { 6051b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu angle = (Float) mSlice.getAnimatedValue(); 606ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb } else { 607ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb angle = getArcCenter(item, pos, count) - SWEEP_ARC / 2f; 608ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb } 6093daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb angle = getDegrees(angle); 6103daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb canvas.rotate(angle, mPieCenterX, y); 611ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb if (mFadeOut != null) { 612ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb p.setAlpha((int)(255 * alpha)); 613ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } 6148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.drawPath(item.getPath(), p); 615ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb if (mFadeOut != null) { 616ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb p.setAlpha(255); 617ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } 6188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.restoreToCount(state); 6198872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 620ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb if (mFadeOut == null) { 621ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb alpha = alpha * (item.isEnabled() ? 1 : 0.3f); 622ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb // draw the item view 623ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb item.setAlpha(alpha); 624ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } 6258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb item.draw(canvas); 6268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 6308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 6318872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public boolean onTouchEvent(MotionEvent evt) { 6328872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb float x = evt.getX(); 6338872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb float y = evt.getY(); 6348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb int action = evt.getActionMasked(); 6353daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb getPolar(x, y, !mTapMode, mPolar); 6368872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (MotionEvent.ACTION_DOWN == action) { 6370f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb if ((x < mDeadZone) || (x > getWidth() - mDeadZone)) { 6380f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb return false; 6390f4a5ae4fae89cc7cde711f6aad8d7f571132ca9Michael Kolb } 6408872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mDown.x = (int) evt.getX(); 6418872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mDown.y = (int) evt.getY(); 6428872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mOpening = false; 6438872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mTapMode) { 6443daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb PieItem item = findItem(mPolar); 6458872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if ((item != null) && (mCurrentItem != item)) { 6468872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mState = STATE_PIE; 6478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb onEnter(item); 6488872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else { 6508872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb setCenter((int) x, (int) y); 6518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb show(true); 6528872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return true; 6548872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else if (MotionEvent.ACTION_UP == action) { 6558872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (isVisible()) { 6568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb PieItem item = mCurrentItem; 6578872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mTapMode) { 6583daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb item = findItem(mPolar); 6593bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (mOpening) { 6608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mOpening = false; 6618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return true; 6628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6648872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (item == null) { 6658872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mTapMode = false; 6668872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb show(false); 6673bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } else if (!mOpening && !item.hasItems()) { 6683bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb startFadeOut(item); 6693bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mTapMode = false; 6703bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } else { 6713bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mTapMode = true; 6728872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return true; 6748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else if (MotionEvent.ACTION_CANCEL == action) { 6768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (isVisible() || mTapMode) { 6778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb show(false); 6788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6798872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb deselect(); 6803bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mHandler.removeMessages(MSG_OPENSUBMENU); 6818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return false; 6828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else if (MotionEvent.ACTION_MOVE == action) { 6833daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb if (pulledToCenter(mPolar)) { 6843bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mHandler.removeMessages(MSG_OPENSUBMENU); 6853bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (hasOpenItem()) { 6863bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (mCurrentItem != null) { 6873bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mCurrentItem.setSelected(false); 6883bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 6893bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb closeOpenItem(); 6903bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mCurrentItem = null; 6918872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else { 6928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb deselect(); 6938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 69410f4ba0198904a3d7679771ce845c847d940226fMichael Kolb mLabel.setText(""); 6958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return false; 6968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 6973daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb PieItem item = findItem(mPolar); 6988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb boolean moved = hasMoved(evt); 6998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if ((item != null) && (mCurrentItem != item) && (!mOpening || moved)) { 7003bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mHandler.removeMessages(MSG_OPENSUBMENU); 7018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // only select if we didn't just open or have moved past slop 7028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (moved) { 7038872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // switch back to swipe mode 7048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mTapMode = false; 7058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 7063bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb onEnterSelect(item); 7073bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mHandler.sendEmptyMessageDelayed(MSG_OPENSUBMENU, PIE_OPEN_SUB_DELAY); 7088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 7098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 7108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return false; 7118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 7128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 71354d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling @Override 71454d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling public boolean isVisible() { 71554d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling return super.isVisible() || mProgressRenderer.isVisible(); 71654d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling } 71754d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling 7183bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private boolean pulledToCenter(PointF polarCoords) { 7193daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb return polarCoords.y < mArcRadius - mRadiusInc; 7203bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 7213bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 722b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb private boolean inside(PointF polar, PieItem item, int pos, int count) { 723b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb float start = getSliceCenter(item, pos, count) - SWEEP_SLICE / 2f; 7243daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb boolean res = (mArcRadius < polar.y) 7253daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb && (start < polar.x) 7263daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb && (start + SWEEP_SLICE > polar.x) 7273daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb && (!mTapMode || (mArcRadius + mRadiusInc > polar.y)); 7283daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb return res; 7293daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb } 7303daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb 7313daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb private void getPolar(float x, float y, boolean useOffset, PointF res) { 7323bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb // get angle and radius from x/y 7333bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb res.x = (float) Math.PI / 2; 7343daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb x = x - mPieCenterX; 7353daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb float y1 = mSliceCenterY - getLevel() * mRadiusInc - y; 7363daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb float y2 = mArcCenterY - getLevel() * mRadiusInc - y; 7373daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb res.y = (float) Math.sqrt(x * x + y2 * y2); 7383bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (x != 0) { 7393daa3518c3bfa1a2c1da37c56e1a34e9a0cac259Michael Kolb res.x = (float) Math.atan2(y1, x); 7403bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (res.x < 0) { 7413bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb res.x = (float) (2 * Math.PI + res.x); 7423bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 7433bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 7443bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb res.y = res.y + (useOffset ? mTouchOffset : 0); 7453bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 7463bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 7478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private boolean hasMoved(MotionEvent e) { 7488872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return mTouchSlopSquared < (e.getX() - mDown.x) * (e.getX() - mDown.x) 7498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb + (e.getY() - mDown.y) * (e.getY() - mDown.y); 7508872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 7518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 7523bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private void onEnterSelect(PieItem item) { 7533bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (mCurrentItem != null) { 7543bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mCurrentItem.setSelected(false); 7553bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 7563bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (item != null && item.isEnabled()) { 757ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb moveSelection(mCurrentItem, item); 7583bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb item.setSelected(true); 7593bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mCurrentItem = item; 76010f4ba0198904a3d7679771ce845c847d940226fMichael Kolb mLabel.setText(mCurrentItem.getLabel()); 76110f4ba0198904a3d7679771ce845c847d940226fMichael Kolb layoutLabel(getLevel()); 7623bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } else { 7633bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mCurrentItem = null; 7643bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 7653bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 7663bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 7673bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb private void onEnterOpen() { 768dc7d1ac9c9fd4ba9f4c689e17a4a248a27463fbeMichael Kolb if ((mCurrentItem != null) && (mCurrentItem != getOpenItem()) && mCurrentItem.hasItems()) { 7693bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb openCurrentItem(); 7703bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 7713bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } 7723bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb 7738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb /** 7748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * enter a slice for a view 7758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * updates model only 7768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * @param item 7778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */ 7788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void onEnter(PieItem item) { 7798872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mCurrentItem != null) { 7808872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mCurrentItem.setSelected(false); 7818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 7828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (item != null && item.isEnabled()) { 7838872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb item.setSelected(true); 7848872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mCurrentItem = item; 785712cc2f5add2fb78fbb723ecbca5f576a91fb54fMichael Kolb mLabel.setText(mCurrentItem.getLabel()); 7863bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if ((mCurrentItem != getOpenItem()) && mCurrentItem.hasItems()) { 7878872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb openCurrentItem(); 78810f4ba0198904a3d7679771ce845c847d940226fMichael Kolb layoutLabel(getLevel()); 7898872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 7908872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } else { 7918872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mCurrentItem = null; 7928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 7938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 7948872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 7958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void deselect() { 7968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mCurrentItem != null) { 7978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mCurrentItem.setSelected(false); 7988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 7993bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb if (hasOpenItem()) { 8003bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb PieItem item = closeOpenItem(); 8013bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb onEnter(item); 8023bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb } else { 8033bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mCurrentItem = null; 8048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 8058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 8068872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 807ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb private int getItemPos(PieItem target) { 808ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb List<PieItem> items = getOpenItem().getItems(); 809ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb return items.indexOf(target); 810ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb } 811ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb 812ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb private int getCurrentCount() { 813ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb return getOpenItem().getItems().size(); 814ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb } 815ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb 816ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb private void moveSelection(PieItem from, PieItem to) { 817ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb final int count = getCurrentCount(); 818ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb final int fromPos = getItemPos(from); 819ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb final int toPos = getItemPos(to); 820ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb if (fromPos != -1 && toPos != -1) { 821ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb float startAngle = getArcCenter(from, getItemPos(from), count) 822ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb - SWEEP_ARC / 2f; 823ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb float endAngle = getArcCenter(to, getItemPos(to), count) 824ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb - SWEEP_ARC / 2f; 8251b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mSlice = new ValueAnimator(); 8261b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mSlice.setFloatValues(startAngle, endAngle); 8271b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu // linear interpolater 8281b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mSlice.setInterpolator(null); 829ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb mSlice.setDuration(PIE_SLICE_DURATION); 8301b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mSlice.addListener(new AnimatorListener() { 831ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb @Override 8321b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationEnd(Animator arg0) { 833ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb mSlice = null; 834ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb } 835ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb 836ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb @Override 8371b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationRepeat(Animator arg0) { 8381b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu } 8391b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu 8401b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu @Override 8411b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationStart(Animator arg0) { 842ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb } 843ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb 844ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb @Override 8451b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationCancel(Animator arg0) { 846ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb } 847ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb }); 8481b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mSlice.start(); 849ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb } 850ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb } 851ad2a745d44fdf5acdd98d3bd8212ca51f45c29e7Michael Kolb 8528872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void openCurrentItem() { 8538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if ((mCurrentItem != null) && mCurrentItem.hasItems()) { 8543bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mOpen.add(mCurrentItem); 855f465110e4b8ed787589e052e5ac746c588c5ac8fMichael Kolb layoutLabel(getLevel()); 8568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mOpening = true; 857ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb if (mFadeIn != null) { 858ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb mFadeIn.cancel(); 859ebcf6fed531d00cfb6900a1fb5d83c60aa7f9693Michael Kolb } 8601b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mXFade = new ValueAnimator(); 8611b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mXFade.setFloatValues(1f, 0f); 8628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mXFade.setDuration(PIE_XFADE_DURATION); 8631b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu // Linear interpolation 8641b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mXFade.setInterpolator(null); 8653bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb final PieItem ci = mCurrentItem; 8661b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mXFade.addListener(new AnimatorListener() { 8678872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 8681b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationStart(Animator animation) { 8698872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 8708872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 8718872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 8721b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationEnd(Animator animation) { 8738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mXFade = null; 8743bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb ci.setSelected(false); 8753bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb mOpening = false; 8768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 8778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 8788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 8791b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationRepeat(Animator animation) { 8801b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu } 8811b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu 8821b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu @Override 8831b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu public void onAnimationCancel(Animator arg0) { 8848872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 8858872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb }); 8861b9362e03c56e98a27879a15b9d133f1e50fc4d4Doris Liu mXFade.start(); 8878872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 8888872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 8898872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 8908872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb /** 8918872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * @param polar x: angle, y: dist 8928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb * @return the item at angle/dist or null 8938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb */ 8948872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private PieItem findItem(PointF polar) { 8958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // find the matching item: 8963bc96b2d1106fc5ebec6fda6aad3bca4d62e81c0Michael Kolb List<PieItem> items = getOpenItem().getItems(); 897b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb final int count = items.size(); 898b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb int pos = 0; 8998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb for (PieItem item : items) { 900b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb if (inside(polar, item, pos, count)) { 9018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return item; 9028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 903b7c49994231f31f5cf4de4a66eec7a85a3bd9551Michael Kolb pos++; 9048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return null; 9068872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9078872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 9108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public boolean handlesTouch() { 9118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return true; 9128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // focus specific code 9158872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void setBlockFocus(boolean blocked) { 9178872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mBlockFocus = blocked; 9188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (blocked) { 9198872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb clear(); 9208872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9218872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9228872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9238872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void setFocus(int x, int y) { 924d9b229be6fa942920317fc5e031e803e408adc1dIgor Murashkin mOverlay.removeCallbacks(mDisappear); 9258872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusX = x; 9268872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusY = y; 9278872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb setCircle(mFocusX, mFocusY); 9288872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9298872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9308872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public int getSize() { 9318872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return 2 * mCircleSize; 9328872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9338872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9348872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private int getRandomRange() { 9358872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb return (int)(-60 + 120 * Math.random()); 9368872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9378872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9388872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void setCircle(int cx, int cy) { 9398872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mCircle.set(cx - mCircleSize, cy - mCircleSize, 9408872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb cx + mCircleSize, cy + mCircleSize); 9418872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mDial.set(cx - mCircleSize + mInnerOffset, cy - mCircleSize + mInnerOffset, 9428872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb cx + mCircleSize - mInnerOffset, cy + mCircleSize - mInnerOffset); 9438872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9448872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9458872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void drawFocus(Canvas canvas) { 9468872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mBlockFocus) return; 9478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusPaint.setStrokeWidth(mOuterStroke); 9488872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.drawCircle((float) mFocusX, (float) mFocusY, (float) mCircleSize, mFocusPaint); 9498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mState == STATE_PIE) return; 9508872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb int color = mFocusPaint.getColor(); 9518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mState == STATE_FINISHING) { 9528872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusPaint.setColor(mFocused ? mSuccessColor : mFailColor); 9538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9548872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusPaint.setStrokeWidth(mInnerStroke); 9558872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb drawLine(canvas, mDialAngle, mFocusPaint); 9568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb drawLine(canvas, mDialAngle + 45, mFocusPaint); 9578872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb drawLine(canvas, mDialAngle + 180, mFocusPaint); 9588872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb drawLine(canvas, mDialAngle + 225, mFocusPaint); 9598872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.save(); 9608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // rotate the arc instead of its offset to better use framework's shape caching 9618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.rotate(mDialAngle, mFocusX, mFocusY); 9628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.drawArc(mDial, 0, 45, false, mFocusPaint); 9638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.drawArc(mDial, 180, 45, false, mFocusPaint); 9648872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.restore(); 9658872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusPaint.setColor(color); 9668872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9678872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9688872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void drawLine(Canvas canvas, int angle, Paint p) { 9698872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb convertCart(angle, mCircleSize - mInnerOffset, mPoint1); 9708872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb convertCart(angle, mCircleSize - mInnerOffset + mInnerOffset / 3, mPoint2); 9718872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb canvas.drawLine(mPoint1.x + mFocusX, mPoint1.y + mFocusY, 9728872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mPoint2.x + mFocusX, mPoint2.y + mFocusY, p); 9738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private static void convertCart(int angle, int radius, Point out) { 9768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb double a = 2 * Math.PI * (angle % 360) / 360; 9778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb out.x = (int) (radius * Math.cos(a) + 0.5); 9788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb out.y = (int) (radius * Math.sin(a) + 0.5); 9798872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9808872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 9828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void showStart() { 9838872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mState == STATE_PIE) return; 9848872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb cancelFocus(); 9858872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mStartAnimationAngle = 67; 9868872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb int range = getRandomRange(); 9878872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb startAnimation(SCALING_UP_TIME, 9888872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb false, mStartAnimationAngle, mStartAnimationAngle + range); 9898872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mState = STATE_FOCUSING; 9908872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 9918872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 9928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 9938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void showSuccess(boolean timeout) { 9948872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mState == STATE_FOCUSING) { 9958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb startAnimation(SCALING_DOWN_TIME, 9968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb timeout, mStartAnimationAngle); 9978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mState = STATE_FINISHING; 9988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocused = true; 9998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 10028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 10038872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void showFail(boolean timeout) { 10048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mState == STATE_FOCUSING) { 10058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb startAnimation(SCALING_DOWN_TIME, 10068872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb timeout, mStartAnimationAngle); 10078872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mState = STATE_FINISHING; 10088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocused = false; 10098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 10128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void cancelFocus() { 10138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusCancelled = true; 10148872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mOverlay.removeCallbacks(mDisappear); 1015e3de7223ee3fe56e097d68f50c5a59ae61370d65Michael Kolb if (mAnimation != null && !mAnimation.hasEnded()) { 10168872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mAnimation.cancel(); 10178872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10188872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusCancelled = false; 10198872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocused = false; 10208872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mState = STATE_IDLE; 10218872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10228872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 102354d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling public void clear(boolean waitUntilProgressIsHidden) { 102454d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling if (mState == STATE_PIE) 102554d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling return; 102654d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling cancelFocus(); 102754d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling 102854d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling if (waitUntilProgressIsHidden) { 102954d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling mProgressRenderer.setVisibilityListener(new VisibilityListener() { 103054d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling @Override 103154d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling public void onHidden() { 103254d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling mOverlay.post(mDisappear); 103354d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling } 103454d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling }); 1035b7dcf9f20708376dfd14f9db6b41addc2f92e5c6Sascha Haeberling } else { 1036b7dcf9f20708376dfd14f9db6b41addc2f92e5c6Sascha Haeberling mOverlay.post(mDisappear); 1037b7dcf9f20708376dfd14f9db6b41addc2f92e5c6Sascha Haeberling mProgressRenderer.setVisibilityListener(null); 103854d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling } 103954d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling } 104054d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling 10418872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 10428872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void clear() { 104354d24c3f82e979b7851e2c0f8b2a4dc69122a7c3Sascha Haeberling clear(false); 10448872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10458872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 10468872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void startAnimation(long duration, boolean timeout, 10478872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb float toScale) { 10488872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb startAnimation(duration, timeout, mDialAngle, 10498872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb toScale); 10508872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10518872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 10528872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private void startAnimation(long duration, boolean timeout, 10538872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb float fromScale, float toScale) { 10548872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb setVisible(true); 10558872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mAnimation.reset(); 10568872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mAnimation.setDuration(duration); 10578872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mAnimation.setScale(fromScale, toScale); 10588872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mAnimation.setAnimationListener(timeout ? mEndAction : null); 10598872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mOverlay.startAnimation(mAnimation); 10608872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb update(); 10618872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10628872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 10638872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private class EndAction implements Animation.AnimationListener { 10648872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 10658872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void onAnimationEnd(Animation animation) { 10668872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb // Keep the focus indicator for some time. 10678872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (!mFocusCancelled) { 10688872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mOverlay.postDelayed(mDisappear, DISAPPEAR_TIMEOUT); 10698872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10708872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10718872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 10728872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 10738872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void onAnimationRepeat(Animation animation) { 10748872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10758872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 10768872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 10778872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void onAnimationStart(Animation animation) { 10788872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10798872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10808872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 10818872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private class Disappear implements Runnable { 10828872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 10838872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void run() { 10848872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb if (mState == STATE_PIE) return; 10858872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb setVisible(false); 10868872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusX = mCenterX; 10878872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocusY = mCenterY; 10888872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mState = STATE_IDLE; 10898872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb setCircle(mFocusX, mFocusY); 10908872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFocused = false; 10918872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10928872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 10938872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 10948872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private class ScaleAnimation extends Animation { 10958872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private float mFrom = 1f; 10968872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb private float mTo = 1f; 10978872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 10988872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public ScaleAnimation() { 10998872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb setFillAfter(true); 11008872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 11018872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 11028872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb public void setScale(float from, float to) { 11038872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mFrom = from; 11048872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mTo = to; 11058872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 11068872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 11078872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb @Override 11088872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb protected void applyTransformation(float interpolatedTime, Transformation t) { 11098872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb mDialAngle = (int)(mFrom + (mTo - mFrom) * interpolatedTime); 11108872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 11118872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb } 11128872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb 11138872c23e739de38d74f04a8c852ebb5199c905f6Michael Kolb} 1114