diff options
95 files changed, 1596 insertions, 57 deletions
diff --git a/api/current.txt b/api/current.txt index aed11b0..63771b9 100644 --- a/api/current.txt +++ b/api/current.txt @@ -425,6 +425,7 @@ package android { field public static final int fastScrollTextColor = 16843609; // 0x1010359 field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336 field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339 + field public static final int feedbackCount = 16843665; // 0x1010391 field public static final int fillAfter = 16843197; // 0x10101bd field public static final int fillBefore = 16843196; // 0x10101bc field public static final int fillEnabled = 16843343; // 0x101024f @@ -478,6 +479,7 @@ package android { field public static final int hand_hour = 16843011; // 0x1010103 field public static final int hand_minute = 16843012; // 0x1010104 field public static final int handle = 16843354; // 0x101025a + field public static final int handleDrawable = 16843657; // 0x1010389 field public static final int handleProfiling = 16842786; // 0x1010022 field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e field public static final int hardwareAccelerated = 16843475; // 0x10102d3 @@ -486,10 +488,12 @@ package android { field public static final int headerDividersEnabled = 16843310; // 0x101022e field public static final int height = 16843093; // 0x1010155 field public static final int hint = 16843088; // 0x1010150 + field public static final int hitRadius = 16843662; // 0x101038e field public static final int homeAsUpIndicator = 16843531; // 0x101030b field public static final int homeLayout = 16843549; // 0x101031d field public static final int horizontalDivider = 16843053; // 0x101012d field public static final int horizontalGap = 16843327; // 0x101023f + field public static final int horizontalOffset = 16843667; // 0x1010393 field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353 field public static final int horizontalSpacing = 16843028; // 0x1010114 field public static final int host = 16842792; // 0x1010028 @@ -610,6 +614,7 @@ package android { field public static final int layout_x = 16843135; // 0x101017f field public static final int layout_y = 16843136; // 0x1010180 field public static final int left = 16843181; // 0x10101ad + field public static final int leftChevronDrawable = 16843658; // 0x101038a field public static final int lineSpacingExtra = 16843287; // 0x1010217 field public static final int lineSpacingMultiplier = 16843288; // 0x1010218 field public static final int lines = 16843092; // 0x1010154 @@ -681,6 +686,7 @@ package android { field public static final int orderingFromXml = 16843239; // 0x10101e7 field public static final int orientation = 16842948; // 0x10100c4 field public static final int outAnimation = 16843128; // 0x1010178 + field public static final int outerRadius = 16843661; // 0x101038d field public static final int overScrollFooter = 16843459; // 0x10102c3 field public static final int overScrollHeader = 16843458; // 0x10102c2 field public static final int overScrollMode = 16843457; // 0x10102c1 @@ -769,6 +775,7 @@ package android { field public static final int restoreAnyVersion = 16843450; // 0x10102ba field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d field public static final int right = 16843183; // 0x10101af + field public static final int rightChevronDrawable = 16843659; // 0x101038b field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093 field public static final int ringtoneType = 16843257; // 0x10101f9 field public static final int rotation = 16843558; // 0x1010326 @@ -844,6 +851,7 @@ package android { field public static final int smallIcon = 16843422; // 0x101029e field public static final int smallScreens = 16843396; // 0x1010284 field public static final int smoothScrollbar = 16843313; // 0x1010231 + field public static final int snapMargin = 16843664; // 0x1010390 field public static final int soundEffectsEnabled = 16843285; // 0x1010215 field public static final int spacing = 16843027; // 0x1010113 field public static final int spinnerDropDownItemStyle = 16842887; // 0x1010087 @@ -908,6 +916,7 @@ package android { field public static final int tag = 16842961; // 0x10100d1 field public static final int targetActivity = 16843266; // 0x1010202 field public static final int targetClass = 16842799; // 0x101002f + field public static final int targetDrawables = 16843656; // 0x1010388 field public static final int targetPackage = 16842785; // 0x1010021 field public static final int targetSdkVersion = 16843376; // 0x1010270 field public static final int taskAffinity = 16842770; // 0x1010012 @@ -1026,8 +1035,10 @@ package android { field public static final int verticalCorrection = 16843322; // 0x101023a field public static final int verticalDivider = 16843054; // 0x101012e field public static final int verticalGap = 16843328; // 0x1010240 + field public static final int verticalOffset = 16843666; // 0x1010392 field public static final int verticalScrollbarPosition = 16843572; // 0x1010334 field public static final int verticalSpacing = 16843029; // 0x1010115 + field public static final int vibrationDuration = 16843663; // 0x101038f field public static final int visibility = 16842972; // 0x10100dc field public static final int visible = 16843156; // 0x1010194 field public static final int vmSafeMode = 16843448; // 0x10102b8 @@ -1044,6 +1055,7 @@ package android { field public static final int wallpaperIntraOpenExitAnimation = 16843416; // 0x1010298 field public static final int wallpaperOpenEnterAnimation = 16843411; // 0x1010293 field public static final int wallpaperOpenExitAnimation = 16843412; // 0x1010294 + field public static final int waveDrawable = 16843660; // 0x101038c field public static final int webTextViewStyle = 16843449; // 0x10102b9 field public static final int webViewStyle = 16842885; // 0x1010085 field public static final int weekDayTextAppearance = 16843592; // 0x1010348 diff --git a/core/java/com/android/internal/widget/multiwaveview/Ease.java b/core/java/com/android/internal/widget/multiwaveview/Ease.java new file mode 100644 index 0000000..7f90c44 --- /dev/null +++ b/core/java/com/android/internal/widget/multiwaveview/Ease.java @@ -0,0 +1,132 @@ +/* + * 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.TimeInterpolator; + +class Ease { + private static final float DOMAIN = 1.0f; + private static final float DURATION = 1.0f; + private static final float START = 0.0f; + + static class Linear { + public static final TimeInterpolator easeNone = new TimeInterpolator() { + public float getInterpolation(float input) { + return input; + } + }; + } + + static class Cubic { + public static final TimeInterpolator easeIn = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN*(input/=DURATION)*input*input + START; + } + }; + public static final TimeInterpolator easeOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN*((input=input/DURATION-1)*input*input + 1) + START; + } + }; + public static final TimeInterpolator easeInOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return ((input/=DURATION/2) < 1.0f) ? + (DOMAIN/2*input*input*input + START) + : (DOMAIN/2*((input-=2)*input*input + 2) + START); + } + }; + } + + static class Quad { + public static final TimeInterpolator easeIn = new TimeInterpolator() { + public float getInterpolation (float input) { + return DOMAIN*(input/=DURATION)*input + START; + } + }; + public static final TimeInterpolator easeOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return -DOMAIN *(input/=DURATION)*(input-2) + START; + } + }; + public static final TimeInterpolator easeInOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return ((input/=DURATION/2) < 1) ? + (DOMAIN/2*input*input + START) + : (-DOMAIN/2 * ((--input)*(input-2) - 1) + START); + } + }; + } + + static class Quart { + public static final TimeInterpolator easeIn = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN*(input/=DURATION)*input*input*input + START; + } + }; + public static final TimeInterpolator easeOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return -DOMAIN * ((input=input/DURATION-1)*input*input*input - 1) + START; + } + }; + public static final TimeInterpolator easeInOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return ((input/=DURATION/2) < 1) ? + (DOMAIN/2*input*input*input*input + START) + : (-DOMAIN/2 * ((input-=2)*input*input*input - 2) + START); + } + }; + } + + static class Quint { + public static final TimeInterpolator easeIn = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN*(input/=DURATION)*input*input*input*input + START; + } + }; + public static final TimeInterpolator easeOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN*((input=input/DURATION-1)*input*input*input*input + 1) + START; + } + }; + public static final TimeInterpolator easeInOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return ((input/=DURATION/2) < 1) ? + (DOMAIN/2*input*input*input*input*input + START) + : (DOMAIN/2*((input-=2)*input*input*input*input + 2) + START); + } + }; + } + + static class Sine { + public static final TimeInterpolator easeIn = new TimeInterpolator() { + public float getInterpolation(float input) { + return -DOMAIN * (float) Math.cos(input/DURATION * (Math.PI/2)) + DOMAIN + START; + } + }; + public static final TimeInterpolator easeOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return DOMAIN * (float) Math.sin(input/DURATION * (Math.PI/2)) + START; + } + }; + public static final TimeInterpolator easeInOut = new TimeInterpolator() { + public float getInterpolation(float input) { + return -DOMAIN/2 * ((float)Math.cos(Math.PI*input/DURATION) - 1.0f) + START; + } + }; + } + +} diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java new file mode 100644 index 0000000..026ad27 --- /dev/null +++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java @@ -0,0 +1,645 @@ +/* + * 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 java.util.ArrayList; + +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.ObjectAnimator; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.content.Context; +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.os.Vibrator; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.View; + +import com.android.internal.R; + +/** + * 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 implements AnimatorUpdateListener { + 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_FIRST_TOUCH = 1; + private static final int STATE_TRACKING = 2; + private static final int STATE_SNAP = 3; + private static final int STATE_FINISH = 4; + + // 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); + } + + // Tune-able parameters + private static final int CHEVRON_INCREMENTAL_DELAY = 50; + private static final int CHEVRON_ANIMATION_DURATION = 1000; + private static final int RETURN_TO_HOME_DURATION = 150; + private static final int HIDE_ANIMATION_DELAY = 500; + private static final int HIDE_ANIMATION_DURACTION = 2000; + private static final int SHOW_ANIMATION_DURATION = 0; + private static final int SHOW_ANIMATION_DELAY = 0; + private TimeInterpolator mChevronAnimationInterpolator = Ease.Quint.easeOut; + + private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>(); + private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>(); + private ArrayList<Tweener> mChevronAnimations = new ArrayList<Tweener>(); + private ArrayList<Tweener> mTargetAnimations = new ArrayList<Tweener>(); + private Tweener mHandleAnimation; + 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 float mVerticalOffset; + private float mHorizontalOffset; + private float mOuterRadius = 0.0f; + private float mHitRadius = 0.0f; + private float mSnapMargin = 0.0f; + private boolean mDragging; + + private AnimatorListener mResetListener = new Animator.AnimatorListener() { + public void onAnimationStart(Animator animation) { } + public void onAnimationRepeat(Animator animation) { } + public void onAnimationEnd(Animator animation) { + switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY); + } + public void onAnimationCancel(Animator animation) { } + }; + + 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); + mHorizontalOffset = a.getDimension(R.styleable.MultiWaveView_horizontalOffset, + mHorizontalOffset); + mVerticalOffset = a.getDimension(R.styleable.MultiWaveView_verticalOffset, + mVerticalOffset); + mHitRadius = a.getDimension(R.styleable.MultiWaveView_hitRadius, mHitRadius); + 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.getDrawable(R.styleable.MultiWaveView_handleDrawable)); + mTapRadius = mHandleDrawable.getWidth()/2; + mOuterRing = new TargetDrawable(res, a.getDrawable(R.styleable.MultiWaveView_waveDrawable)); + + // Read animation drawables + Drawable leftChevron = a.getDrawable(R.styleable.MultiWaveView_leftChevronDrawable); + if (leftChevron != null) { + for (int i = 0; i < mFeedbackCount; i++) { + mChevronDrawables.add(new TargetDrawable(res, leftChevron)); + } + } + Drawable rightChevron = a.getDrawable(R.styleable.MultiWaveView_rightChevronDrawable); + if (rightChevron != null) { + for (int i = 0; i < mFeedbackCount; i++) { + mChevronDrawables.add(new TargetDrawable(res, rightChevron)); + } + } + + // Read array of target drawables + TypedValue outValue = new TypedValue(); + if (a.getValue(R.styleable.MultiWaveView_targetDrawables, outValue)) { + setTargetResources(outValue.resourceId); + } + if (mTargetDrawables == null || mTargetDrawables.size() == 0) { + throw new IllegalStateException("Must specify at least one target drawable"); + } + + setVibrateEnabled(mVibrationDuration > 0); + } + + private void dump() { + Log.v(TAG, "Outer Radius = " + mOuterRadius); + Log.v(TAG, "HitRadius = " + mHitRadius); + 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); + Log.v(TAG, "HorizontalOffset = " + mHorizontalOffset); + Log.v(TAG, "VerticalOffset = " + mVerticalOffset); + } + + @Override + protected int getSuggestedMinimumWidth() { + // View should be large enough to contain the background + target drawable on either edge + return mOuterRing.getWidth() + + (mTargetDrawables.size() > 0 ? (mTargetDrawables.get(0).getWidth()) : 0); + } + + @Override + protected int getSuggestedMinimumHeight() { + // View should be large enough to contain the unlock ring + target drawable on either edge + return mOuterRing.getHeight() + + (mTargetDrawables.size() > 0 ? (mTargetDrawables.get(0).getHeight()) : 0); + } + + private void switchToState(int state, float x, float y) { + switch (state) { + case STATE_IDLE: + stopChevronAnimation(); + deactivateTargets(); + mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE); + break; + + case STATE_FIRST_TOUCH: + stopHandleAnimation(); + deactivateTargets(); + showTargets(); + mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE); + setGrabbedState(OnTriggerListener.CENTER_HANDLE); + break; + + case STATE_TRACKING: + break; + + case STATE_SNAP: + break; + + case STATE_FINISH: + doFinish(); + break; + } + } + + /** + * 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 left + * followed by right chevrons. + */ + private void startChevronAnimation() { + final int icons = mChevronDrawables.size(); + for (Tweener tween : mChevronAnimations) { + tween.animator.cancel(); + } + for (int i = 0; i < icons; i++) { + TargetDrawable icon = mChevronDrawables.get(i); + icon.setY(mWaveCenterY); + icon.setAlpha(1.0f); + mChevronAnimations.clear(); + int delay = (int) (Math.abs(0.5f + i - icons / 2) * CHEVRON_INCREMENTAL_DELAY); + if (i < icons/2) { + // Left chevrons + icon.setX(mWaveCenterX - mHandleDrawable.getWidth() / 2); + mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION, + "ease", mChevronAnimationInterpolator, + "delay", delay, + "x", mWaveCenterX - mOuterRadius, + "alpha", 0.0f, + "onUpdate", this)); + } else { + // Right chevrons + icon.setX(mWaveCenterX + mHandleDrawable.getWidth() / 2); + mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION, + "ease", mChevronAnimationInterpolator, + "delay", delay, + "x", mWaveCenterX + mOuterRadius, + "alpha", 0.0f, + "onUpdate", this)); + } + } + } + + private void stopChevronAnimation() { + for (Tweener anim : mChevronAnimations) { + anim.animator.end(); + } + mChevronAnimations.clear(); + } + + private void stopHandleAnimation() { + if (mHandleAnimation != null) { + mHandleAnimation.animator.end(); + mHandleAnimation = null; + } + } + + private void deactivateTargets() { + for (TargetDrawable target : mTargetDrawables) { + 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 whichHandle the handle that triggered the event. + */ + private void dispatchTriggerEvent(int whichHandle) { + vibrate(); + if (mOnTriggerListener != null) { + mOnTriggerListener.onTrigger(this, whichHandle); + } + } + + private void doFinish() { + // Inform listener of any active targets. Typically only one will be active. + final int activeTarget = mActiveTarget; + boolean targetHit = activeTarget != -1; + if (targetHit) { + Log.v(TAG, "Finish with target hit = " + targetHit); + dispatchTriggerEvent(mActiveTarget); + } + + setGrabbedState(OnTriggerListener.NO_HANDLE); + + // Animate finger outline back to home position + mHandleDrawable.setAlpha(targetHit ? 0.0f : 1.0f); + mHandleAnimation = Tweener.to(mHandleDrawable, RETURN_TO_HOME_DURATION, + "ease", Ease.Quart.easeOut, + "delay", targetHit ? HIDE_ANIMATION_DELAY : 0, + "alpha", 1.0f, + "x", mWaveCenterX, + "y", mWaveCenterY, + "onUpdate", this, + "onComplete", mResetListener); + + // Hide unselected targets + hideTargets(true); + + // Highlight the selected one + if (targetHit) { + mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE); + } + + stopChevronAnimation(); + } + + private void hideTargets(boolean animate) { + if (mTargetAnimations.size() > 0) { + stopTargetAnimation(); + } + for (TargetDrawable target : mTargetDrawables) { + target.setState(TargetDrawable.STATE_INACTIVE); + mTargetAnimations.add(Tweener.to(target, + animate ? HIDE_ANIMATION_DURACTION : 0, + "alpha", 0.0f, + "delay", HIDE_ANIMATION_DELAY, + "onUpdate", this)); + } + mTargetAnimations.add(Tweener.to(mOuterRing, + animate ? HIDE_ANIMATION_DURACTION : 0, + "alpha", 0.0f, + "delay", HIDE_ANIMATION_DELAY, + "onUpdate", this)); + } + + private void showTargets() { + if (mTargetAnimations.size() > 0) { + stopTargetAnimation(); + } + for (TargetDrawable target : mTargetDrawables) { + target.setState(TargetDrawable.STATE_INACTIVE); + mTargetAnimations.add(Tweener.to(target, SHOW_ANIMATION_DURATION, + "alpha", 1.0f, + "delay", SHOW_ANIMATION_DELAY, + "onUpdate", this)); + } + mTargetAnimations.add(Tweener.to(mOuterRing, SHOW_ANIMATION_DURATION, + "alpha", 1.0f, + "delay", SHOW_ANIMATION_DELAY, + "onUpdate", this)); + } + + private void stopTargetAnimation() { + for (Tweener anim : mTargetAnimations) { + anim.animator.end(); + } + mTargetAnimations.clear(); + } + + private void vibrate() { + if (mVibrator != null) { + mVibrator.vibrate(mVibrationDuration); + } + } + + /** + * Loads an array of drawables from the given resourceId. + * + * @param resourceId + */ + public void setTargetResources(int resourceId) { + Resources res = getContext().getResources(); + TypedArray array = res.obtainTypedArray(resourceId); + int count = array.length(); + mTargetDrawables = new ArrayList<TargetDrawable>(count); + for (int i = 0; i < count; i++) { + Drawable drawable = array.getDrawable(i); + mTargetDrawables.add(new TargetDrawable(res, drawable)); + } + } + + /** + * 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() { + stopChevronAnimation(); + 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) { + stopChevronAnimation(); + stopHandleAnimation(); + stopTargetAnimation(); + hideChevrons(); + hideTargets(animate); + mHandleDrawable.setX(mWaveCenterX); + mHandleDrawable.setY(mWaveCenterY); + mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + final int action = event.getAction(); + + boolean handled = false; + float x = event.getX(); + float y = event.getY(); + switch (action) { + case MotionEvent.ACTION_DOWN: + handleDown(x, y); + handled = true; + break; + + case MotionEvent.ACTION_MOVE: + handleMove(x, y); + handled = true; + break; + + case MotionEvent.ACTION_UP: + handleUp(x, y); + handleMove(x, y); + handled = true; + break; + + case MotionEvent.ACTION_CANCEL: + handleMove(x, y); + handled = true; + break; + } + invalidate(); + return handled ? true : super.onTouchEvent(event); + } + + private void handleDown(float x, float y) { + final float dx = x - mWaveCenterX; + final float dy = y - mWaveCenterY; + if (dist2(dx,dy) <= square(mTapRadius)) { + if (DEBUG) Log.v(TAG, "** Handle HIT"); + switchToState(STATE_FIRST_TOUCH, x, y); + mDragging = true; + } else { + mDragging = false; + stopTargetAnimation(); + ping(); + } + } + + private void handleUp(float x, float y) { + if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE"); + switchToState(STATE_FINISH, x, y); + } + + private void handleMove(float x, float y) { + if (!mDragging) { + return; + } + + float tx = x - mWaveCenterX; + float ty = y - mWaveCenterY; + float touchRadius = (float) Math.sqrt(dist2(tx, ty)); + final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f; + float limitX = mWaveCenterX + tx * scale; + float limitY = mWaveCenterY + ty * scale; + + int activeTarget = -1; + boolean singleTarget = mTargetDrawables.size() == 1; + if (singleTarget) { + // Snap to outer ring if there's only one target + float snapRadius = mOuterRadius - mSnapMargin; + if (touchRadius > snapRadius) { + activeTarget = 0; + x = limitX; + y = limitY; + } + } else { + // If there's more than one target, snap to the closest one less than hitRadius away. + float best = Float.MAX_VALUE; + final float hitRadius2 = mHitRadius * mHitRadius; + for (int i = 0; i < mTargetDrawables.size(); i++) { + // Snap to the first target in range + TargetDrawable target = mTargetDrawables.get(i); + float dx = limitX - target.getX(); + float dy = limitY - target.getY(); + float dist2 = dx*dx + dy*dy; + if (target.isValid() && dist2 < hitRadius2 && dist2 < best) { + activeTarget = i; + best = dist2; + } + } + } + if (activeTarget != -1) { + switchToState(STATE_SNAP, x,y); + mHandleDrawable.setX(singleTarget ? limitX : mTargetDrawables.get(activeTarget).getX()); + mHandleDrawable.setY(singleTarget ? limitY : mTargetDrawables.get(activeTarget).getY()); + TargetDrawable currentTarget = mTargetDrawables.get(activeTarget); + if (currentTarget.hasState(TargetDrawable.STATE_FOCUSED)) { + currentTarget.setState(TargetDrawable.STATE_FOCUSED); + mHandleDrawable.setAlpha(0.0f); + } + } else { + switchToState(STATE_TRACKING, x, y); + mHandleDrawable.setX(x); + mHandleDrawable.setY(y); + mHandleDrawable.setAlpha(1.0f); + } + // Draw handle outside parent's bounds + invalidateGlobalRegion(mHandleDrawable); + + if (mActiveTarget != activeTarget && activeTarget != -1) { + vibrate(); + } + mActiveTarget = activeTarget; + } + + /** + * 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) { + mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState); + } + } + } + + @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; + + mWaveCenterX = mHorizontalOffset + Math.max(width, mOuterRing.getWidth() ) / 2; + mWaveCenterY = mVerticalOffset + Math.max(height, mOuterRing.getHeight()) / 2; + mHandleDrawable.setX(mWaveCenterX); + mHandleDrawable.setY(mWaveCenterY); + mOuterRing.setX(mWaveCenterX); + mOuterRing.setY(Math.max(mWaveCenterY, mWaveCenterY)); + mOuterRing.setAlpha(0.0f); + if (mOuterRadius == 0.0f) { + mOuterRadius = 0.5f*(float) Math.sqrt(dist2(mWaveCenterX, mWaveCenterY)); + } + if (mHitRadius == 0.0f) { + // Use the radius of inscribed circle of the first target. + mHitRadius = mTargetDrawables.get(0).getWidth() / 2.0f; + } + if (mSnapMargin == 0.0f) { + mSnapMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + SNAP_MARGIN_DEFAULT, getContext().getResources().getDisplayMetrics()); + } + for (int i = 0; i < mTargetDrawables.size(); i++) { + final TargetDrawable targetIcon = mTargetDrawables.get(i); + double angle = -2.0f * Math.PI * i / mTargetDrawables.size(); + float xPosition = mWaveCenterX + mOuterRadius * (float) Math.cos(angle); + float yPosition = mWaveCenterY + mOuterRadius * (float) Math.sin(angle); + targetIcon.setX(xPosition); + targetIcon.setY(yPosition); + targetIcon.setAlpha(0.0f); + } + hideChevrons(); + hideTargets(false); + if (DEBUG) dump(); + } + + private void hideChevrons() { + for (TargetDrawable chevron : mChevronDrawables) { + chevron.setAlpha(0.0f); + } + } + + @Override + protected void onDraw(Canvas canvas) { + mOuterRing.draw(canvas); + for (TargetDrawable target : mTargetDrawables) { + target.draw(canvas); + } + for (TargetDrawable target : mChevronDrawables) { + target.draw(canvas); + } + mHandleDrawable.draw(canvas); + } + + public void setOnTriggerListener(OnTriggerListener listener) { + mOnTriggerListener = listener; + } + + public void onAnimationUpdate(ValueAnimator animation) { + invalidateGlobalRegion(mHandleDrawable); + invalidate(); + } + + private float square(float d) { + return d * d; + } + + private float dist2(float dx, float dy) { + return dx*dx + dy*dy; + } + +}
\ No newline at end of file diff --git a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java new file mode 100644 index 0000000..d3baa2b --- /dev/null +++ b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java @@ -0,0 +1,215 @@ +/* + * 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.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.StateListDrawable; +import android.util.Log; + +public class TargetDrawable { + private static final String TAG = "TargetDrawable"; + public static final int[] STATE_ACTIVE = + { android.R.attr.state_enabled, android.R.attr.state_active }; + public static final int[] STATE_INACTIVE = + { android.R.attr.state_enabled, -android.R.attr.state_active }; + public static final int[] STATE_FOCUSED = + { android.R.attr.state_enabled, android.R.attr.state_focused }; + + private float mTranslationX = 0.0f; + private float mTranslationY = 0.0f; + private float mScaleX = 1.0f; + private float mScaleY = 1.0f; + private float mAlpha = 1.0f; + private Drawable mDrawable; + + /* package */ static class DrawableWithAlpha extends Drawable { + private float mAlpha = 1.0f; + private Drawable mRealDrawable; + public DrawableWithAlpha(Drawable realDrawable) { + mRealDrawable = realDrawable; + } + public void setAlpha(float alpha) { + mAlpha = alpha; + } + public float getAlpha() { + return mAlpha; + } + public void draw(Canvas canvas) { + mRealDrawable.setAlpha((int) Math.round(mAlpha * 255f)); + mRealDrawable.draw(canvas); + } + @Override + public void setAlpha(int alpha) { + mRealDrawable.setAlpha(alpha); + } + @Override + public void setColorFilter(ColorFilter cf) { + mRealDrawable.setColorFilter(cf); + } + @Override + public int getOpacity() { + return mRealDrawable.getOpacity(); + } + } + + public TargetDrawable(Resources res, int resId) { + this(res, resId == 0 ? null : res.getDrawable(resId)); + } + + public TargetDrawable(Resources res, Drawable drawable) { + // Mutate the drawable so we can animate shared drawable properties. + mDrawable = drawable != null ? drawable.mutate() : null; + resizeDrawables(); + setState(STATE_INACTIVE); + } + + public void setState(int [] state) { + if (mDrawable instanceof StateListDrawable) { + StateListDrawable d = (StateListDrawable) mDrawable; + d.setState(state); + } + } + + public boolean hasState(int [] state) { + if (mDrawable instanceof StateListDrawable) { + StateListDrawable d = (StateListDrawable) mDrawable; + // TODO: this doesn't seem to work + return d.getStateDrawableIndex(state) != -1; + } + return false; + } + + /** + * Returns true if the drawable is a StateListDrawable and is in the focused state. + * + * @return + */ + public boolean isActive() { + if (mDrawable instanceof StateListDrawable) { + StateListDrawable d = (StateListDrawable) mDrawable; + int[] states = d.getState(); + for (int i = 0; i < states.length; i++) { + if (states[i] == android.R.attr.state_focused) { + return true; + } + } + } + return false; + } + + /** + * Returns true if this target is enabled. Typically an enabled target contains a valid + * drawable in a valid state. Currently all targets with valid drawables are valid. + * + * @return + */ + public boolean isValid() { + return mDrawable != null; + } + + /** + * Makes drawables in a StateListDrawable all the same dimensions. + * If not a StateListDrawable, then justs sets the bounds to the intrinsic size of the + * drawable. + */ + private void resizeDrawables() { + if (mDrawable instanceof StateListDrawable) { + StateListDrawable d = (StateListDrawable) mDrawable; + int maxWidth = 0; + int maxHeight = 0; + for (int i = 0; i < d.getStateCount(); i++) { + Drawable childDrawable = d.getStateDrawable(i); + maxWidth = Math.max(maxWidth, childDrawable.getIntrinsicWidth()); + maxHeight = Math.max(maxHeight, childDrawable.getIntrinsicHeight()); + } + Log.v(TAG, "union of childDrawable rects " + d + " to: " + maxWidth + "x" + maxHeight); + d.setBounds(0, 0, maxWidth, maxHeight); + for (int i = 0; i < d.getStateCount(); i++) { + Drawable childDrawable = d.getStateDrawable(i); + Log.v(TAG, "sizing drawable " + childDrawable + " to: " + maxWidth + "x" + maxHeight); + childDrawable.setBounds(0, 0, maxWidth, maxHeight); + } + } else if (mDrawable != null) { + mDrawable.setBounds(0, 0, + mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()); + } + } + + public void setX(float x) { + mTranslationX = x; + } + + public void setY(float y) { + mTranslationY = y; + } + + public void setScaleX(float x) { + mScaleX = x; + } + + public void setScaleY(float y) { + mScaleY = y; + } + + public void setAlpha(float alpha) { + mAlpha = alpha; + } + + public float getX() { + return mTranslationX; + } + + public float getY() { + return mTranslationY; + } + + public float getScaleX() { + return mScaleX; + } + + public float getScaleY() { + return mScaleY; + } + + public float getAlpha() { + return mAlpha; + } + + public int getWidth() { + return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0; + } + + public int getHeight() { + return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0; + } + + public void draw(Canvas canvas) { + if (mDrawable == null) { + return; + } + canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.translate(mTranslationX, mTranslationY); + canvas.scale(mScaleX, mScaleY); + canvas.translate(-0.5f * getWidth(), -0.5f * getHeight()); + mDrawable.setAlpha((int) Math.round(mAlpha * 255f)); + mDrawable.draw(canvas); + canvas.restore(); + } +} diff --git a/core/java/com/android/internal/widget/multiwaveview/Tweener.java b/core/java/com/android/internal/widget/multiwaveview/Tweener.java new file mode 100644 index 0000000..c2746d9 --- /dev/null +++ b/core/java/com/android/internal/widget/multiwaveview/Tweener.java @@ -0,0 +1,132 @@ +/* + * 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 java.util.ArrayList; +import java.util.HashMap; + +import android.animation.Animator.AnimatorListener; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator.AnimatorUpdateListener; + +class Tweener { + private static final String TAG = "Tweener"; + + private Object object; + ObjectAnimator animator; + private static HashMap<Object, Tweener> sTweens = new HashMap<Object, Tweener>(); + + public Tweener(Object obj, ObjectAnimator anim) { + object = obj; + animator = anim; + } + + public static Tweener to(Object object, long duration, Object... vars) { + long delay = 0; + AnimatorUpdateListener updateListener = null; + AnimatorListener listener = null; + TimeInterpolator interpolator = null; + + // Iterate through arguments and discover properties to animate + ArrayList<PropertyValuesHolder> props = new ArrayList<PropertyValuesHolder>(vars.length/2); + for (int i = 0; i < vars.length; i+=2) { + if (!(vars[i] instanceof String)) { + throw new IllegalArgumentException("Key must be a string: " + vars[i]); + } + String key = (String) vars[i]; + Object value = vars[i+1]; + if ("simultaneousTween".equals(key)) { + // TODO + } else if ("ease".equals(key)) { + interpolator = (TimeInterpolator) value; // TODO: multiple interpolators? + } else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) { + updateListener = (AnimatorUpdateListener) value; + } else if ("onComplete".equals(key) || "onCompleteListener".equals(key)) { + listener = (AnimatorListener) value; + } else if ("delay".equals(key)) { + delay = ((Number) value).longValue(); + } else if ("syncWith".equals(key)) { + // TODO + } else if (value instanceof Number[]) { + // TODO: support Tween.from() + } else if (value instanceof Number) { + float floatValue = ((Number)value).floatValue(); + props.add(PropertyValuesHolder.ofFloat(key, floatValue)); + } else { + throw new IllegalArgumentException( + "Bad argument for key \"" + key + "with value" + value); + } + } + + // Re-use existing tween, if present + Tweener tween = sTweens.get(object); + if (tween == null) { + ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(object, + props.toArray(new PropertyValuesHolder[props.size()])); + tween = new Tweener(object, anim); + sTweens.put(object, tween); + } else { + tween.animator.cancel(); + replace(props, object); + } + + if (interpolator != null) { + tween.animator.setInterpolator(interpolator); + } + + // Update animation with properties discovered in loop above + tween.animator.setStartDelay(delay); + tween.animator.setDuration(duration); + if (updateListener != null) { + tween.animator.removeAllUpdateListeners(); // There should be only one + tween.animator.addUpdateListener(updateListener); + } + if (listener != null) { + tween.animator.removeAllListeners(); // There should be only one. + tween.animator.addListener(listener); + } + tween.animator.start(); + + return tween; + } + + Tweener from(Object object, long duration, Object... vars) { + // TODO: for v of vars + // toVars[v] = object[v] + // object[v] = vars[v] + return Tweener.to(object, duration, vars); + } + + static void replace(ArrayList<PropertyValuesHolder> props, Object... args) { + for (final Object killobject : args) { + Tweener tween = sTweens.get(killobject); + if (tween != null) { + if (killobject == tween.object) { + tween.animator.cancel(); + if (props != null) { + tween.animator.setValues( + props.toArray(new PropertyValuesHolder[props.size()])); + } else { + sTweens.remove(tween); + } + } + } + } + } +} diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png Binary files differnew file mode 100644 index 0000000..8089912 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png Binary files differnew file mode 100644 index 0000000..e4ba8fd --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png Binary files differnew file mode 100644 index 0000000..c9197c8 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png Binary files differnew file mode 100644 index 0000000..d008afa --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png Binary files differnew file mode 100644 index 0000000..e508900 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png Binary files differnew file mode 100644 index 0000000..9866769 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png Binary files differnew file mode 100644 index 0000000..f5dfacc --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png Binary files differnew file mode 100644 index 0000000..b4d399d --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png Binary files differnew file mode 100644 index 0000000..e21a87c --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png Binary files differnew file mode 100644 index 0000000..3283f99 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png Binary files differnew file mode 100644 index 0000000..732133c --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png Binary files differnew file mode 100644 index 0000000..0bbf62f --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png Binary files differnew file mode 100644 index 0000000..5294bc5 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png Binary files differnew file mode 100644 index 0000000..fce4980 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png Binary files differnew file mode 100644 index 0000000..ecafbea --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png Binary files differnew file mode 100644 index 0000000..1f527b7 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png Binary files differnew file mode 100644 index 0000000..73f01c9 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png Binary files differnew file mode 100644 index 0000000..d4e558d --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png Binary files differnew file mode 100644 index 0000000..5d999a6 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png Binary files differnew file mode 100644 index 0000000..d01bdb2 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png Binary files differnew file mode 100644 index 0000000..72b8f0a --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png Binary files differnew file mode 100644 index 0000000..bf73a26 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png Binary files differnew file mode 100644 index 0000000..d333946 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png Binary files differnew file mode 100644 index 0000000..e053222 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png Binary files differnew file mode 100644 index 0000000..7db46c1 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png Binary files differnew file mode 100644 index 0000000..0ad03c0 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png Binary files differnew file mode 100644 index 0000000..f46e8bd --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png Binary files differnew file mode 100644 index 0000000..ddeeb18 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png Binary files differnew file mode 100644 index 0000000..e5ef113 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png Binary files differnew file mode 100644 index 0000000..ab723b7 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png Binary files differnew file mode 100644 index 0000000..d1aae18 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png Binary files differnew file mode 100644 index 0000000..b52c844 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png Binary files differnew file mode 100644 index 0000000..722027e --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png Binary files differnew file mode 100644 index 0000000..c10344f --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png Binary files differnew file mode 100644 index 0000000..08c6cfe --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png Binary files differnew file mode 100644 index 0000000..30eb974 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png Binary files differnew file mode 100644 index 0000000..aab2f6b --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png Binary files differnew file mode 100644 index 0000000..4151f73 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png Binary files differnew file mode 100644 index 0000000..3b2f3fc --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png Binary files differnew file mode 100644 index 0000000..6a5af9d --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png Binary files differnew file mode 100644 index 0000000..c288ce4 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png Binary files differnew file mode 100644 index 0000000..03f524d --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png Binary files differnew file mode 100644 index 0000000..db59b5f --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png Binary files differnew file mode 100644 index 0000000..eb6ceed --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png Binary files differnew file mode 100644 index 0000000..dbfc5ba --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png Binary files differnew file mode 100644 index 0000000..1de7586 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png Binary files differnew file mode 100644 index 0000000..e007322 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png Binary files differnew file mode 100644 index 0000000..df47993 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png Binary files differnew file mode 100644 index 0000000..6f51447 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png Binary files differnew file mode 100644 index 0000000..dd255f5 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png Binary files differnew file mode 100644 index 0000000..8edf62d --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png Binary files differnew file mode 100644 index 0000000..2a47e9b --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png Binary files differnew file mode 100644 index 0000000..f049dc9 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png Binary files differnew file mode 100644 index 0000000..75173cb --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png Binary files differnew file mode 100644 index 0000000..9f6da72 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png Binary files differnew file mode 100644 index 0000000..4244ca0 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png Binary files differnew file mode 100644 index 0000000..a98a379 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png Binary files differnew file mode 100644 index 0000000..fa2a0f4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png Binary files differnew file mode 100644 index 0000000..c44a330 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png Binary files differnew file mode 100644 index 0000000..2264dc3 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png Binary files differnew file mode 100644 index 0000000..0b4b260 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png Binary files differnew file mode 100644 index 0000000..fd81211 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png Binary files differnew file mode 100644 index 0000000..5a93472 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png Binary files differnew file mode 100644 index 0000000..73f6a2e --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png Binary files differnew file mode 100644 index 0000000..9edc70b --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png Binary files differnew file mode 100644 index 0000000..0485af0 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png Binary files differnew file mode 100644 index 0000000..6af5375 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png Binary files differnew file mode 100644 index 0000000..29c4572 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png Binary files differnew file mode 100644 index 0000000..42c8ad2 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png Binary files differnew file mode 100644 index 0000000..ff65f20 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png Binary files differnew file mode 100644 index 0000000..fa0be96 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png Binary files differnew file mode 100644 index 0000000..d067ab8 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png Binary files differnew file mode 100644 index 0000000..1a53c63 --- /dev/null +++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png diff --git a/core/res/res/drawable/ic_lockscreen_answer.xml b/core/res/res/drawable/ic_lockscreen_answer.xml new file mode 100644 index 0000000..b42fc2a --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_answer.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_answer_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_answer_active" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_decline.xml b/core/res/res/drawable/ic_lockscreen_decline.xml new file mode 100644 index 0000000..65128a1 --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_decline.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_decline_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_decline_activated" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_handle.xml b/core/res/res/drawable/ic_lockscreen_handle.xml new file mode 100644 index 0000000..e7b4a6e --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_handle.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_handle_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_handle_pressed" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_send_sms.xml b/core/res/res/drawable/ic_lockscreen_send_sms.xml new file mode 100644 index 0000000..2503a5c --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_send_sms.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_text_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_text_activated" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_silent.xml b/core/res/res/drawable/ic_lockscreen_silent.xml new file mode 100644 index 0000000..2521eb7 --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_silent.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_silent_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_silent_activated" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_soundon.xml b/core/res/res/drawable/ic_lockscreen_soundon.xml new file mode 100644 index 0000000..2b306a5 --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_soundon.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_soundon_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_soundon_activated" /> + +</selector> diff --git a/core/res/res/drawable/ic_lockscreen_unlock.xml b/core/res/res/drawable/ic_lockscreen_unlock.xml new file mode 100644 index 0000000..0a49c18 --- /dev/null +++ b/core/res/res/drawable/ic_lockscreen_unlock.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item + android:state_enabled="true" + android:state_active="false" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_unlock_normal" /> + + <item + android:state_enabled="true" + android:state_active="true" + android:state_focused="false" + android:drawable="@drawable/ic_lockscreen_unlock_activated" /> + +</selector> diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml index c9c1692..543747f 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml @@ -59,7 +59,7 @@ /> <com.android.internal.widget.WaveView - android:id="@+id/wave_view" + android:id="@+id/unlock_widget" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml index 3bb7821..c83f910 100644 --- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml +++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml @@ -50,7 +50,8 @@ android:layout_width="0dip" android:gravity="center_horizontal|center_vertical"> - <TextView android:id="@+id/screenLocked" + <com.android.internal.widget.WaveView + android:id="@+id/unlock_widget" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml index 5fe38d5..24891dc 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml @@ -22,11 +22,11 @@ depending on the state of the device. It is the same for landscape and portrait.--> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" - android:id="@+id/root"> + android:id="@+id/root" + android:clipChildren="false"> <TextView android:id="@+id/carrier" @@ -162,13 +162,25 @@ android:drawablePadding="4dip" /> - <com.android.internal.widget.SlidingTab - android:id="@+id/tab_selector" + <com.android.internal.widget.multiwaveview.MultiWaveView + android:id="@+id/unlock_widget" android:orientation="horizontal" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="300dip" android:layout_alignParentBottom="true" - android:layout_marginBottom="80dip" + + android:targetDrawables="@array/lockscreen_targets_when_silent" + android:handleDrawable="@drawable/ic_lockscreen_handle" + android:waveDrawable="@drawable/ic_lockscreen_outerring" + android:outerRadius="@*android:dimen/multiwaveview_target_placement_radius" + android:snapMargin="@*android:dimen/multiwaveview_snap_margin" + android:hitRadius="@*android:dimen/multiwaveview_hit_radius" + android:vibrationDuration="20" + android:leftChevronDrawable="@drawable/ic_lockscreen_chevron_left" + android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right" + android:feedbackCount="3" + android:horizontalOffset="0dip" + android:verticalOffset="60dip" /> <!-- emergency call button shown when sim is PUKd and tab_selector is diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml index 3c2ad9a..02994a9 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml @@ -21,11 +21,11 @@ state of the device, as well as instructions on how to get past it depending on the state of the device.--> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" - android:id="@+id/root"> + android:id="@+id/root" + android:clipChildren="false"> <!-- left side --> <RelativeLayout @@ -164,12 +164,23 @@ </RelativeLayout> <!-- right side --> - <com.android.internal.widget.SlidingTab - android:id="@+id/tab_selector" - android:orientation="vertical" - android:layout_width="wrap_content" + <com.android.internal.widget.multiwaveview.MultiWaveView + android:id="@+id/unlock_widget" + android:layout_width="300dip" android:layout_height="match_parent" - android:layout_marginRight="80dip" + + android:targetDrawables="@array/lockscreen_targets_when_silent" + android:handleDrawable="@drawable/ic_lockscreen_handle" + android:waveDrawable="@drawable/ic_lockscreen_outerring" + android:outerRadius="@*android:dimen/multiwaveview_target_placement_radius" + android:snapMargin="@*android:dimen/multiwaveview_snap_margin" + android:hitRadius="@*android:dimen/multiwaveview_hit_radius" + android:vibrationDuration="20" + android:leftChevronDrawable="@drawable/ic_lockscreen_chevron_left" + android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right" + android:feedbackCount="3" + android:horizontalOffset="60dip" + android:verticalOffset="0dip" /> <!-- emergency call button shown when sim is PUKd and tab_selector is diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml new file mode 100644 index 0000000..85130ba --- /dev/null +++ b/core/res/res/values-land/arrays.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/colors.xml +** +** Copyright 2006, 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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Resources for MultiWaveView in LockScreen --> + <array name="ic_lockscreen_targets_when_silent"> + <item>@null</item>" + <item>@drawable/ic_lockscreen_unlock</item> + <item>@null</item> + <item>@drawable/ic_lockscreen_soundon</item> + </array> + + <array name="ic_lockscreen_targets_when_soundon"> + <item>@null</item>" + <item>@drawable/ic_lockscreen_unlock</item> + <item>@null</item> + <item>@drawable/ic_lockscreen_silent</item> + </array> + +</resources> diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml index 810c3b2..0f04a67 100644 --- a/core/res/res/values/arrays.xml +++ b/core/res/res/values/arrays.xml @@ -333,4 +333,19 @@ <item>中文 (繁體)</item> </string-array> + <!-- Resources for MultiWaveView in LockScreen --> + <array name="lockscreen_targets_when_silent"> + <item>@drawable/ic_lockscreen_unlock</item> + <item>@null</item> + <item>@drawable/ic_lockscreen_soundon</item> + <item>@null</item> + </array> + + <array name="lockscreen_targets_when_soundon"> + <item>@drawable/ic_lockscreen_unlock</item> + <item>@null</item> + <item>@drawable/ic_lockscreen_silent</item> + <item>@null</item>" + </array> + </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index d5da592..acfdfc9 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -5009,6 +5009,48 @@ </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"/> + + <!-- Sets a drawable as the drag center. --> + <attr name="handleDrawable" format="reference" /> + + <!-- Drawable to use for chevron animation on the left. --> + <attr name="leftChevronDrawable" format="reference" /> + + <!-- Drawable to use for chevron animation on the right. --> + <attr name="rightChevronDrawable" 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" /> + + <!-- Size of target radius. Points within this distance of target center is a "hit". --> + <attr name="hitRadius" 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 to shift center of pattern vertically. --> + <attr name="verticalOffset" format="dimension" /> + + <!-- Used to shift center of pattern horizontally. --> + <attr name="horizontalOffset" format="dimension" /> + </declare-styleable> + + <!-- =============================== --> <!-- LockPatternView class attributes --> <!-- =============================== --> <eat-comment /> @@ -5145,7 +5187,7 @@ </declare-styleable> <declare-styleable name="Storage"> - <!-- path to mount point for the storage --> + <!-- path to mount point for the storage --> <attr name="mountPoint" format="string" /> <!-- user visible description of the storage --> <attr name="storageDescription" format="string" /> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 724c528..df22f15 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -57,6 +57,15 @@ <!-- Default correction for the space key in the password keyboard --> <dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen> + <!-- Default target placement radius for MultiWaveView --> + <dimen name="multiwaveview_target_placement_radius">135dip</dimen> + + <!-- Default distance beyond which MultiWaveView snaps to the target radius --> + <dimen name="multiwaveview_snap_margin">20dip</dimen> + + <!-- Default distance from each snap target that MultiWaveView considers a "hit" --> + <dimen name="multiwaveview_hit_radius">60dip</dimen> + <!-- Preference activity side margins --> <dimen name="preference_screen_side_margin">0dp</dimen> <!-- Preference activity side margins negative--> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 82a3b8a..4108c1b 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1752,4 +1752,17 @@ <public type="attr" name="accessibilityFlags" /> <public type="attr" name="canRetrieveWindowContent" /> + <public type="attr" name="targetDrawables" /> + <public type="attr" name="handleDrawable" /> + <public type="attr" name="leftChevronDrawable" /> + <public type="attr" name="rightChevronDrawable" /> + <public type="attr" name="waveDrawable" /> + <public type="attr" name="outerRadius" /> + <public type="attr" name="hitRadius" /> + <public type="attr" name="vibrationDuration" /> + <public type="attr" name="snapMargin" /> + <public type="attr" name="feedbackCount" /> + <public type="attr" name="verticalOffset" /> + <public type="attr" name="horizontalOffset" /> + </resources> diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java index 6f7a6ee..0178395 100644 --- a/policy/src/com/android/internal/policy/impl/LockScreen.java +++ b/policy/src/com/android/internal/policy/impl/LockScreen.java @@ -22,6 +22,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.SlidingTab; import com.android.internal.widget.WaveView; import com.android.internal.widget.WaveView.OnTriggerListener; +import com.android.internal.widget.multiwaveview.MultiWaveView; import android.app.ActivityManager; import android.content.Context; @@ -91,6 +92,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, private WaveView mEnergyWave; private SlidingTabMethods mSlidingTabMethods; private WaveViewMethods mWaveViewMethods; + private MultiWaveView mMultiWaveView; + private MultiWaveViewMethods mMultiWaveViewMethods; /** * The status of this lock screen. @@ -166,34 +169,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) { mCallback.goToUnlockScreen(); } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { - // toggle silent mode - mSilentMode = !mSilentMode; - if (mSilentMode) { - final boolean vibe = (Settings.System.getInt( - getContext().getContentResolver(), - Settings.System.VIBRATE_IN_SILENT, 1) == 1); - - mAudioManager.setRingerMode(vibe - ? AudioManager.RINGER_MODE_VIBRATE - : AudioManager.RINGER_MODE_SILENT); - } else { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); - } - + toggleRingMode(); updateRightTabResources(); - - String message = mSilentMode ? - getContext().getString(R.string.global_action_silent_mode_on_status) : - getContext().getString(R.string.global_action_silent_mode_off_status); - - final int toastIcon = mSilentMode - ? R.drawable.ic_lock_ringer_off - : R.drawable.ic_lock_ringer_on; - - final int toastColor = mSilentMode - ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff) - : getContext().getResources().getColor(R.color.keyguard_text_color_soundon); - toastMessage(mScreenLocked, message, toastColor, toastIcon); + doSilenceRingToast(); mCallback.pokeWakelock(); } } @@ -214,19 +192,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen, } } - class WaveViewMethods implements WaveView.OnTriggerListener { - private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0; - private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000; + private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0; + private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000; + class WaveViewMethods implements WaveView.OnTriggerListener { /** {@inheritDoc} */ public void onTrigger(View v, int whichHandle) { if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) { - // Delay hiding lock screen long enough for animation to finish - postDelayed(new Runnable() { - public void run() { - mCallback.goToUnlockScreen(); - } - }, WAIT_FOR_ANIMATION_TIMEOUT); + requestUnlockScreen(); } } @@ -243,6 +216,80 @@ class LockScreen extends LinearLayout implements KeyguardScreen, } } + class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener { + public void onGrabbed(View v, int handle) { + + } + public void onReleased(View v, int handle) { + + } + public void onTrigger(View v, int target) { + if (target == 0) { // TODO: Use resources to determine which handle was used + mCallback.goToUnlockScreen(); + } else if (target == 2) { + toggleRingMode(); + updateResources(); + doSilenceRingToast(); + mCallback.pokeWakelock(); + } + + } + + private void updateResources() { + mMultiWaveView.setTargetResources(mSilentMode ? R.array.lockscreen_targets_when_silent + : R.array.lockscreen_targets_when_soundon); + } + + public void onGrabbedStateChange(View v, int handle) { + // Don't poke the wake lock when returning to a state where the handle is + // not grabbed since that can happen when the system (instead of the user) + // cancels the grab. + if (handle != MultiWaveView.OnTriggerListener.NO_HANDLE) { + mCallback.pokeWakelock(); + } + } + } + + private void requestUnlockScreen() { + // Delay hiding lock screen long enough for animation to finish + postDelayed(new Runnable() { + public void run() { + mCallback.goToUnlockScreen(); + } + }, WAIT_FOR_ANIMATION_TIMEOUT); + } + + private void doSilenceRingToast() { + String message = mSilentMode ? + getContext().getString(R.string.global_action_silent_mode_on_status) : + getContext().getString(R.string.global_action_silent_mode_off_status); + + final int toastIcon = mSilentMode + ? R.drawable.ic_lock_ringer_off + : R.drawable.ic_lock_ringer_on; + + final int toastColor = mSilentMode + ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff) + : getContext().getResources().getColor(R.color.keyguard_text_color_soundon); + toastMessage(mScreenLocked, message, toastColor, toastIcon); + } + + private void toggleRingMode() { + // toggle silent mode + mSilentMode = !mSilentMode; + if (mSilentMode) { + final boolean vibe = (Settings.System.getInt( + getContext().getContentResolver(), + Settings.System.VIBRATE_IN_SILENT, 1) == 1); + + mAudioManager.setRingerMode(vibe + ? AudioManager.RINGER_MODE_VIBRATE + : AudioManager.RINGER_MODE_SILENT); + } else { + mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); + } + } + /** * In general, we enable unlocking the insecure key guard with the menu key. However, there are * some cases where we wish to disable it, notably when the menu button placement or technology @@ -319,9 +366,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mSilentMode = isSilentMode(); - mSlidingTab = (SlidingTab) findViewById(R.id.tab_selector); - mEnergyWave = (WaveView) findViewById(R.id.wave_view); - if (mSlidingTab != null) { + View unlockWidget = findViewById(R.id.unlock_widget); + if (unlockWidget instanceof SlidingTab) { + mSlidingTab = (SlidingTab) unlockWidget; mSlidingTab.setHoldAfterTrigger(true, false); mSlidingTab.setLeftHintText(R.string.lockscreen_unlock_label); mSlidingTab.setLeftTabResources( @@ -332,11 +379,17 @@ class LockScreen extends LinearLayout implements KeyguardScreen, mSlidingTabMethods = new SlidingTabMethods(); mSlidingTab.setOnTriggerListener(mSlidingTabMethods); mSlidingTabMethods.updateRightTabResources(); - } else if (mEnergyWave != null) { + } else if (unlockWidget instanceof WaveView) { + mEnergyWave = (WaveView) unlockWidget; mWaveViewMethods = new WaveViewMethods(); mEnergyWave.setOnTriggerListener(mWaveViewMethods); + } else if (unlockWidget instanceof MultiWaveView) { + mMultiWaveView = (MultiWaveView) unlockWidget; + mMultiWaveViewMethods = new MultiWaveViewMethods(); + mMultiWaveViewMethods.updateResources(); // update silence/ring resources + mMultiWaveView.setOnTriggerListener(mMultiWaveViewMethods); } else { - throw new IllegalStateException("Must have either SlidingTab or WaveView defined"); + throw new IllegalStateException("Unrecognized unlock widget: " + unlockWidget); } resetStatusInfo(updateMonitor); |