diff options
author | John Spurlock <jspurlock@google.com> | 2014-03-28 13:13:50 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-03-28 13:13:50 +0000 |
commit | ca4761661a41fc0750a2bc5e7c90481216e626c3 (patch) | |
tree | c0f343ab85cdcd6d79909816039c8af27bdc5c8d | |
parent | 1c9c97c5ef8adfd171ab632bf560332738ce90e2 (diff) | |
parent | 0e14f2d45557527242f27ce7de9027e6ccaa45d6 (diff) | |
download | frameworks_base-ca4761661a41fc0750a2bc5e7c90481216e626c3.zip frameworks_base-ca4761661a41fc0750a2bc5e7c90481216e626c3.tar.gz frameworks_base-ca4761661a41fc0750a2bc5e7c90481216e626c3.tar.bz2 |
am 0e14f2d4: Merge "Remove obsolete MultiWaveView"
* commit '0e14f2d45557527242f27ce7de9027e6ccaa45d6':
Remove obsolete MultiWaveView
-rw-r--r-- | core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java | 1270 | ||||
-rw-r--r-- | core/res/res/values/attrs.xml | 57 | ||||
-rw-r--r-- | packages/SystemUI/res/values/config.xml | 4 |
3 files changed, 11 insertions, 1320 deletions
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java deleted file mode 100644 index 4648f39..0000000 --- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java +++ /dev/null @@ -1,1270 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.widget.multiwaveview; - -import android.animation.Animator; -import android.animation.Animator.AnimatorListener; -import android.animation.AnimatorListenerAdapter; -import android.animation.TimeInterpolator; -import android.animation.ValueAnimator; -import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; -import android.media.AudioManager; -import android.os.Bundle; -import android.os.UserHandle; -import android.os.Vibrator; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; - -import com.android.internal.R; - -import java.util.ArrayList; - -/** - * A special widget containing a center and outer ring. Moving the center ring to the outer ring - * causes an event that can be caught by implementing OnTriggerListener. - */ -public class MultiWaveView extends View { - private static final String TAG = "MultiWaveView"; - private static final boolean DEBUG = false; - - // Wave state machine - private static final int STATE_IDLE = 0; - private static final int STATE_START = 1; - private static final int STATE_FIRST_TOUCH = 2; - private static final int STATE_TRACKING = 3; - private static final int STATE_SNAP = 4; - private static final int STATE_FINISH = 5; - - // Animation properties. - private static final float SNAP_MARGIN_DEFAULT = 20.0f; // distance to ring before we snap to it - - public interface OnTriggerListener { - int NO_HANDLE = 0; - int CENTER_HANDLE = 1; - public void onGrabbed(View v, int handle); - public void onReleased(View v, int handle); - public void onTrigger(View v, int target); - public void onGrabbedStateChange(View v, int handle); - public void onFinishFinalAnimation(); - } - - // Tuneable parameters for animation - private static final int CHEVRON_INCREMENTAL_DELAY = 160; - private static final int CHEVRON_ANIMATION_DURATION = 850; - private static final int RETURN_TO_HOME_DELAY = 1200; - private static final int RETURN_TO_HOME_DURATION = 200; - private static final int HIDE_ANIMATION_DELAY = 200; - private static final int HIDE_ANIMATION_DURATION = 200; - private static final int SHOW_ANIMATION_DURATION = 200; - private static final int SHOW_ANIMATION_DELAY = 50; - private static final int INITIAL_SHOW_HANDLE_DURATION = 200; - - private static final float TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.3f; - private static final float TARGET_SCALE_EXPANDED = 1.0f; - private static final float TARGET_SCALE_COLLAPSED = 0.8f; - private static final float RING_SCALE_EXPANDED = 1.0f; - private static final float RING_SCALE_COLLAPSED = 0.5f; - - private TimeInterpolator mChevronAnimationInterpolator = Ease.Quad.easeOut; - - private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>(); - private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>(); - private AnimationBundle mChevronAnimations = new AnimationBundle(); - private AnimationBundle mTargetAnimations = new AnimationBundle(); - private AnimationBundle mHandleAnimations = new AnimationBundle(); - private ArrayList<String> mTargetDescriptions; - private ArrayList<String> mDirectionDescriptions; - private OnTriggerListener mOnTriggerListener; - private TargetDrawable mHandleDrawable; - private TargetDrawable mOuterRing; - private Vibrator mVibrator; - - private int mFeedbackCount = 3; - private int mVibrationDuration = 0; - private int mGrabbedState; - private int mActiveTarget = -1; - private float mTapRadius; - private float mWaveCenterX; - private float mWaveCenterY; - private int mMaxTargetHeight; - private int mMaxTargetWidth; - - private float mOuterRadius = 0.0f; - private float mSnapMargin = 0.0f; - private boolean mDragging; - private int mNewTargetResources; - - private class AnimationBundle extends ArrayList<Tweener> { - private static final long serialVersionUID = 0xA84D78726F127468L; - private boolean mSuspended; - - public void start() { - if (mSuspended) return; // ignore attempts to start animations - final int count = size(); - for (int i = 0; i < count; i++) { - Tweener anim = get(i); - anim.animator.start(); - } - } - - public void cancel() { - final int count = size(); - for (int i = 0; i < count; i++) { - Tweener anim = get(i); - anim.animator.cancel(); - } - clear(); - } - - public void stop() { - final int count = size(); - for (int i = 0; i < count; i++) { - Tweener anim = get(i); - anim.animator.end(); - } - clear(); - } - - public void setSuspended(boolean suspend) { - mSuspended = suspend; - } - }; - - private AnimatorListener mResetListener = new AnimatorListenerAdapter() { - public void onAnimationEnd(Animator animator) { - switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY); - dispatchOnFinishFinalAnimation(); - } - }; - - private AnimatorListener mResetListenerWithPing = new AnimatorListenerAdapter() { - public void onAnimationEnd(Animator animator) { - ping(); - switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY); - dispatchOnFinishFinalAnimation(); - } - }; - - private AnimatorUpdateListener mUpdateListener = new AnimatorUpdateListener() { - public void onAnimationUpdate(ValueAnimator animation) { - invalidateGlobalRegion(mHandleDrawable); - invalidate(); - } - }; - - private boolean mAnimatingTargets; - private AnimatorListener mTargetUpdateListener = new AnimatorListenerAdapter() { - public void onAnimationEnd(Animator animator) { - if (mNewTargetResources != 0) { - internalSetTargetResources(mNewTargetResources); - mNewTargetResources = 0; - hideTargets(false, false); - } - mAnimatingTargets = false; - } - }; - private int mTargetResourceId; - private int mTargetDescriptionsResourceId; - private int mDirectionDescriptionsResourceId; - private boolean mAlwaysTrackFinger; - private int mHorizontalInset; - private int mVerticalInset; - private int mGravity = Gravity.TOP; - private boolean mInitialLayout = true; - private Tweener mBackgroundAnimator; - - public MultiWaveView(Context context) { - this(context, null); - } - - public MultiWaveView(Context context, AttributeSet attrs) { - super(context, attrs); - Resources res = context.getResources(); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiWaveView); - mOuterRadius = a.getDimension(R.styleable.MultiWaveView_outerRadius, mOuterRadius); - mSnapMargin = a.getDimension(R.styleable.MultiWaveView_snapMargin, mSnapMargin); - mVibrationDuration = a.getInt(R.styleable.MultiWaveView_vibrationDuration, - mVibrationDuration); - mFeedbackCount = a.getInt(R.styleable.MultiWaveView_feedbackCount, - mFeedbackCount); - mHandleDrawable = new TargetDrawable(res, - a.peekValue(R.styleable.MultiWaveView_handleDrawable).resourceId); - mTapRadius = mHandleDrawable.getWidth()/2; - mOuterRing = new TargetDrawable(res, - a.peekValue(R.styleable.MultiWaveView_waveDrawable).resourceId); - mAlwaysTrackFinger = a.getBoolean(R.styleable.MultiWaveView_alwaysTrackFinger, false); - - // Read array of chevron drawables - TypedValue outValue = new TypedValue(); - if (a.getValue(R.styleable.MultiWaveView_chevronDrawables, outValue)) { - ArrayList<TargetDrawable> chevrons = loadDrawableArray(outValue.resourceId); - for (int i = 0; i < chevrons.size(); i++) { - final TargetDrawable chevron = chevrons.get(i); - for (int k = 0; k < mFeedbackCount; k++) { - mChevronDrawables.add(chevron == null ? null : new TargetDrawable(chevron)); - } - } - } - - // Read array of target drawables - if (a.getValue(R.styleable.MultiWaveView_targetDrawables, outValue)) { - internalSetTargetResources(outValue.resourceId); - } - if (mTargetDrawables == null || mTargetDrawables.size() == 0) { - throw new IllegalStateException("Must specify at least one target drawable"); - } - - // Read array of target descriptions - if (a.getValue(R.styleable.MultiWaveView_targetDescriptions, outValue)) { - final int resourceId = outValue.resourceId; - if (resourceId == 0) { - throw new IllegalStateException("Must specify target descriptions"); - } - setTargetDescriptionsResourceId(resourceId); - } - - // Read array of direction descriptions - if (a.getValue(R.styleable.MultiWaveView_directionDescriptions, outValue)) { - final int resourceId = outValue.resourceId; - if (resourceId == 0) { - throw new IllegalStateException("Must specify direction descriptions"); - } - setDirectionDescriptionsResourceId(resourceId); - } - - a.recycle(); - - // Use gravity attribute from LinearLayout - a = context.obtainStyledAttributes(attrs, android.R.styleable.LinearLayout); - mGravity = a.getInt(android.R.styleable.LinearLayout_gravity, Gravity.TOP); - a.recycle(); - - setVibrateEnabled(mVibrationDuration > 0); - assignDefaultsIfNeeded(); - } - - private void dump() { - Log.v(TAG, "Outer Radius = " + mOuterRadius); - Log.v(TAG, "SnapMargin = " + mSnapMargin); - Log.v(TAG, "FeedbackCount = " + mFeedbackCount); - Log.v(TAG, "VibrationDuration = " + mVibrationDuration); - Log.v(TAG, "TapRadius = " + mTapRadius); - Log.v(TAG, "WaveCenterX = " + mWaveCenterX); - Log.v(TAG, "WaveCenterY = " + mWaveCenterY); - } - - public void suspendAnimations() { - mChevronAnimations.setSuspended(true); - mTargetAnimations.setSuspended(true); - mHandleAnimations.setSuspended(true); - } - - public void resumeAnimations() { - mChevronAnimations.setSuspended(false); - mTargetAnimations.setSuspended(false); - mHandleAnimations.setSuspended(false); - mChevronAnimations.start(); - mTargetAnimations.start(); - mHandleAnimations.start(); - } - - @Override - protected int getSuggestedMinimumWidth() { - // View should be large enough to contain the background + handle and - // target drawable on either edge. - return (int) (Math.max(mOuterRing.getWidth(), 2 * mOuterRadius) + mMaxTargetWidth); - } - - @Override - protected int getSuggestedMinimumHeight() { - // View should be large enough to contain the unlock ring + target and - // target drawable on either edge - return (int) (Math.max(mOuterRing.getHeight(), 2 * mOuterRadius) + mMaxTargetHeight); - } - - private int resolveMeasured(int measureSpec, int desired) - { - int result = 0; - int specSize = MeasureSpec.getSize(measureSpec); - switch (MeasureSpec.getMode(measureSpec)) { - case MeasureSpec.UNSPECIFIED: - result = desired; - break; - case MeasureSpec.AT_MOST: - result = Math.min(specSize, desired); - break; - case MeasureSpec.EXACTLY: - default: - result = specSize; - } - return result; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int minimumWidth = getSuggestedMinimumWidth(); - final int minimumHeight = getSuggestedMinimumHeight(); - int computedWidth = resolveMeasured(widthMeasureSpec, minimumWidth); - int computedHeight = resolveMeasured(heightMeasureSpec, minimumHeight); - computeInsets((computedWidth - minimumWidth), (computedHeight - minimumHeight)); - setMeasuredDimension(computedWidth, computedHeight); - } - - private void switchToState(int state, float x, float y) { - switch (state) { - case STATE_IDLE: - deactivateTargets(); - hideTargets(true, false); - startBackgroundAnimation(0, 0.0f); - mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE); - break; - - case STATE_START: - deactivateHandle(0, 0, 1.0f, null); - startBackgroundAnimation(0, 0.0f); - break; - - case STATE_FIRST_TOUCH: - deactivateTargets(); - showTargets(true); - mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE); - startBackgroundAnimation(INITIAL_SHOW_HANDLE_DURATION, 1.0f); - setGrabbedState(OnTriggerListener.CENTER_HANDLE); - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - announceTargets(); - } - break; - - case STATE_TRACKING: - break; - - case STATE_SNAP: - break; - - case STATE_FINISH: - doFinish(); - break; - } - } - - private void activateHandle(int duration, int delay, float finalAlpha, - AnimatorListener finishListener) { - mHandleAnimations.cancel(); - mHandleAnimations.add(Tweener.to(mHandleDrawable, duration, - "ease", Ease.Cubic.easeIn, - "delay", delay, - "alpha", finalAlpha, - "onUpdate", mUpdateListener, - "onComplete", finishListener)); - mHandleAnimations.start(); - } - - private void deactivateHandle(int duration, int delay, float finalAlpha, - AnimatorListener finishListener) { - mHandleAnimations.cancel(); - mHandleAnimations.add(Tweener.to(mHandleDrawable, duration, - "ease", Ease.Quart.easeOut, - "delay", delay, - "alpha", finalAlpha, - "x", 0, - "y", 0, - "onUpdate", mUpdateListener, - "onComplete", finishListener)); - mHandleAnimations.start(); - } - - /** - * Animation used to attract user's attention to the target button. - * Assumes mChevronDrawables is an a list with an even number of chevrons filled with - * mFeedbackCount items in the order: left, right, top, bottom. - */ - private void startChevronAnimation() { - final float chevronStartDistance = mHandleDrawable.getWidth() * 0.8f; - final float chevronStopDistance = mOuterRadius * 0.9f / 2.0f; - final float startScale = 0.5f; - final float endScale = 2.0f; - final int directionCount = mFeedbackCount > 0 ? mChevronDrawables.size()/mFeedbackCount : 0; - - mChevronAnimations.stop(); - - // Add an animation for all chevron drawables. There are mFeedbackCount drawables - // in each direction and directionCount directions. - for (int direction = 0; direction < directionCount; direction++) { - double angle = 2.0 * Math.PI * direction / directionCount; - final float sx = (float) Math.cos(angle); - final float sy = 0.0f - (float) Math.sin(angle); - final float[] xrange = new float[] - {sx * chevronStartDistance, sx * chevronStopDistance}; - final float[] yrange = new float[] - {sy * chevronStartDistance, sy * chevronStopDistance}; - for (int count = 0; count < mFeedbackCount; count++) { - int delay = count * CHEVRON_INCREMENTAL_DELAY; - final TargetDrawable icon = mChevronDrawables.get(direction*mFeedbackCount + count); - if (icon == null) { - continue; - } - mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION, - "ease", mChevronAnimationInterpolator, - "delay", delay, - "x", xrange, - "y", yrange, - "alpha", new float[] {1.0f, 0.0f}, - "scaleX", new float[] {startScale, endScale}, - "scaleY", new float[] {startScale, endScale}, - "onUpdate", mUpdateListener)); - } - } - mChevronAnimations.start(); - } - - private void deactivateTargets() { - final int count = mTargetDrawables.size(); - for (int i = 0; i < count; i++) { - TargetDrawable target = mTargetDrawables.get(i); - target.setState(TargetDrawable.STATE_INACTIVE); - } - mActiveTarget = -1; - } - - void invalidateGlobalRegion(TargetDrawable drawable) { - int width = drawable.getWidth(); - int height = drawable.getHeight(); - RectF childBounds = new RectF(0, 0, width, height); - childBounds.offset(drawable.getX() - width/2, drawable.getY() - height/2); - View view = this; - while (view.getParent() != null && view.getParent() instanceof View) { - view = (View) view.getParent(); - view.getMatrix().mapRect(childBounds); - view.invalidate((int) Math.floor(childBounds.left), - (int) Math.floor(childBounds.top), - (int) Math.ceil(childBounds.right), - (int) Math.ceil(childBounds.bottom)); - } - } - - /** - * Dispatches a trigger event to listener. Ignored if a listener is not set. - * @param whichTarget the target that was triggered. - */ - private void dispatchTriggerEvent(int whichTarget) { - vibrate(); - if (mOnTriggerListener != null) { - mOnTriggerListener.onTrigger(this, whichTarget); - } - } - - private void dispatchOnFinishFinalAnimation() { - if (mOnTriggerListener != null) { - mOnTriggerListener.onFinishFinalAnimation(); - } - } - - private void doFinish() { - final int activeTarget = mActiveTarget; - final boolean targetHit = activeTarget != -1; - - if (targetHit) { - if (DEBUG) Log.v(TAG, "Finish with target hit = " + targetHit); - - highlightSelected(activeTarget); - - // Inform listener of any active targets. Typically only one will be active. - deactivateHandle(RETURN_TO_HOME_DURATION, RETURN_TO_HOME_DELAY, 0.0f, mResetListener); - dispatchTriggerEvent(activeTarget); - if (!mAlwaysTrackFinger) { - // Force ring and targets to finish animation to final expanded state - mTargetAnimations.stop(); - } - } else { - // Animate handle back to the center based on current state. - deactivateHandle(HIDE_ANIMATION_DURATION, HIDE_ANIMATION_DELAY, 1.0f, - mResetListenerWithPing); - hideTargets(true, false); - } - - setGrabbedState(OnTriggerListener.NO_HANDLE); - } - - private void highlightSelected(int activeTarget) { - // Highlight the given target and fade others - mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE); - hideUnselected(activeTarget); - } - - private void hideUnselected(int active) { - for (int i = 0; i < mTargetDrawables.size(); i++) { - if (i != active) { - mTargetDrawables.get(i).setAlpha(0.0f); - } - } - } - - private void hideTargets(boolean animate, boolean expanded) { - mTargetAnimations.cancel(); - // Note: these animations should complete at the same time so that we can swap out - // the target assets asynchronously from the setTargetResources() call. - mAnimatingTargets = animate; - final int duration = animate ? HIDE_ANIMATION_DURATION : 0; - final int delay = animate ? HIDE_ANIMATION_DELAY : 0; - - final float targetScale = expanded ? TARGET_SCALE_EXPANDED : TARGET_SCALE_COLLAPSED; - final int length = mTargetDrawables.size(); - for (int i = 0; i < length; i++) { - TargetDrawable target = mTargetDrawables.get(i); - target.setState(TargetDrawable.STATE_INACTIVE); - mTargetAnimations.add(Tweener.to(target, duration, - "ease", Ease.Cubic.easeOut, - "alpha", 0.0f, - "scaleX", targetScale, - "scaleY", targetScale, - "delay", delay, - "onUpdate", mUpdateListener)); - } - - final float ringScaleTarget = expanded ? RING_SCALE_EXPANDED : RING_SCALE_COLLAPSED; - mTargetAnimations.add(Tweener.to(mOuterRing, duration, - "ease", Ease.Cubic.easeOut, - "alpha", 0.0f, - "scaleX", ringScaleTarget, - "scaleY", ringScaleTarget, - "delay", delay, - "onUpdate", mUpdateListener, - "onComplete", mTargetUpdateListener)); - - mTargetAnimations.start(); - } - - private void showTargets(boolean animate) { - mTargetAnimations.stop(); - mAnimatingTargets = animate; - final int delay = animate ? SHOW_ANIMATION_DELAY : 0; - final int duration = animate ? SHOW_ANIMATION_DURATION : 0; - final int length = mTargetDrawables.size(); - for (int i = 0; i < length; i++) { - TargetDrawable target = mTargetDrawables.get(i); - target.setState(TargetDrawable.STATE_INACTIVE); - mTargetAnimations.add(Tweener.to(target, duration, - "ease", Ease.Cubic.easeOut, - "alpha", 1.0f, - "scaleX", 1.0f, - "scaleY", 1.0f, - "delay", delay, - "onUpdate", mUpdateListener)); - } - mTargetAnimations.add(Tweener.to(mOuterRing, duration, - "ease", Ease.Cubic.easeOut, - "alpha", 1.0f, - "scaleX", 1.0f, - "scaleY", 1.0f, - "delay", delay, - "onUpdate", mUpdateListener, - "onComplete", mTargetUpdateListener)); - - mTargetAnimations.start(); - } - - private void vibrate() { - final boolean hapticEnabled = Settings.System.getIntForUser( - mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, - UserHandle.USER_CURRENT) != 0; - if (mVibrator != null && hapticEnabled) { - mVibrator.vibrate(mVibrationDuration, AudioManager.STREAM_SYSTEM); - } - } - - private ArrayList<TargetDrawable> loadDrawableArray(int resourceId) { - Resources res = getContext().getResources(); - TypedArray array = res.obtainTypedArray(resourceId); - final int count = array.length(); - ArrayList<TargetDrawable> drawables = new ArrayList<TargetDrawable>(count); - for (int i = 0; i < count; i++) { - TypedValue value = array.peekValue(i); - TargetDrawable target = new TargetDrawable(res, value != null ? value.resourceId : 0); - drawables.add(target); - } - array.recycle(); - return drawables; - } - - private void internalSetTargetResources(int resourceId) { - mTargetDrawables = loadDrawableArray(resourceId); - mTargetResourceId = resourceId; - final int count = mTargetDrawables.size(); - int maxWidth = mHandleDrawable.getWidth(); - int maxHeight = mHandleDrawable.getHeight(); - for (int i = 0; i < count; i++) { - TargetDrawable target = mTargetDrawables.get(i); - maxWidth = Math.max(maxWidth, target.getWidth()); - maxHeight = Math.max(maxHeight, target.getHeight()); - } - if (mMaxTargetWidth != maxWidth || mMaxTargetHeight != maxHeight) { - mMaxTargetWidth = maxWidth; - mMaxTargetHeight = maxHeight; - requestLayout(); // required to resize layout and call updateTargetPositions() - } else { - updateTargetPositions(mWaveCenterX, mWaveCenterY); - updateChevronPositions(mWaveCenterX, mWaveCenterY); - } - } - - /** - * Loads an array of drawables from the given resourceId. - * - * @param resourceId - */ - public void setTargetResources(int resourceId) { - if (mAnimatingTargets) { - // postpone this change until we return to the initial state - mNewTargetResources = resourceId; - } else { - internalSetTargetResources(resourceId); - } - } - - public int getTargetResourceId() { - return mTargetResourceId; - } - - /** - * Sets the resource id specifying the target descriptions for accessibility. - * - * @param resourceId The resource id. - */ - public void setTargetDescriptionsResourceId(int resourceId) { - mTargetDescriptionsResourceId = resourceId; - if (mTargetDescriptions != null) { - mTargetDescriptions.clear(); - } - } - - /** - * Gets the resource id specifying the target descriptions for accessibility. - * - * @return The resource id. - */ - public int getTargetDescriptionsResourceId() { - return mTargetDescriptionsResourceId; - } - - /** - * Sets the resource id specifying the target direction descriptions for accessibility. - * - * @param resourceId The resource id. - */ - public void setDirectionDescriptionsResourceId(int resourceId) { - mDirectionDescriptionsResourceId = resourceId; - if (mDirectionDescriptions != null) { - mDirectionDescriptions.clear(); - } - } - - /** - * Gets the resource id specifying the target direction descriptions. - * - * @return The resource id. - */ - public int getDirectionDescriptionsResourceId() { - return mDirectionDescriptionsResourceId; - } - - /** - * Enable or disable vibrate on touch. - * - * @param enabled - */ - public void setVibrateEnabled(boolean enabled) { - if (enabled && mVibrator == null) { - mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); - } else { - mVibrator = null; - } - } - - /** - * Starts chevron animation. Example use case: show chevron animation whenever the phone rings - * or the user touches the screen. - * - */ - public void ping() { - startChevronAnimation(); - } - - /** - * Resets the widget to default state and cancels all animation. If animate is 'true', will - * animate objects into place. Otherwise, objects will snap back to place. - * - * @param animate - */ - public void reset(boolean animate) { - mChevronAnimations.stop(); - mHandleAnimations.stop(); - mTargetAnimations.stop(); - startBackgroundAnimation(0, 0.0f); - hideChevrons(); - hideTargets(animate, false); - deactivateHandle(0, 0, 1.0f, null); - Tweener.reset(); - } - - private void startBackgroundAnimation(int duration, float alpha) { - Drawable background = getBackground(); - if (mAlwaysTrackFinger && background != null) { - if (mBackgroundAnimator != null) { - mBackgroundAnimator.animator.end(); - } - mBackgroundAnimator = Tweener.to(background, duration, - "ease", Ease.Cubic.easeIn, - "alpha", new int[] {0, (int)(255.0f * alpha)}, - "delay", SHOW_ANIMATION_DELAY); - mBackgroundAnimator.animator.start(); - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - final int action = event.getAction(); - boolean handled = false; - switch (action) { - case MotionEvent.ACTION_DOWN: - if (DEBUG) Log.v(TAG, "*** DOWN ***"); - handleDown(event); - handled = true; - break; - - case MotionEvent.ACTION_MOVE: - if (DEBUG) Log.v(TAG, "*** MOVE ***"); - handleMove(event); - handled = true; - break; - - case MotionEvent.ACTION_UP: - if (DEBUG) Log.v(TAG, "*** UP ***"); - handleMove(event); - handleUp(event); - handled = true; - break; - - case MotionEvent.ACTION_CANCEL: - if (DEBUG) Log.v(TAG, "*** CANCEL ***"); - handleMove(event); - handleCancel(event); - handled = true; - break; - } - invalidate(); - return handled ? true : super.onTouchEvent(event); - } - - private void moveHandleTo(float x, float y, boolean animate) { - mHandleDrawable.setX(x); - mHandleDrawable.setY(y); - } - - private void handleDown(MotionEvent event) { - float eventX = event.getX(); - float eventY = event.getY(); - switchToState(STATE_START, eventX, eventY); - if (!trySwitchToFirstTouchState(eventX, eventY)) { - mDragging = false; - ping(); - } - } - - private void handleUp(MotionEvent event) { - if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE"); - switchToState(STATE_FINISH, event.getX(), event.getY()); - } - - private void handleCancel(MotionEvent event) { - if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL"); - - // We should drop the active target here but it interferes with - // moving off the screen in the direction of the navigation bar. At some point we may - // want to revisit how we handle this. For now we'll allow a canceled event to - // activate the current target. - - // mActiveTarget = -1; // Drop the active target if canceled. - - switchToState(STATE_FINISH, event.getX(), event.getY()); - } - - private void handleMove(MotionEvent event) { - int activeTarget = -1; - final int historySize = event.getHistorySize(); - ArrayList<TargetDrawable> targets = mTargetDrawables; - int ntargets = targets.size(); - float x = 0.0f; - float y = 0.0f; - for (int k = 0; k < historySize + 1; k++) { - float eventX = k < historySize ? event.getHistoricalX(k) : event.getX(); - float eventY = k < historySize ? event.getHistoricalY(k) : event.getY(); - // tx and ty are relative to wave center - float tx = eventX - mWaveCenterX; - float ty = eventY - mWaveCenterY; - float touchRadius = (float) Math.sqrt(dist2(tx, ty)); - final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f; - float limitX = tx * scale; - float limitY = ty * scale; - double angleRad = Math.atan2(-ty, tx); - - if (!mDragging) { - trySwitchToFirstTouchState(eventX, eventY); - } - - if (mDragging) { - // For multiple targets, snap to the one that matches - final float snapRadius = mOuterRadius - mSnapMargin; - final float snapDistance2 = snapRadius * snapRadius; - // Find first target in range - for (int i = 0; i < ntargets; i++) { - TargetDrawable target = targets.get(i); - - double targetMinRad = (i - 0.5) * 2 * Math.PI / ntargets; - double targetMaxRad = (i + 0.5) * 2 * Math.PI / ntargets; - if (target.isEnabled()) { - boolean angleMatches = - (angleRad > targetMinRad && angleRad <= targetMaxRad) || - (angleRad + 2 * Math.PI > targetMinRad && - angleRad + 2 * Math.PI <= targetMaxRad); - if (angleMatches && (dist2(tx, ty) > snapDistance2)) { - activeTarget = i; - } - } - } - } - x = limitX; - y = limitY; - } - - if (!mDragging) { - return; - } - - if (activeTarget != -1) { - switchToState(STATE_SNAP, x,y); - moveHandleTo(x, y, false); - } else { - switchToState(STATE_TRACKING, x, y); - moveHandleTo(x, y, false); - } - - // Draw handle outside parent's bounds - invalidateGlobalRegion(mHandleDrawable); - - if (mActiveTarget != activeTarget) { - // Defocus the old target - if (mActiveTarget != -1) { - TargetDrawable target = targets.get(mActiveTarget); - if (target.hasState(TargetDrawable.STATE_FOCUSED)) { - target.setState(TargetDrawable.STATE_INACTIVE); - } - } - // Focus the new target - if (activeTarget != -1) { - TargetDrawable target = targets.get(activeTarget); - if (target.hasState(TargetDrawable.STATE_FOCUSED)) { - target.setState(TargetDrawable.STATE_FOCUSED); - } - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - String targetContentDescription = getTargetDescription(activeTarget); - announceText(targetContentDescription); - } - activateHandle(0, 0, 0.0f, null); - } else { - activateHandle(0, 0, 1.0f, null); - } - } - mActiveTarget = activeTarget; - } - - @Override - public boolean onHoverEvent(MotionEvent event) { - if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) { - final int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_HOVER_ENTER: - event.setAction(MotionEvent.ACTION_DOWN); - break; - case MotionEvent.ACTION_HOVER_MOVE: - event.setAction(MotionEvent.ACTION_MOVE); - break; - case MotionEvent.ACTION_HOVER_EXIT: - event.setAction(MotionEvent.ACTION_UP); - break; - } - onTouchEvent(event); - event.setAction(action); - } - return super.onHoverEvent(event); - } - - /** - * Sets the current grabbed state, and dispatches a grabbed state change - * event to our listener. - */ - private void setGrabbedState(int newState) { - if (newState != mGrabbedState) { - if (newState != OnTriggerListener.NO_HANDLE) { - vibrate(); - } - mGrabbedState = newState; - if (mOnTriggerListener != null) { - if (newState == OnTriggerListener.NO_HANDLE) { - mOnTriggerListener.onReleased(this, OnTriggerListener.CENTER_HANDLE); - } else { - mOnTriggerListener.onGrabbed(this, OnTriggerListener.CENTER_HANDLE); - } - mOnTriggerListener.onGrabbedStateChange(this, newState); - } - } - } - - private boolean trySwitchToFirstTouchState(float x, float y) { - final float tx = x - mWaveCenterX; - final float ty = y - mWaveCenterY; - if (mAlwaysTrackFinger || dist2(tx,ty) <= getScaledTapRadiusSquared()) { - if (DEBUG) Log.v(TAG, "** Handle HIT"); - switchToState(STATE_FIRST_TOUCH, x, y); - moveHandleTo(tx, ty, false); - mDragging = true; - return true; - } - return false; - } - - private void assignDefaultsIfNeeded() { - if (mOuterRadius == 0.0f) { - mOuterRadius = Math.max(mOuterRing.getWidth(), mOuterRing.getHeight())/2.0f; - } - if (mSnapMargin == 0.0f) { - mSnapMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - SNAP_MARGIN_DEFAULT, getContext().getResources().getDisplayMetrics()); - } - } - - private void computeInsets(int dx, int dy) { - final int layoutDirection = getLayoutDirection(); - final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); - - switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { - case Gravity.LEFT: - mHorizontalInset = 0; - break; - case Gravity.RIGHT: - mHorizontalInset = dx; - break; - case Gravity.CENTER_HORIZONTAL: - default: - mHorizontalInset = dx / 2; - break; - } - switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) { - case Gravity.TOP: - mVerticalInset = 0; - break; - case Gravity.BOTTOM: - mVerticalInset = dy; - break; - case Gravity.CENTER_VERTICAL: - default: - mVerticalInset = dy / 2; - break; - } - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - final int width = right - left; - final int height = bottom - top; - - // Target placement width/height. This puts the targets on the greater of the ring - // width or the specified outer radius. - final float placementWidth = Math.max(mOuterRing.getWidth(), 2 * mOuterRadius); - final float placementHeight = Math.max(mOuterRing.getHeight(), 2 * mOuterRadius); - float newWaveCenterX = mHorizontalInset - + Math.max(width, mMaxTargetWidth + placementWidth) / 2; - float newWaveCenterY = mVerticalInset - + Math.max(height, + mMaxTargetHeight + placementHeight) / 2; - - if (mInitialLayout) { - hideChevrons(); - hideTargets(false, false); - moveHandleTo(0, 0, false); - mInitialLayout = false; - } - - mOuterRing.setPositionX(newWaveCenterX); - mOuterRing.setPositionY(newWaveCenterY); - - mHandleDrawable.setPositionX(newWaveCenterX); - mHandleDrawable.setPositionY(newWaveCenterY); - - updateTargetPositions(newWaveCenterX, newWaveCenterY); - updateChevronPositions(newWaveCenterX, newWaveCenterY); - - mWaveCenterX = newWaveCenterX; - mWaveCenterY = newWaveCenterY; - - if (DEBUG) dump(); - } - - private void updateTargetPositions(float centerX, float centerY) { - // Reposition the target drawables if the view changed. - ArrayList<TargetDrawable> targets = mTargetDrawables; - final int size = targets.size(); - final float alpha = (float) (-2.0f * Math.PI / size); - for (int i = 0; i < size; i++) { - final TargetDrawable targetIcon = targets.get(i); - final float angle = alpha * i; - targetIcon.setPositionX(centerX); - targetIcon.setPositionY(centerY); - targetIcon.setX(mOuterRadius * (float) Math.cos(angle)); - targetIcon.setY(mOuterRadius * (float) Math.sin(angle)); - } - } - - private void updateChevronPositions(float centerX, float centerY) { - ArrayList<TargetDrawable> chevrons = mChevronDrawables; - final int size = chevrons.size(); - for (int i = 0; i < size; i++) { - TargetDrawable target = chevrons.get(i); - if (target != null) { - target.setPositionX(centerX); - target.setPositionY(centerY); - } - } - } - - private void hideChevrons() { - ArrayList<TargetDrawable> chevrons = mChevronDrawables; - final int size = chevrons.size(); - for (int i = 0; i < size; i++) { - TargetDrawable chevron = chevrons.get(i); - if (chevron != null) { - chevron.setAlpha(0.0f); - } - } - } - - @Override - protected void onDraw(Canvas canvas) { - mOuterRing.draw(canvas); - final int ntargets = mTargetDrawables.size(); - for (int i = 0; i < ntargets; i++) { - TargetDrawable target = mTargetDrawables.get(i); - if (target != null) { - target.draw(canvas); - } - } - final int nchevrons = mChevronDrawables.size(); - for (int i = 0; i < nchevrons; i++) { - TargetDrawable chevron = mChevronDrawables.get(i); - if (chevron != null) { - chevron.draw(canvas); - } - } - mHandleDrawable.draw(canvas); - } - - public void setOnTriggerListener(OnTriggerListener listener) { - mOnTriggerListener = listener; - } - - private float square(float d) { - return d * d; - } - - private float dist2(float dx, float dy) { - return dx*dx + dy*dy; - } - - private float getScaledTapRadiusSquared() { - final float scaledTapRadius; - if (AccessibilityManager.getInstance(mContext).isEnabled()) { - scaledTapRadius = TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED * mTapRadius; - } else { - scaledTapRadius = mTapRadius; - } - return square(scaledTapRadius); - } - - private void announceTargets() { - StringBuilder utterance = new StringBuilder(); - final int targetCount = mTargetDrawables.size(); - for (int i = 0; i < targetCount; i++) { - String targetDescription = getTargetDescription(i); - String directionDescription = getDirectionDescription(i); - if (!TextUtils.isEmpty(targetDescription) - && !TextUtils.isEmpty(directionDescription)) { - String text = String.format(directionDescription, targetDescription); - utterance.append(text); - } - if (utterance.length() > 0) { - announceText(utterance.toString()); - } - } - } - - private void announceText(String text) { - setContentDescription(text); - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); - setContentDescription(null); - } - - private String getTargetDescription(int index) { - if (mTargetDescriptions == null || mTargetDescriptions.isEmpty()) { - mTargetDescriptions = loadDescriptions(mTargetDescriptionsResourceId); - if (mTargetDrawables.size() != mTargetDescriptions.size()) { - Log.w(TAG, "The number of target drawables must be" - + " euqal to the number of target descriptions."); - return null; - } - } - return mTargetDescriptions.get(index); - } - - private String getDirectionDescription(int index) { - if (mDirectionDescriptions == null || mDirectionDescriptions.isEmpty()) { - mDirectionDescriptions = loadDescriptions(mDirectionDescriptionsResourceId); - if (mTargetDrawables.size() != mDirectionDescriptions.size()) { - Log.w(TAG, "The number of target drawables must be" - + " euqal to the number of direction descriptions."); - return null; - } - } - return mDirectionDescriptions.get(index); - } - - private ArrayList<String> loadDescriptions(int resourceId) { - TypedArray array = getContext().getResources().obtainTypedArray(resourceId); - final int count = array.length(); - ArrayList<String> targetContentDescriptions = new ArrayList<String>(count); - for (int i = 0; i < count; i++) { - String contentDescription = array.getString(i); - targetContentDescriptions.add(contentDescription); - } - array.recycle(); - return targetContentDescriptions; - } - - public int getResourceIdForTarget(int index) { - final TargetDrawable drawable = mTargetDrawables.get(index); - return drawable == null ? 0 : drawable.getResourceId(); - } - - public void setEnableTarget(int resourceId, boolean enabled) { - for (int i = 0; i < mTargetDrawables.size(); i++) { - final TargetDrawable target = mTargetDrawables.get(i); - if (target.getResourceId() == resourceId) { - target.setEnabled(enabled); - break; // should never be more than one match - } - } - } - - /** - * Gets the position of a target in the array that matches the given resource. - * @param resourceId - * @return the index or -1 if not found - */ - public int getTargetPosition(int resourceId) { - for (int i = 0; i < mTargetDrawables.size(); i++) { - final TargetDrawable target = mTargetDrawables.get(i); - if (target.getResourceId() == resourceId) { - return i; // should never be more than one match - } - } - return -1; - } - - private boolean replaceTargetDrawables(Resources res, int existingResourceId, - int newResourceId) { - if (existingResourceId == 0 || newResourceId == 0) { - return false; - } - - boolean result = false; - final ArrayList<TargetDrawable> drawables = mTargetDrawables; - final int size = drawables.size(); - for (int i = 0; i < size; i++) { - final TargetDrawable target = drawables.get(i); - if (target != null && target.getResourceId() == existingResourceId) { - target.setDrawable(res, newResourceId); - result = true; - } - } - - if (result) { - requestLayout(); // in case any given drawable's size changes - } - - return result; - } - - /** - * Searches the given package for a resource to use to replace the Drawable on the - * target with the given resource id - * @param component of the .apk that contains the resource - * @param name of the metadata in the .apk - * @param existingResId the resource id of the target to search for - * @return true if found in the given package and replaced at least one target Drawables - */ - public boolean replaceTargetDrawablesIfPresent(ComponentName component, String name, - int existingResId) { - if (existingResId == 0) return false; - - try { - PackageManager packageManager = mContext.getPackageManager(); - // Look for the search icon specified in the activity meta-data - Bundle metaData = packageManager.getActivityInfo( - component, PackageManager.GET_META_DATA).metaData; - if (metaData != null) { - int iconResId = metaData.getInt(name); - if (iconResId != 0) { - Resources res = packageManager.getResourcesForActivity(component); - return replaceTargetDrawables(res, existingResId, iconResId); - } - } - } catch (NameNotFoundException e) { - Log.w(TAG, "Failed to swap drawable; " - + component.flattenToShortString() + " not found", e); - } catch (Resources.NotFoundException nfe) { - Log.w(TAG, "Failed to swap drawable from " - + component.flattenToShortString(), nfe); - } - return false; - } -} diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index df7cde7..999bc57 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -6033,16 +6033,16 @@ <eat-comment /> <declare-styleable name="GlowPadView"> <!-- Reference to an array resource that be shown as targets around a circle. --> - <attr name="targetDrawables"/> + <attr name="targetDrawables" format="reference" /> <!-- Reference to an array resource that be used as description for the targets around the circle. --> - <attr name="targetDescriptions"/> + <attr name="targetDescriptions" format="reference" /> <!-- Reference to an array resource that be used to announce the directions with targets around the circle. --> - <attr name="directionDescriptions"/> + <attr name="directionDescriptions" format="reference" /> <!-- Sets a drawable as the center. --> - <attr name="handleDrawable"/> + <attr name="handleDrawable" format="reference" /> <!-- Drawable to use for wave ripple animation. --> <attr name="outerRingDrawable" format="reference"/> @@ -6054,22 +6054,22 @@ <attr name="innerRadius"/> <!-- Outer radius of glow area. Target icons will be drawn on this circle. --> - <attr name="outerRadius"/> + <attr name="outerRadius" format="dimension" /> <!-- Radius of glow under finger. --> <attr name="glowRadius" format="dimension" /> <!-- Tactile feedback duration for actions. Set to '0' for no vibration. --> - <attr name="vibrationDuration"/> + <attr name="vibrationDuration" format="integer" /> <!-- How close we need to be before snapping to a target. --> - <attr name="snapMargin"/> + <attr name="snapMargin" format="dimension" /> <!-- Number of waves/chevrons to show in animation. --> - <attr name="feedbackCount"/> + <attr name="feedbackCount" format="integer" /> <!-- Used when the handle shouldn't wait to be hit before following the finger --> - <attr name="alwaysTrackFinger"/> + <attr name="alwaysTrackFinger" format="boolean" /> <!-- Location along the circle of the first item, in degrees.--> <attr name="firstItemOffset" format="float" /> @@ -6086,45 +6086,6 @@ </declare-styleable> <!-- =============================== --> - <!-- MultiWaveView class attributes --> - <!-- =============================== --> - <eat-comment /> - <declare-styleable name="MultiWaveView"> - <!-- Reference to an array resource that be shown as targets around a circle. --> - <attr name="targetDrawables" format="reference"/> - - <!-- Reference to an array resource that be used as description for the targets around the circle. --> - <attr name="targetDescriptions" format="reference"/> - - <!-- Reference to an array resource that be used to announce the directions with targets around the circle. --> - <attr name="directionDescriptions" format="reference"/> - - <!-- Sets a drawable as the drag center. --> - <attr name="handleDrawable" format="reference" /> - - <!-- Drawables to use for chevron animations. May be null. --> - <attr name="chevronDrawables" format="reference"/> - - <!-- Drawable to use for wave ripple animation. --> - <attr name="waveDrawable" format="reference" /> - - <!-- Outer radius of target circle. Icons will be drawn on this circle. --> - <attr name="outerRadius" format="dimension" /> - - <!-- Tactile feedback duration for actions. Set to '0' for no vibration. --> - <attr name="vibrationDuration" format="integer"/> - - <!-- How close we need to be before snapping to a target. --> - <attr name="snapMargin" format="dimension" /> - - <!-- Number of waves/chevrons to show in animation. --> - <attr name="feedbackCount" format="integer" /> - - <!-- Used when the handle shouldn't wait to be hit before following the finger --> - <attr name="alwaysTrackFinger" format="boolean" /> - </declare-styleable> - - <!-- =============================== --> <!-- SizeAdaptiveLayout class attributes --> <!-- =============================== --> <eat-comment /> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 1dd9300..77ab17b 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -56,10 +56,10 @@ <!-- Amount of time to hold off before showing the search panel when the user presses home --> <integer name="config_show_search_delay">200</integer> - <!-- Vibration duration for MultiWaveView used in SearchPanelView --> + <!-- Vibration duration for GlowPadView used in SearchPanelView --> <integer translatable="false" name="config_vibration_duration">0</integer> - <!-- Vibration duration for MultiWaveView used in SearchPanelView --> + <!-- Vibration duration for GlowPadView used in SearchPanelView --> <integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer> <!-- The length of the vibration when the notification pops open. --> |