OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / systemui / statusbar / phone / LockIcon.java
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16
17 package com.android.systemui.statusbar.phone;
18
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.graphics.drawable.AnimatedVectorDrawable;
22 import android.graphics.drawable.Drawable;
23 import android.graphics.drawable.InsetDrawable;
24 import android.util.AttributeSet;
25 import android.view.View;
26 import android.view.accessibility.AccessibilityNodeInfo;
27
28 import com.android.keyguard.KeyguardUpdateMonitor;
29 import com.android.systemui.R;
30 import com.android.systemui.statusbar.KeyguardAffordanceView;
31 import com.android.systemui.statusbar.policy.AccessibilityController;
32
33 /**
34  * Manages the different states and animations of the unlock icon.
35  */
36 public class LockIcon extends KeyguardAffordanceView {
37
38     private static final int STATE_LOCKED = 0;
39     private static final int STATE_LOCK_OPEN = 1;
40     private static final int STATE_FACE_UNLOCK = 2;
41     private static final int STATE_FINGERPRINT = 3;
42     private static final int STATE_FINGERPRINT_ERROR = 4;
43
44     private int mLastState = 0;
45     private boolean mLastDeviceInteractive;
46     private boolean mTransientFpError;
47     private boolean mDeviceInteractive;
48     private boolean mScreenOn;
49     private boolean mLastScreenOn;
50     private TrustDrawable mTrustDrawable;
51     private final UnlockMethodCache mUnlockMethodCache;
52     private AccessibilityController mAccessibilityController;
53     private boolean mHasFingerPrintIcon;
54     private int mDensity;
55
56     public LockIcon(Context context, AttributeSet attrs) {
57         super(context, attrs);
58         mTrustDrawable = new TrustDrawable(context);
59         setBackground(mTrustDrawable);
60         mUnlockMethodCache = UnlockMethodCache.getInstance(context);
61     }
62
63     @Override
64     protected void onVisibilityChanged(View changedView, int visibility) {
65         super.onVisibilityChanged(changedView, visibility);
66         if (isShown()) {
67             mTrustDrawable.start();
68         } else {
69             mTrustDrawable.stop();
70         }
71     }
72
73     @Override
74     protected void onDetachedFromWindow() {
75         super.onDetachedFromWindow();
76         mTrustDrawable.stop();
77     }
78
79     public void setTransientFpError(boolean transientFpError) {
80         mTransientFpError = transientFpError;
81         update();
82     }
83
84     public void setDeviceInteractive(boolean deviceInteractive) {
85         mDeviceInteractive = deviceInteractive;
86         update();
87     }
88
89     public void setScreenOn(boolean screenOn) {
90         mScreenOn = screenOn;
91         update();
92     }
93
94     @Override
95     protected void onConfigurationChanged(Configuration newConfig) {
96         super.onConfigurationChanged(newConfig);
97         final int density = newConfig.densityDpi;
98         if (density != mDensity) {
99             mDensity = density;
100             mTrustDrawable.stop();
101             mTrustDrawable = new TrustDrawable(getContext());
102             setBackground(mTrustDrawable);
103             update();
104         }
105     }
106
107     public void update() {
108         update(false /* force */);
109     }
110
111     public void update(boolean force) {
112         boolean visible = isShown()
113                 && KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
114         if (visible) {
115             mTrustDrawable.start();
116         } else {
117             mTrustDrawable.stop();
118         }
119         // TODO: Real icon for facelock.
120         int state = getState();
121         boolean anyFingerprintIcon = state == STATE_FINGERPRINT || state == STATE_FINGERPRINT_ERROR;
122         boolean useAdditionalPadding = anyFingerprintIcon;
123         boolean trustHidden = anyFingerprintIcon;
124         if (state != mLastState || mDeviceInteractive != mLastDeviceInteractive
125                 || mScreenOn != mLastScreenOn || force) {
126             boolean isAnim = true;
127             int iconRes = getAnimationResForTransition(mLastState, state, mLastDeviceInteractive,
128                     mDeviceInteractive, mLastScreenOn, mScreenOn);
129             if (iconRes == R.drawable.lockscreen_fingerprint_draw_off_animation) {
130                 anyFingerprintIcon = true;
131                 useAdditionalPadding = true;
132                 trustHidden = true;
133             } else if (iconRes == R.drawable.trusted_state_to_error_animation) {
134                 anyFingerprintIcon = true;
135                 useAdditionalPadding = false;
136                 trustHidden = true;
137             } else if (iconRes == R.drawable.error_to_trustedstate_animation) {
138                 anyFingerprintIcon = true;
139                 useAdditionalPadding = false;
140                 trustHidden = false;
141             }
142             if (iconRes == -1) {
143                 iconRes = getIconForState(state, mScreenOn, mDeviceInteractive);
144                 isAnim = false;
145             }
146             Drawable icon = mContext.getDrawable(iconRes);
147             final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
148                     ? (AnimatedVectorDrawable) icon
149                     : null;
150             int iconHeight = getResources().getDimensionPixelSize(
151                     R.dimen.keyguard_affordance_icon_height);
152             int iconWidth = getResources().getDimensionPixelSize(
153                     R.dimen.keyguard_affordance_icon_width);
154             if (!anyFingerprintIcon && (icon.getIntrinsicHeight() != iconHeight
155                     || icon.getIntrinsicWidth() != iconWidth)) {
156                 icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight);
157             }
158             setPaddingRelative(0, 0, 0, useAdditionalPadding
159                     ? getResources().getDimensionPixelSize(
160                     R.dimen.fingerprint_icon_additional_padding)
161                     : 0);
162             setRestingAlpha(
163                     anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
164             setImageDrawable(icon);
165             String contentDescription = getResources().getString(anyFingerprintIcon
166                     ? R.string.accessibility_unlock_button_fingerprint
167                     : R.string.accessibility_unlock_button);
168             setContentDescription(contentDescription);
169             mHasFingerPrintIcon = anyFingerprintIcon;
170             if (animation != null && isAnim) {
171                 animation.start();
172             }
173             mLastState = state;
174             mLastDeviceInteractive = mDeviceInteractive;
175             mLastScreenOn = mScreenOn;
176         }
177
178         // Hide trust circle when fingerprint is running.
179         boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !trustHidden;
180         mTrustDrawable.setTrustManaged(trustManaged);
181         updateClickability();
182     }
183
184     private void updateClickability() {
185         if (mAccessibilityController == null) {
186             return;
187         }
188         boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
189         boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
190                 && !mAccessibilityController.isAccessibilityEnabled();
191         boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
192                 && !clickToForceLock;
193         setClickable(clickToForceLock || clickToUnlock);
194         setLongClickable(longClickToForceLock);
195         setFocusable(mAccessibilityController.isAccessibilityEnabled());
196     }
197
198     @Override
199     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
200         super.onInitializeAccessibilityNodeInfo(info);
201         if (mHasFingerPrintIcon) {
202             // Avoid that the button description is also spoken
203             info.setClassName(LockIcon.class.getName());
204             AccessibilityNodeInfo.AccessibilityAction unlock
205                     = new AccessibilityNodeInfo.AccessibilityAction(
206                     AccessibilityNodeInfo.ACTION_CLICK,
207                     getContext().getString(R.string.accessibility_unlock_without_fingerprint));
208             info.addAction(unlock);
209         }
210     }
211
212     public void setAccessibilityController(AccessibilityController accessibilityController) {
213         mAccessibilityController = accessibilityController;
214     }
215
216     private int getIconForState(int state, boolean screenOn, boolean deviceInteractive) {
217         switch (state) {
218             case STATE_LOCKED:
219                 return R.drawable.ic_lock_24dp;
220             case STATE_LOCK_OPEN:
221                 return R.drawable.ic_lock_open_24dp;
222             case STATE_FACE_UNLOCK:
223                 return com.android.internal.R.drawable.ic_account_circle;
224             case STATE_FINGERPRINT:
225                 // If screen is off and device asleep, use the draw on animation so the first frame
226                 // gets drawn.
227                 return screenOn && deviceInteractive
228                         ? R.drawable.ic_fingerprint
229                         : R.drawable.lockscreen_fingerprint_draw_on_animation;
230             case STATE_FINGERPRINT_ERROR:
231                 return R.drawable.ic_fingerprint_error;
232             default:
233                 throw new IllegalArgumentException();
234         }
235     }
236
237     private int getAnimationResForTransition(int oldState, int newState,
238             boolean oldDeviceInteractive, boolean deviceInteractive,
239             boolean oldScreenOn, boolean screenOn) {
240         if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
241             return R.drawable.lockscreen_fingerprint_fp_to_error_state_animation;
242         } else if (oldState == STATE_LOCK_OPEN && newState == STATE_FINGERPRINT_ERROR) {
243             return R.drawable.trusted_state_to_error_animation;
244         } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_LOCK_OPEN) {
245             return R.drawable.error_to_trustedstate_animation;
246         } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
247             return R.drawable.lockscreen_fingerprint_error_state_to_fp_animation;
248         } else if (oldState == STATE_FINGERPRINT && newState == STATE_LOCK_OPEN
249                 && !mUnlockMethodCache.isTrusted()) {
250             return R.drawable.lockscreen_fingerprint_draw_off_animation;
251         } else if (newState == STATE_FINGERPRINT && (!oldScreenOn && screenOn && deviceInteractive
252                 || screenOn && !oldDeviceInteractive && deviceInteractive)) {
253             return R.drawable.lockscreen_fingerprint_draw_on_animation;
254         } else {
255             return -1;
256         }
257     }
258
259     private int getState() {
260         KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
261         boolean fingerprintRunning = updateMonitor.isFingerprintDetectionRunning();
262         boolean unlockingAllowed = updateMonitor.isUnlockingWithFingerprintAllowed();
263         if (mTransientFpError) {
264             return STATE_FINGERPRINT_ERROR;
265         } else if (mUnlockMethodCache.canSkipBouncer()) {
266             return STATE_LOCK_OPEN;
267         } else if (mUnlockMethodCache.isFaceUnlockRunning()) {
268             return STATE_FACE_UNLOCK;
269         } else if (fingerprintRunning && unlockingAllowed) {
270             return STATE_FINGERPRINT;
271         } else {
272             return STATE_LOCKED;
273         }
274     }
275
276     /**
277      * A wrapper around another Drawable that overrides the intrinsic size.
278      */
279     private static class IntrinsicSizeDrawable extends InsetDrawable {
280
281         private final int mIntrinsicWidth;
282         private final int mIntrinsicHeight;
283
284         public IntrinsicSizeDrawable(Drawable drawable, int intrinsicWidth, int intrinsicHeight) {
285             super(drawable, 0);
286             mIntrinsicWidth = intrinsicWidth;
287             mIntrinsicHeight = intrinsicHeight;
288         }
289
290         @Override
291         public int getIntrinsicWidth() {
292             return mIntrinsicWidth;
293         }
294
295         @Override
296         public int getIntrinsicHeight() {
297             return mIntrinsicHeight;
298         }
299     }
300 }