Merge "Fix 6398209: Improve MultiWaveView animations and interaction" into jb-dev

This commit is contained in:
Jim Miller
2012-05-10 16:41:55 -07:00
committed by Android (Google) Code Review
12 changed files with 281 additions and 134 deletions

View File

@@ -69,16 +69,19 @@ public class MultiWaveView extends View {
public void onGrabbedStateChange(View v, int handle);
}
// Tune-able parameters
// 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 = 300;
private static final int HIDE_ANIMATION_DELAY = 200;
private static final int HIDE_ANIMATION_DURATION = RETURN_TO_HOME_DELAY;
private static final int SHOW_ANIMATION_DURATION = 0;
private static final int HIDE_ANIMATION_DURATION = 200;
private static final int SHOW_ANIMATION_DURATION = 200;
private static final int SHOW_ANIMATION_DELAY = 0;
private static final float TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.3f;
private static final long RING_EXPAND_DURATION = 200;
private static final float TARGET_INITIAL_POSITION_SCALE = 0.8f;
private TimeInterpolator mChevronAnimationInterpolator = Ease.Quad.easeOut;
private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>();
@@ -149,6 +152,7 @@ public class MultiWaveView extends View {
private int mHorizontalInset;
private int mVerticalInset;
private int mGravity = Gravity.TOP;
private boolean mInitialLayout = true;
public MultiWaveView(Context context) {
this(context, null);
@@ -274,7 +278,7 @@ public class MultiWaveView extends View {
final int minimumHeight = getSuggestedMinimumHeight();
int computedWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
int computedHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
setupGravity((computedWidth - minimumWidth), (computedHeight - minimumHeight));
computeInsets((computedWidth - minimumWidth), (computedHeight - minimumHeight));
setMeasuredDimension(computedWidth, computedHeight);
}
@@ -315,17 +319,17 @@ public class MultiWaveView extends View {
*/
private void startChevronAnimation() {
final float r = mHandleDrawable.getWidth() * 0.4f;
final float chevronAnimationDistance = mOuterRadius * 0.9f;
final float chevronAnimationDistance = mOuterRadius * 0.9f / 2.0f;
final float from[][] = {
{mWaveCenterX - r, mWaveCenterY}, // left
{mWaveCenterX + r, mWaveCenterY}, // right
{mWaveCenterX, mWaveCenterY - r}, // top
{mWaveCenterX, mWaveCenterY + r} }; // bottom
{ -r, 0}, // left
{ +r, 0}, // right
{0, -r}, // top
{0, +r} }; // bottom
final float to[][] = {
{mWaveCenterX - chevronAnimationDistance, mWaveCenterY}, // left
{mWaveCenterX + chevronAnimationDistance, mWaveCenterY}, // right
{mWaveCenterX, mWaveCenterY - chevronAnimationDistance}, // top
{mWaveCenterX, mWaveCenterY + chevronAnimationDistance} }; // bottom
{ -chevronAnimationDistance, 0}, // left
{ chevronAnimationDistance, 0}, // right
{ 0, -chevronAnimationDistance}, // top
{ 0, +chevronAnimationDistance} }; // bottom
mChevronAnimations.clear();
final float startScale = 0.5f;
@@ -416,32 +420,25 @@ public class MultiWaveView extends View {
mHandleDrawable.setAlpha(targetHit ? 0.0f : 1.0f);
if (targetHit) {
mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE);
hideUnselected(activeTarget);
// Inform listener of any active targets. Typically only one will be active.
if (DEBUG) Log.v(TAG, "Finish with target hit = " + targetHit);
dispatchTriggerEvent(mActiveTarget);
mHandleAnimation = Tweener.to(mHandleDrawable, 0,
"ease", Ease.Quart.easeOut,
"delay", RETURN_TO_HOME_DELAY,
"alpha", 1.0f,
"x", mWaveCenterX,
"y", mWaveCenterY,
"onUpdate", mUpdateListener,
"onComplete", mResetListener);
} else {
// Animate finger outline back to home position
mHandleAnimation = Tweener.to(mHandleDrawable, RETURN_TO_HOME_DURATION,
"ease", Ease.Quart.easeOut,
"delay", 0,
"alpha", 1.0f,
"x", mWaveCenterX,
"y", mWaveCenterY,
"onUpdate", mUpdateListener,
"onComplete", mDragging ? mResetListenerWithPing : mResetListener);
}
// Animate handle back to the center based on current state.
int delay = targetHit ? RETURN_TO_HOME_DELAY : 0;
int duration = targetHit ? 0 : RETURN_TO_HOME_DURATION;
mHandleAnimation = Tweener.to(mHandleDrawable, duration,
"ease", Ease.Quart.easeOut,
"delay", delay,
"alpha", 1.0f,
"x", 0,
"y", 0,
"onUpdate", mUpdateListener,
"onComplete", (mDragging && !targetHit) ? mResetListenerWithPing : mResetListener);
setGrabbedState(OnTriggerListener.NO_HANDLE);
}
@@ -461,27 +458,30 @@ public class MultiWaveView extends View {
// 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;
if (animate) {
final int duration = animate ? HIDE_ANIMATION_DURATION : 0;
for (TargetDrawable target : mTargetDrawables) {
target.setState(TargetDrawable.STATE_INACTIVE);
mTargetAnimations.add(Tweener.to(target, duration,
"alpha", 0.0f,
"delay", HIDE_ANIMATION_DELAY,
"onUpdate", mUpdateListener));
}
mTargetAnimations.add(Tweener.to(mOuterRing, duration,
final int duration = animate ? HIDE_ANIMATION_DURATION : 0;
final int delay = animate ? HIDE_ANIMATION_DELAY : 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", 0.0f,
"delay", HIDE_ANIMATION_DELAY,
"onUpdate", mUpdateListener,
"onComplete", mTargetUpdateListener));
} else {
for (TargetDrawable target : mTargetDrawables) {
target.setState(TargetDrawable.STATE_INACTIVE);
target.setAlpha(0.0f);
}
mOuterRing.setAlpha(0.0f);
"scaleX", TARGET_INITIAL_POSITION_SCALE,
"scaleY", TARGET_INITIAL_POSITION_SCALE,
"delay", delay,
"onUpdate", mUpdateListener));
}
float ringScaleTarget = mActiveTarget != -1 ? 1.5f : 0.5f;
mTargetAnimations.add(Tweener.to(mOuterRing, duration,
"ease", Ease.Cubic.easeOut,
"alpha", 0.0f,
"scaleX", ringScaleTarget,
"scaleY", ringScaleTarget,
"delay", delay,
"onUpdate", mUpdateListener,
"onComplete", mTargetUpdateListener));
}
private void showTargets(boolean animate) {
@@ -489,26 +489,31 @@ public class MultiWaveView extends View {
stopTargetAnimation();
}
mAnimatingTargets = animate;
if (animate) {
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", mUpdateListener));
}
mTargetAnimations.add(Tweener.to(mOuterRing, SHOW_ANIMATION_DURATION,
final int delay = animate ? SHOW_ANIMATION_DELAY : 0;
final int length = mTargetDrawables.size();
for (int i = 0; i < length; i++) {
TargetDrawable target = mTargetDrawables.get(i);
target.setState(TargetDrawable.STATE_INACTIVE);
target.setScaleX(TARGET_INITIAL_POSITION_SCALE);
target.setScaleY(TARGET_INITIAL_POSITION_SCALE);
mTargetAnimations.add(Tweener.to(target, animate ? SHOW_ANIMATION_DURATION : 0,
"ease", Ease.Cubic.easeOut,
"alpha", 1.0f,
"delay", SHOW_ANIMATION_DELAY,
"onUpdate", mUpdateListener,
"onComplete", mTargetUpdateListener));
} else {
for (TargetDrawable target : mTargetDrawables) {
target.setState(TargetDrawable.STATE_INACTIVE);
target.setAlpha(1.0f);
}
mOuterRing.setAlpha(1.0f);
"scaleX", 1.0f,
"scaleY", 1.0f,
"delay", delay,
"onUpdate", mUpdateListener));
}
mOuterRing.setScaleX(0.5f);
mOuterRing.setScaleY(0.5f);
mTargetAnimations.add(Tweener.to(mOuterRing, animate ? RING_EXPAND_DURATION : 0,
"ease", Ease.Cubic.easeOut,
"alpha", 1.0f,
"scaleX", 1.0f,
"scaleY", 1.0f,
"delay", delay,
"onUpdate", mUpdateListener,
"onComplete", mTargetUpdateListener));
}
private void stopTargetAnimation() {
@@ -545,7 +550,8 @@ public class MultiWaveView extends View {
mMaxTargetHeight = maxHeight;
requestLayout(); // required to resize layout and call updateTargetPositions()
} else {
updateTargetPositions();
updateTargetPositions(mWaveCenterX, mWaveCenterY);
updateChevronPositions(mWaveCenterX, mWaveCenterY);
}
array.recycle();
}
@@ -645,8 +651,8 @@ public class MultiWaveView extends View {
stopTargetAnimation();
hideChevrons();
hideTargets(animate);
mHandleDrawable.setX(mWaveCenterX);
mHandleDrawable.setY(mWaveCenterY);
mHandleDrawable.setX(0);
mHandleDrawable.setY(0);
mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
Tweener.reset();
}
@@ -677,7 +683,7 @@ public class MultiWaveView extends View {
case MotionEvent.ACTION_CANCEL:
if (DEBUG) Log.v(TAG, "*** CANCEL ***");
// handleMove(event);
handleMove(event);
handleCancel(event);
handled = true;
break;
@@ -687,7 +693,6 @@ public class MultiWaveView extends View {
}
private void moveHandleTo(float x, float y, boolean animate) {
// TODO: animate the handle based on the current state/position
mHandleDrawable.setX(x);
mHandleDrawable.setY(y);
}
@@ -707,7 +712,14 @@ public class MultiWaveView extends View {
private void handleCancel(MotionEvent event) {
if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL");
mActiveTarget = -1; // Drop the active target if canceled.
// 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());
}
@@ -719,24 +731,25 @@ public class MultiWaveView extends View {
int activeTarget = -1;
final int historySize = event.getHistorySize();
final boolean singleTarget = mTargetDrawables.size() == 1;
float x = 0.0f;
float y = 0.0f;
for (int k = 0; k < historySize + 1; k++) {
float x = k < historySize ? event.getHistoricalX(k) : event.getX();
float y = k < historySize ? event.getHistoricalY(k) : event.getY();
float tx = x - mWaveCenterX;
float ty = y - mWaveCenterY;
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 = mWaveCenterX + tx * scale;
float limitY = mWaveCenterY + ty * scale;
float limitX = tx * scale;
float limitY = ty * scale;
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.
@@ -753,34 +766,47 @@ public class MultiWaveView extends View {
best = dist2;
}
}
x = limitX;
y = limitY;
}
if (activeTarget != -1) {
switchToState(STATE_SNAP, x,y);
float newX = singleTarget ? limitX : mTargetDrawables.get(activeTarget).getX();
float newY = singleTarget ? limitY : mTargetDrawables.get(activeTarget).getY();
moveHandleTo(newX, newY, false);
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);
moveHandleTo(x, y, false);
mHandleDrawable.setAlpha(1.0f);
}
x = limitX;
y = limitY;
}
if (activeTarget != -1) {
switchToState(STATE_SNAP, x,y);
TargetDrawable target = mTargetDrawables.get(activeTarget);
float newX = singleTarget ? x : target.getX();
float newY = singleTarget ? y : target.getY();
moveHandleTo(newX, newY, false);
} else {
switchToState(STATE_TRACKING, x, y);
moveHandleTo(x, y, false);
mHandleDrawable.setAlpha(1.0f);
}
// Draw handle outside parent's bounds
invalidateGlobalRegion(mHandleDrawable);
if (mActiveTarget != activeTarget && activeTarget != -1) {
dispatchGrabbedEvent(activeTarget);
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
String targetContentDescription = getTargetDescription(activeTarget);
announceText(targetContentDescription);
if (mActiveTarget != activeTarget) {
// Defocus the old target
if (mActiveTarget != -1) {
TargetDrawable target = mTargetDrawables.get(mActiveTarget);
if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
target.setState(TargetDrawable.STATE_INACTIVE);
mHandleDrawable.setAlpha(1.0f);
}
}
// Focus the new target
if (activeTarget != -1) {
TargetDrawable target = mTargetDrawables.get(activeTarget);
if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
target.setState(TargetDrawable.STATE_FOCUSED);
mHandleDrawable.setAlpha(0.0f);
}
dispatchGrabbedEvent(activeTarget);
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
String targetContentDescription = getTargetDescription(activeTarget);
announceText(targetContentDescription);
}
}
}
mActiveTarget = activeTarget;
@@ -831,21 +857,21 @@ public class MultiWaveView extends View {
private boolean trySwitchToFirstTouchState(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
final float dx = x - mWaveCenterX;
final float dy = y - mWaveCenterY;
if (mAlwaysTrackFinger || dist2(dx,dy) <= getScaledTapRadiusSquared()) {
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(x, y, false);
moveHandleTo(tx, ty, false);
mDragging = true;
return true;
}
return false;
}
private void performInitialLayout(float centerX, float centerY) {
private void assignDefaultsIfNeeded(float centerX, float centerY) {
if (mOuterRadius == 0.0f) {
mOuterRadius = 0.5f*(float) Math.sqrt(dist2(centerX, centerY));
mOuterRadius = 0.5f*(float) Math.hypot(centerX, centerY);
}
if (mHitRadius == 0.0f) {
// Use the radius of inscribed circle of the first target.
@@ -855,12 +881,9 @@ public class MultiWaveView extends View {
mSnapMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
SNAP_MARGIN_DEFAULT, getContext().getResources().getDisplayMetrics());
}
hideChevrons();
hideTargets(false);
moveHandleTo(centerX, centerY, false);
}
private void setupGravity(int dx, int dy) {
private void computeInsets(int dx, int dy) {
final int layoutDirection = getResolvedLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
@@ -899,29 +922,49 @@ public class MultiWaveView extends View {
+ Math.max(width, mMaxTargetWidth + mOuterRing.getWidth()) / 2;
float newWaveCenterY = mVerticalOffset + mVerticalInset
+ Math.max(height, + mMaxTargetHeight + mOuterRing.getHeight()) / 2;
if (newWaveCenterX != mWaveCenterX || newWaveCenterY != mWaveCenterY) {
if (mWaveCenterX == 0 && mWaveCenterY == 0) {
performInitialLayout(newWaveCenterX, newWaveCenterY);
}
mWaveCenterX = newWaveCenterX;
mWaveCenterY = newWaveCenterY;
mOuterRing.setX(mWaveCenterX);
mOuterRing.setY(Math.max(mWaveCenterY, mWaveCenterY));
assignDefaultsIfNeeded(newWaveCenterX, newWaveCenterY);
if (mInitialLayout) {
hideChevrons();
hideTargets(false);
moveHandleTo(0, 0, false);
mInitialLayout = false;
}
updateTargetPositions();
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() {
private void updateTargetPositions(float centerX, float centerY) {
// Reposition the target drawables if the view changed.
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.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) {
for (TargetDrawable target : mChevronDrawables) {
if (target != null) {
target.setPositionX(centerX);
target.setPositionY(centerY);
}
}
}

View File

@@ -32,10 +32,13 @@ public class TargetDrawable {
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 };
{ android.R.attr.state_enabled, -android.R.attr.state_active,
android.R.attr.state_focused };
private float mTranslationX = 0.0f;
private float mTranslationY = 0.0f;
private float mPositionX = 0.0f;
private float mPositionY = 0.0f;
private float mScaleX = 1.0f;
private float mScaleY = 1.0f;
private float mAlpha = 1.0f;
@@ -196,6 +199,22 @@ public class TargetDrawable {
return mAlpha;
}
public void setPositionX(float x) {
mPositionX = x;
}
public void setPositionY(float y) {
mPositionY = y;
}
public float getPositionX() {
return mPositionX;
}
public float getPositionY() {
return mPositionY;
}
public int getWidth() {
return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0;
}
@@ -209,8 +228,8 @@ public class TargetDrawable {
return;
}
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(mTranslationX, mTranslationY);
canvas.scale(mScaleX, mScaleY);
canvas.scale(mScaleX, mScaleY, mPositionX, mPositionY);
canvas.translate(mTranslationX + mPositionX, mTranslationY + mPositionY);
canvas.translate(-0.5f * getWidth(), -0.5f * getHeight());
mDrawable.setAlpha((int) Math.round(mAlpha * 255f));
mDrawable.draw(canvas);

View File

@@ -27,4 +27,10 @@
android:state_focused="false"
android:drawable="@drawable/ic_lockscreen_answer_active" />
<item
android:state_enabled="true"
android:state_active="false"
android:state_focused="true"
android:drawable="@drawable/ic_lockscreen_answer_active" />
</selector>

View File

@@ -27,4 +27,10 @@
android:state_focused="false"
android:drawable="@drawable/ic_lockscreen_camera_activated" />
<item
android:state_enabled="true"
android:state_active="false"
android:state_focused="true"
android:drawable="@drawable/ic_lockscreen_camera_activated" />
</selector>

View File

@@ -27,4 +27,10 @@
android:state_focused="false"
android:drawable="@drawable/ic_lockscreen_decline_activated" />
<item
android:state_enabled="true"
android:state_active="false"
android:state_focused="true"
android:drawable="@drawable/ic_lockscreen_decline_activated" />
</selector>

View File

@@ -17,7 +17,8 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
>
<size android:height="@dimen/keyguard_lockscreen_outerring_diameter" android:width="@dimen/keyguard_lockscreen_outerring_diameter" />
<size android:height="@dimen/keyguard_lockscreen_outerring_diameter"
android:width="@dimen/keyguard_lockscreen_outerring_diameter" />
<solid android:color="#00000000" />
<stroke android:color="#1affffff" android:width="2dp" />
</shape>

View File

@@ -27,4 +27,10 @@
android:state_focused="false"
android:drawable="@drawable/ic_lockscreen_google_activated" />
<item
android:state_enabled="true"
android:state_active="false"
android:state_focused="true"
android:drawable="@drawable/ic_lockscreen_google_activated" />
</selector>

View File

@@ -27,4 +27,10 @@
android:state_focused="false"
android:drawable="@drawable/ic_lockscreen_text_activated" />
<item
android:state_enabled="true"
android:state_active="false"
android:state_focused="true"
android:drawable="@drawable/ic_lockscreen_text_activated" />
</selector>

View File

@@ -27,4 +27,10 @@
android:state_focused="false"
android:drawable="@drawable/ic_lockscreen_silent_activated" />
<item
android:state_enabled="true"
android:state_active="false"
android:state_focused="true"
android:drawable="@drawable/ic_lockscreen_silent_activated" />
</selector>

View File

@@ -27,4 +27,10 @@
android:state_focused="false"
android:drawable="@drawable/ic_lockscreen_soundon_activated" />
<item
android:state_enabled="true"
android:state_active="false"
android:state_focused="true"
android:drawable="@drawable/ic_lockscreen_soundon_activated" />
</selector>

View File

@@ -27,4 +27,10 @@
android:state_focused="false"
android:drawable="@drawable/ic_lockscreen_unlock_activated" />
<item
android:state_enabled="true"
android:state_active="false"
android:state_focused="true"
android:drawable="@drawable/ic_lockscreen_unlock_activated" />
</selector>

View File

@@ -0,0 +1,36 @@
<?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="@color/transparent" />
<item
android:state_enabled="true"
android:state_active="true"
android:state_focused="false"
android:drawable="@drawable/ic_lockscreen_unlock_activated" />
<item
android:state_enabled="true"
android:state_active="false"
android:state_focused="true"
android:drawable="@drawable/ic_lockscreen_unlock_activated" />
</selector>