blob: 094cd1f32b9ee8cb80ddf82bf98b5a333295f212 [file] [log] [blame]
Jorim Jaggia6310292014-04-16 14:11:52 +02001/*
2 * Copyright (C) 2014 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
17package com.android.systemui.statusbar.phone;
18
19import android.app.ActivityManagerNative;
20import android.app.admin.DevicePolicyManager;
21import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
Jorim Jaggi97b63c42014-05-02 23:03:34 +020025import android.content.pm.PackageManager;
Adrian Roosa06905b2014-05-28 12:13:48 +020026import android.content.pm.ResolveInfo;
Jorim Jaggie210cc82014-08-12 23:44:59 +020027import android.content.res.Configuration;
Jorim Jaggi27c9b742015-04-09 10:34:49 -070028import android.content.res.Resources;
Adrian Roos72cc3702014-09-18 17:25:09 +020029import android.graphics.drawable.Drawable;
30import android.graphics.drawable.InsetDrawable;
Jim Millerfe6439f2015-04-11 18:07:57 -070031import android.hardware.fingerprint.FingerprintManager;
Yorke Lee583a20242014-08-12 18:47:08 -070032import android.os.AsyncTask;
Jorim Jaggib2e104f2014-08-15 18:12:36 +020033import android.os.Bundle;
Jorim Jaggia6310292014-04-16 14:11:52 +020034import android.os.RemoteException;
35import android.os.UserHandle;
Jorim Jaggi27c9b742015-04-09 10:34:49 -070036import android.os.Vibrator;
Jorim Jaggia6310292014-04-16 14:11:52 +020037import android.provider.MediaStore;
Jorim Jaggi27c9b742015-04-09 10:34:49 -070038import android.provider.Settings;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070039import android.telecom.TelecomManager;
Jorim Jaggia6310292014-04-16 14:11:52 +020040import android.util.AttributeSet;
41import android.util.Log;
Jorim Jaggie210cc82014-08-12 23:44:59 +020042import android.util.TypedValue;
Jorim Jaggia6310292014-04-16 14:11:52 +020043import android.view.View;
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +020044import android.view.ViewGroup;
Jorim Jaggib2e104f2014-08-15 18:12:36 +020045import android.view.accessibility.AccessibilityNodeInfo;
Jorim Jaggi16423aa2014-10-28 11:42:58 +010046import android.view.animation.AnimationUtils;
47import android.view.animation.Interpolator;
Jorim Jaggia6310292014-04-16 14:11:52 +020048import android.widget.FrameLayout;
Jorim Jaggie210cc82014-08-12 23:44:59 +020049import android.widget.TextView;
Adrian Roosa06905b2014-05-28 12:13:48 +020050
51import com.android.internal.widget.LockPatternUtils;
52import com.android.keyguard.KeyguardUpdateMonitor;
53import com.android.keyguard.KeyguardUpdateMonitorCallback;
Christoph Studerb0183992014-12-22 21:02:26 +010054import com.android.systemui.EventLogConstants;
55import com.android.systemui.EventLogTags;
Jorim Jaggia6310292014-04-16 14:11:52 +020056import com.android.systemui.R;
Jorim Jaggib2e104f2014-08-15 18:12:36 +020057import com.android.systemui.statusbar.CommandQueue;
Selim Cinekbaa23272014-07-08 18:01:07 +020058import com.android.systemui.statusbar.KeyguardAffordanceView;
Jorim Jaggib2e104f2014-08-15 18:12:36 +020059import com.android.systemui.statusbar.KeyguardIndicationController;
60import com.android.systemui.statusbar.policy.AccessibilityController;
61import com.android.systemui.statusbar.policy.FlashlightController;
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +020062import com.android.systemui.statusbar.policy.PreviewInflater;
Jorim Jaggia6310292014-04-16 14:11:52 +020063
Jorim Jaggib2e104f2014-08-15 18:12:36 +020064import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
65import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
66
Jorim Jaggia6310292014-04-16 14:11:52 +020067/**
68 * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
69 * text.
70 */
Selim Cinek4c6969a2014-05-26 19:22:17 +020071public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
Jorim Jaggib2e104f2014-08-15 18:12:36 +020072 UnlockMethodCache.OnUnlockMethodChangedListener,
73 AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {
Jorim Jaggia6310292014-04-16 14:11:52 +020074
75 final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
76
Adrian Roosa06905b2014-05-28 12:13:48 +020077 private static final Intent SECURE_CAMERA_INTENT =
78 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
79 .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
80 private static final Intent INSECURE_CAMERA_INTENT =
81 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
Jorim Jaggi97b63c42014-05-02 23:03:34 +020082 private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
Jorim Jaggi16423aa2014-10-28 11:42:58 +010083 private static final int DOZE_ANIMATION_STAGGER_DELAY = 48;
84 private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
Jorim Jaggi27c9b742015-04-09 10:34:49 -070085 private static final long TRANSIENT_FP_ERROR_TIMEOUT = 1300;
86 private static final long[] FP_ERROR_VIBRATE_PATTERN = new long[] {0, 30, 100, 30};
87 private static final long[] FP_SUCCESS_VIBRATE_PATTERN = new long[] {0, 30};
Jorim Jaggi97b63c42014-05-02 23:03:34 +020088
Selim Cinekbaa23272014-07-08 18:01:07 +020089 private KeyguardAffordanceView mCameraImageView;
90 private KeyguardAffordanceView mPhoneImageView;
91 private KeyguardAffordanceView mLockIcon;
Jorim Jaggie210cc82014-08-12 23:44:59 +020092 private TextView mIndicationText;
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +020093 private ViewGroup mPreviewContainer;
94
95 private View mPhonePreview;
96 private View mCameraPreview;
Jorim Jaggi97b63c42014-05-02 23:03:34 +020097
Jorim Jaggi97b63c42014-05-02 23:03:34 +020098 private ActivityStarter mActivityStarter;
Jorim Jaggiecc798e2014-05-26 18:14:37 +020099 private UnlockMethodCache mUnlockMethodCache;
Adrian Roosa06905b2014-05-28 12:13:48 +0200100 private LockPatternUtils mLockPatternUtils;
Adrian Roos1e1d6ac2014-07-22 17:18:55 +0200101 private FlashlightController mFlashlightController;
Jorim Jaggi781c29c2014-08-05 20:39:15 +0200102 private PreviewInflater mPreviewInflater;
Adrian Roos4ebcdfd2014-08-12 23:33:49 +0200103 private KeyguardIndicationController mIndicationController;
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200104 private AccessibilityController mAccessibilityController;
105 private PhoneStatusBar mPhoneStatusBar;
Adrian Roos2fe592d2014-05-17 03:11:59 +0200106
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200107 private final TrustDrawable mTrustDrawable;
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100108 private final Interpolator mLinearOutSlowInInterpolator;
Adrian Roos72cc3702014-09-18 17:25:09 +0200109 private int mLastUnlockIconRes = 0;
Jorim Jaggia86790b2015-04-02 16:32:29 -0700110 private boolean mPrewarmSent;
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700111 private boolean mTransientFpError;
Adrian Roos72cc3702014-09-18 17:25:09 +0200112
Jorim Jaggia6310292014-04-16 14:11:52 +0200113 public KeyguardBottomAreaView(Context context) {
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200114 this(context, null);
Jorim Jaggia6310292014-04-16 14:11:52 +0200115 }
116
117 public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200118 this(context, attrs, 0);
Jorim Jaggia6310292014-04-16 14:11:52 +0200119 }
120
121 public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200122 this(context, attrs, defStyleAttr, 0);
Jorim Jaggia6310292014-04-16 14:11:52 +0200123 }
124
125 public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
126 int defStyleRes) {
127 super(context, attrs, defStyleAttr, defStyleRes);
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200128 mTrustDrawable = new TrustDrawable(mContext);
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100129 mLinearOutSlowInInterpolator =
130 AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
Jorim Jaggia6310292014-04-16 14:11:52 +0200131 }
132
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200133 private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
134 @Override
135 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
136 super.onInitializeAccessibilityNodeInfo(host, info);
137 String label = null;
138 if (host == mLockIcon) {
139 label = getResources().getString(R.string.unlock_label);
140 } else if (host == mCameraImageView) {
141 label = getResources().getString(R.string.camera_label);
142 } else if (host == mPhoneImageView) {
143 label = getResources().getString(R.string.phone_label);
144 }
145 info.addAction(new AccessibilityAction(ACTION_CLICK, label));
146 }
147
148 @Override
149 public boolean performAccessibilityAction(View host, int action, Bundle args) {
150 if (action == ACTION_CLICK) {
151 if (host == mLockIcon) {
152 mPhoneStatusBar.animateCollapsePanels(
Jorim Jaggi4eedc1d2014-10-27 13:45:56 +0100153 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200154 return true;
155 } else if (host == mCameraImageView) {
156 launchCamera();
157 return true;
158 } else if (host == mPhoneImageView) {
159 launchPhone();
160 return true;
161 }
162 }
163 return super.performAccessibilityAction(host, action, args);
164 }
165 };
166
Jorim Jaggia6310292014-04-16 14:11:52 +0200167 @Override
168 protected void onFinishInflate() {
169 super.onFinishInflate();
Adrian Roosa06905b2014-05-28 12:13:48 +0200170 mLockPatternUtils = new LockPatternUtils(mContext);
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +0200171 mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container);
Selim Cinekbaa23272014-07-08 18:01:07 +0200172 mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
173 mPhoneImageView = (KeyguardAffordanceView) findViewById(R.id.phone_button);
174 mLockIcon = (KeyguardAffordanceView) findViewById(R.id.lock_icon);
Jorim Jaggie210cc82014-08-12 23:44:59 +0200175 mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text);
Adrian Roosa06905b2014-05-28 12:13:48 +0200176 watchForCameraPolicyChanges();
Jorim Jaggia6310292014-04-16 14:11:52 +0200177 updateCameraVisibility();
Jorim Jaggi97b63c42014-05-02 23:03:34 +0200178 updatePhoneVisibility();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200179 mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
180 mUnlockMethodCache.addListener(this);
Jorim Jaggie7b12522014-08-06 16:41:21 +0200181 updateLockIcon();
Selim Cinekbaa23272014-07-08 18:01:07 +0200182 setClipChildren(false);
183 setClipToPadding(false);
Jorim Jaggi781c29c2014-08-05 20:39:15 +0200184 mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext));
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +0200185 inflatePreviews();
Adrian Roos4ebcdfd2014-08-12 23:33:49 +0200186 mLockIcon.setOnClickListener(this);
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200187 mLockIcon.setBackground(mTrustDrawable);
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200188 mLockIcon.setOnLongClickListener(this);
189 mCameraImageView.setOnClickListener(this);
190 mPhoneImageView.setOnClickListener(this);
191 initAccessibility();
192 }
193
194 private void initAccessibility() {
195 mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate);
196 mPhoneImageView.setAccessibilityDelegate(mAccessibilityDelegate);
197 mCameraImageView.setAccessibilityDelegate(mAccessibilityDelegate);
Jorim Jaggia6310292014-04-16 14:11:52 +0200198 }
199
Jorim Jaggie210cc82014-08-12 23:44:59 +0200200 @Override
201 protected void onConfigurationChanged(Configuration newConfig) {
202 super.onConfigurationChanged(newConfig);
203 int indicationBottomMargin = getResources().getDimensionPixelSize(
204 R.dimen.keyguard_indication_margin_bottom);
205 MarginLayoutParams mlp = (MarginLayoutParams) mIndicationText.getLayoutParams();
206 if (mlp.bottomMargin != indicationBottomMargin) {
207 mlp.bottomMargin = indicationBottomMargin;
208 mIndicationText.setLayoutParams(mlp);
209 }
210
211 // Respect font size setting.
212 mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
213 getResources().getDimensionPixelSize(
214 com.android.internal.R.dimen.text_size_small_material));
215 }
216
Jorim Jaggi97b63c42014-05-02 23:03:34 +0200217 public void setActivityStarter(ActivityStarter activityStarter) {
218 mActivityStarter = activityStarter;
219 }
220
Adrian Roos1e1d6ac2014-07-22 17:18:55 +0200221 public void setFlashlightController(FlashlightController flashlightController) {
222 mFlashlightController = flashlightController;
223 }
224
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200225 public void setAccessibilityController(AccessibilityController accessibilityController) {
226 mAccessibilityController = accessibilityController;
227 accessibilityController.addStateChangedCallback(this);
228 }
229
230 public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
231 mPhoneStatusBar = phoneStatusBar;
Dan Sandlere163a642015-03-01 22:58:32 -0500232 updateCameraVisibility(); // in case onFinishInflate() was called too early
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200233 }
234
Adrian Roosa06905b2014-05-28 12:13:48 +0200235 private Intent getCameraIntent() {
236 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
237 boolean currentUserHasTrust = updateMonitor.getUserHasTrust(
238 mLockPatternUtils.getCurrentUser());
239 return mLockPatternUtils.isSecure() && !currentUserHasTrust
240 ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
241 }
242
Jorim Jaggia6310292014-04-16 14:11:52 +0200243 private void updateCameraVisibility() {
Dan Sandlere163a642015-03-01 22:58:32 -0500244 if (mCameraImageView == null) {
245 // Things are not set up yet; reply hazy, ask again later
246 return;
247 }
Adrian Roosa06905b2014-05-28 12:13:48 +0200248 ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
249 PackageManager.MATCH_DEFAULT_ONLY,
250 mLockPatternUtils.getCurrentUser());
Jorim Jaggi15dac5f2014-08-27 19:08:26 +0200251 boolean visible = !isCameraDisabledByDpm() && resolved != null
252 && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance);
Selim Cinek4c6969a2014-05-26 19:22:17 +0200253 mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
Jorim Jaggia6310292014-04-16 14:11:52 +0200254 }
255
Jorim Jaggi97b63c42014-05-02 23:03:34 +0200256 private void updatePhoneVisibility() {
257 boolean visible = isPhoneVisible();
Selim Cinek4c6969a2014-05-26 19:22:17 +0200258 mPhoneImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
Jorim Jaggi97b63c42014-05-02 23:03:34 +0200259 }
260
261 private boolean isPhoneVisible() {
262 PackageManager pm = mContext.getPackageManager();
263 return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
264 && pm.resolveActivity(PHONE_INTENT, 0) != null;
265 }
266
Jorim Jaggia6310292014-04-16 14:11:52 +0200267 private boolean isCameraDisabledByDpm() {
268 final DevicePolicyManager dpm =
269 (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
Dan Sandlere163a642015-03-01 22:58:32 -0500270 if (dpm != null && mPhoneStatusBar != null) {
Jorim Jaggia6310292014-04-16 14:11:52 +0200271 try {
272 final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
273 final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
274 final boolean disabledBecauseKeyguardSecure =
275 (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
Jim Millerab954542014-10-10 18:21:49 -0700276 && mPhoneStatusBar.isKeyguardSecure();
Jorim Jaggia6310292014-04-16 14:11:52 +0200277 return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
278 } catch (RemoteException e) {
279 Log.e(TAG, "Can't get userId", e);
280 }
281 }
282 return false;
283 }
284
Adrian Roosa06905b2014-05-28 12:13:48 +0200285 private void watchForCameraPolicyChanges() {
Jorim Jaggia6310292014-04-16 14:11:52 +0200286 final IntentFilter filter = new IntentFilter();
287 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
Adrian Roosa06905b2014-05-28 12:13:48 +0200288 getContext().registerReceiverAsUser(mDevicePolicyReceiver,
289 UserHandle.ALL, filter, null, null);
290 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
Jorim Jaggia6310292014-04-16 14:11:52 +0200291 }
292
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200293 @Override
294 public void onStateChanged(boolean accessibilityEnabled, boolean touchExplorationEnabled) {
295 mCameraImageView.setClickable(touchExplorationEnabled);
296 mPhoneImageView.setClickable(touchExplorationEnabled);
297 mCameraImageView.setFocusable(accessibilityEnabled);
298 mPhoneImageView.setFocusable(accessibilityEnabled);
299 updateLockIconClickability();
Jorim Jaggia6310292014-04-16 14:11:52 +0200300 }
301
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200302 private void updateLockIconClickability() {
303 if (mAccessibilityController == null) {
304 return;
305 }
Adrian Roos38fc76062014-09-22 17:34:56 +0200306 boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
307 boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
308 && !mAccessibilityController.isAccessibilityEnabled();
309 boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
310 && !clickToForceLock;
311 mLockIcon.setClickable(clickToForceLock || clickToUnlock);
312 mLockIcon.setLongClickable(longClickToForceLock);
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200313 mLockIcon.setFocusable(mAccessibilityController.isAccessibilityEnabled());
Jorim Jaggia6310292014-04-16 14:11:52 +0200314 }
315
Selim Cinek4c6969a2014-05-26 19:22:17 +0200316 @Override
317 public void onClick(View v) {
318 if (v == mCameraImageView) {
319 launchCamera();
320 } else if (v == mPhoneImageView) {
321 launchPhone();
Adrian Roos4ebcdfd2014-08-12 23:33:49 +0200322 } if (v == mLockIcon) {
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200323 if (!mAccessibilityController.isAccessibilityEnabled()) {
324 handleTrustCircleClick();
325 } else {
326 mPhoneStatusBar.animateCollapsePanels(
327 CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
328 }
Selim Cinek4c6969a2014-05-26 19:22:17 +0200329 }
330 }
331
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200332 @Override
333 public boolean onLongClick(View v) {
334 handleTrustCircleClick();
335 return true;
336 }
337
338 private void handleTrustCircleClick() {
Christoph Studerb0183992014-12-22 21:02:26 +0100339 EventLogTags.writeSysuiLockscreenGesture(
340 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK, 0 /* lengthDp - N/A */,
341 0 /* velocityDp - N/A */);
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200342 mIndicationController.showTransientIndication(
343 R.string.keyguard_indication_trust_disabled);
344 mLockPatternUtils.requireCredentialEntry(mLockPatternUtils.getCurrentUser());
345 }
346
Jorim Jaggia86790b2015-04-02 16:32:29 -0700347 public void prewarmCamera() {
Adrian Roosa06905b2014-05-28 12:13:48 +0200348 Intent intent = getCameraIntent();
Jorim Jaggia86790b2015-04-02 16:32:29 -0700349 String targetPackage = PreviewInflater.getTargetPackage(mContext, intent,
350 mLockPatternUtils.getCurrentUser());
351 if (targetPackage != null) {
352 Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_PREWARM);
353 prewarm.setPackage(targetPackage);
354 mPrewarmSent = true;
355 mContext.sendBroadcast(prewarm);
356 }
357 }
358
359 public void maybeCooldownCamera() {
360 if (!mPrewarmSent) {
361 return;
362 }
363 mPrewarmSent = false;
364 Intent intent = getCameraIntent();
365 String targetPackage = PreviewInflater.getTargetPackage(mContext, intent,
366 mLockPatternUtils.getCurrentUser());
367 if (targetPackage != null) {
368 Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_COOLDOWN);
369 prewarm.setPackage(targetPackage);
370 mContext.sendBroadcast(prewarm);
371 }
372 }
373
374 public void launchCamera() {
375
376 // Reset prewarm state.
377 mPrewarmSent = false;
378 final Intent intent = getCameraIntent();
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200379 boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
380 mContext, intent, mLockPatternUtils.getCurrentUser());
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200381 if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
Jorim Jaggia86790b2015-04-02 16:32:29 -0700382 AsyncTask.execute(new Runnable() {
383 @Override
384 public void run() {
385 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
386 }
387 });
Adrian Roosa06905b2014-05-28 12:13:48 +0200388 } else {
Jorim Jaggi746f7fa2014-08-27 17:52:46 +0200389
390 // We need to delay starting the activity because ResolverActivity finishes itself if
391 // launched behind lockscreen.
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200392 mActivityStarter.startActivity(intent, false /* dismissShade */);
Adrian Roosa06905b2014-05-28 12:13:48 +0200393 }
Jorim Jaggia6310292014-04-16 14:11:52 +0200394 }
395
Selim Cinek4c6969a2014-05-26 19:22:17 +0200396 public void launchPhone() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700397 final TelecomManager tm = TelecomManager.from(mContext);
Nancy Chen0eb1e402014-08-21 22:52:29 -0700398 if (tm.isInCall()) {
Yorke Lee583a20242014-08-12 18:47:08 -0700399 AsyncTask.execute(new Runnable() {
400 @Override
401 public void run() {
Nancy Chen0eb1e402014-08-21 22:52:29 -0700402 tm.showInCallScreen(false /* showDialpad */);
Yorke Lee583a20242014-08-12 18:47:08 -0700403 }
404 });
405 } else {
Jorim Jaggi85dc23c2014-09-08 14:42:29 +0200406 mActivityStarter.startActivity(PHONE_INTENT, false /* dismissShade */);
Yorke Lee583a20242014-08-12 18:47:08 -0700407 }
Jorim Jaggi97b63c42014-05-02 23:03:34 +0200408 }
409
Adrian Roos2fe592d2014-05-17 03:11:59 +0200410
411 @Override
412 protected void onVisibilityChanged(View changedView, int visibility) {
413 super.onVisibilityChanged(changedView, visibility);
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200414 if (isShown()) {
415 mTrustDrawable.start();
416 } else {
417 mTrustDrawable.stop();
418 }
Adrian Roos2fe592d2014-05-17 03:11:59 +0200419 if (changedView == this && visibility == VISIBLE) {
Jorim Jaggie7b12522014-08-06 16:41:21 +0200420 updateLockIcon();
Adrian Roosa06905b2014-05-28 12:13:48 +0200421 updateCameraVisibility();
Adrian Roos2fe592d2014-05-17 03:11:59 +0200422 }
423 }
424
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200425 @Override
426 protected void onDetachedFromWindow() {
427 super.onDetachedFromWindow();
428 mTrustDrawable.stop();
429 }
430
Jorim Jaggie7b12522014-08-06 16:41:21 +0200431 private void updateLockIcon() {
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200432 boolean visible = isShown() && KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
433 if (visible) {
434 mTrustDrawable.start();
435 } else {
436 mTrustDrawable.stop();
437 }
438 if (!visible) {
Adrian Roos2fe592d2014-05-17 03:11:59 +0200439 return;
440 }
Jorim Jaggie7b12522014-08-06 16:41:21 +0200441 // TODO: Real icon for facelock.
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700442 boolean isFingerprintIcon =
443 KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning();
444 boolean anyFingerprintIcon = isFingerprintIcon || mTransientFpError;
445 int iconRes = mTransientFpError ? R.drawable.ic_fingerprint_error
446 : isFingerprintIcon ? R.drawable.ic_fingerprint
447 : mUnlockMethodCache.isFaceUnlockRunning()
448 ? com.android.internal.R.drawable.ic_account_circle
Christoph Studer2231c6e2014-12-19 12:40:13 +0100449 : mUnlockMethodCache.isCurrentlyInsecure() ? R.drawable.ic_lock_open_24dp
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200450 : R.drawable.ic_lock_24dp;
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700451
Adrian Roos72cc3702014-09-18 17:25:09 +0200452 if (mLastUnlockIconRes != iconRes) {
453 Drawable icon = mContext.getDrawable(iconRes);
454 int iconHeight = getResources().getDimensionPixelSize(
455 R.dimen.keyguard_affordance_icon_height);
456 int iconWidth = getResources().getDimensionPixelSize(
457 R.dimen.keyguard_affordance_icon_width);
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700458 if (!anyFingerprintIcon && (icon.getIntrinsicHeight() != iconHeight
459 || icon.getIntrinsicWidth() != iconWidth)) {
Adrian Roos72cc3702014-09-18 17:25:09 +0200460 icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight);
461 }
462 mLockIcon.setImageDrawable(icon);
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700463 mLockIcon.setPaddingRelative(0, 0, 0, anyFingerprintIcon
464 ? getResources().getDimensionPixelSize(
465 R.dimen.fingerprint_icon_additional_padding)
466 : 0);
467 mLockIcon.setRestingAlpha(
468 anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
Adrian Roos72cc3702014-09-18 17:25:09 +0200469 }
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700470
471 // Hide trust circle when fingerprint is running.
472 boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !anyFingerprintIcon;
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200473 mTrustDrawable.setTrustManaged(trustManaged);
Jorim Jaggib2e104f2014-08-15 18:12:36 +0200474 updateLockIconClickability();
Adrian Roos2fe592d2014-05-17 03:11:59 +0200475 }
476
Selim Cinekbaa23272014-07-08 18:01:07 +0200477 public KeyguardAffordanceView getPhoneView() {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200478 return mPhoneImageView;
479 }
480
Selim Cinekbaa23272014-07-08 18:01:07 +0200481 public KeyguardAffordanceView getCameraView() {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200482 return mCameraImageView;
483 }
484
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +0200485 public View getPhonePreview() {
486 return mPhonePreview;
487 }
488
489 public View getCameraPreview() {
490 return mCameraPreview;
491 }
492
Selim Cinekbaa23272014-07-08 18:01:07 +0200493 public KeyguardAffordanceView getLockIcon() {
Selim Cinek4c6969a2014-05-26 19:22:17 +0200494 return mLockIcon;
495 }
496
Selim Cinekf99d0002014-06-13 07:36:01 +0200497 public View getIndicationView() {
498 return mIndicationText;
499 }
500
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200501 @Override
Jorim Jaggi2580a9762014-06-25 03:08:25 +0200502 public boolean hasOverlappingRendering() {
503 return false;
504 }
505
506 @Override
Christoph Studer2231c6e2014-12-19 12:40:13 +0100507 public void onUnlockMethodStateChanged() {
Jorim Jaggie7b12522014-08-06 16:41:21 +0200508 updateLockIcon();
Adrian Roosa06905b2014-05-28 12:13:48 +0200509 updateCameraVisibility();
Jorim Jaggiecc798e2014-05-26 18:14:37 +0200510 }
Adrian Roosa06905b2014-05-28 12:13:48 +0200511
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +0200512 private void inflatePreviews() {
Jorim Jaggi781c29c2014-08-05 20:39:15 +0200513 mPhonePreview = mPreviewInflater.inflatePreview(PHONE_INTENT);
514 mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent());
Jorim Jaggib6cdcbc2014-07-25 21:58:29 +0200515 if (mPhonePreview != null) {
516 mPreviewContainer.addView(mPhonePreview);
517 mPhonePreview.setVisibility(View.INVISIBLE);
518 }
519 if (mCameraPreview != null) {
520 mPreviewContainer.addView(mCameraPreview);
521 mCameraPreview.setVisibility(View.INVISIBLE);
522 }
523 }
524
Jorim Jaggi16423aa2014-10-28 11:42:58 +0100525 public void startFinishDozeAnimation() {
526 long delay = 0;
527 if (mPhoneImageView.getVisibility() == View.VISIBLE) {
528 startFinishDozeAnimationElement(mPhoneImageView, delay);
529 delay += DOZE_ANIMATION_STAGGER_DELAY;
530 }
531 startFinishDozeAnimationElement(mLockIcon, delay);
532 delay += DOZE_ANIMATION_STAGGER_DELAY;
533 if (mCameraImageView.getVisibility() == View.VISIBLE) {
534 startFinishDozeAnimationElement(mCameraImageView, delay);
535 }
536 mIndicationText.setAlpha(0f);
537 mIndicationText.animate()
538 .alpha(1f)
539 .setInterpolator(mLinearOutSlowInInterpolator)
540 .setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
541 }
542
543 private void startFinishDozeAnimationElement(View element, long delay) {
544 element.setAlpha(0f);
545 element.setTranslationY(element.getHeight() / 2);
546 element.animate()
547 .alpha(1f)
548 .translationY(0f)
549 .setInterpolator(mLinearOutSlowInInterpolator)
550 .setStartDelay(delay)
551 .setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
552 }
553
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700554 private void vibrateFingerprintError() {
555 mContext.getSystemService(Vibrator.class).vibrate(FP_ERROR_VIBRATE_PATTERN, -1);
556 }
557
558 private void vibrateFingerprintSuccess() {
559 mContext.getSystemService(Vibrator.class).vibrate(FP_SUCCESS_VIBRATE_PATTERN, -1);
560 }
561
Adrian Roosa06905b2014-05-28 12:13:48 +0200562 private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() {
563 public void onReceive(Context context, Intent intent) {
564 post(new Runnable() {
565 @Override
566 public void run() {
567 updateCameraVisibility();
568 }
569 });
570 }
571 };
572
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700573 private final Runnable mTransientFpErrorClearRunnable = new Runnable() {
574 @Override
575 public void run() {
576 mTransientFpError = false;
577 mIndicationController.hideTransientIndication();
578 updateLockIcon();
579 }
580 };
581
Adrian Roosa06905b2014-05-28 12:13:48 +0200582 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
583 new KeyguardUpdateMonitorCallback() {
584 @Override
585 public void onUserSwitchComplete(int userId) {
586 updateCameraVisibility();
587 }
Jorim Jaggie7b12522014-08-06 16:41:21 +0200588
589 @Override
Adrian Roos2e3ccbb2014-08-19 22:23:37 +0200590 public void onScreenTurnedOn() {
591 updateLockIcon();
592 }
593
594 @Override
595 public void onScreenTurnedOff(int why) {
596 updateLockIcon();
597 }
Adrian Roosb9ae0902014-10-27 14:20:30 +0100598
599 @Override
600 public void onKeyguardVisibilityChanged(boolean showing) {
601 updateLockIcon();
602 }
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700603
604 @Override
605 public void onFingerprintAuthenticated(int userId) {
606 vibrateFingerprintSuccess();
607 }
608
609 @Override
610 public void onFingerprintRunningStateChanged(boolean running) {
611 updateLockIcon();
612 }
613
614 @Override
615 public void onFingerprintHelp(int msgId, String helpString) {
616 vibrateFingerprintError();
617 mTransientFpError = true;
618 mIndicationController.showTransientIndication(helpString,
619 getResources().getColor(R.color.system_warning_color, null));
620 removeCallbacks(mTransientFpErrorClearRunnable);
621 postDelayed(mTransientFpErrorClearRunnable, TRANSIENT_FP_ERROR_TIMEOUT);
622 updateLockIcon();
623 }
624
625 @Override
626 public void onFingerprintError(int msgId, String errString) {
627 // TODO: Go to bouncer if this is "too many attempts" (lockout) error.
628 Log.i(TAG, "FP Error: " + errString);
Jim Millerfe6439f2015-04-11 18:07:57 -0700629 updateLockIcon();
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700630 }
Adrian Roosa06905b2014-05-28 12:13:48 +0200631 };
Adrian Roos4ebcdfd2014-08-12 23:33:49 +0200632
633 public void setKeyguardIndicationController(
634 KeyguardIndicationController keyguardIndicationController) {
635 mIndicationController = keyguardIndicationController;
636 }
Adrian Roos72cc3702014-09-18 17:25:09 +0200637
Adrian Roos72cc3702014-09-18 17:25:09 +0200638 /**
639 * A wrapper around another Drawable that overrides the intrinsic size.
640 */
641 private static class IntrinsicSizeDrawable extends InsetDrawable {
642
643 private final int mIntrinsicWidth;
644 private final int mIntrinsicHeight;
645
646 public IntrinsicSizeDrawable(Drawable drawable, int intrinsicWidth, int intrinsicHeight) {
647 super(drawable, 0);
648 mIntrinsicWidth = intrinsicWidth;
649 mIntrinsicHeight = intrinsicHeight;
650 }
651
652 @Override
653 public int getIntrinsicWidth() {
654 return mIntrinsicWidth;
655 }
656
657 @Override
658 public int getIntrinsicHeight() {
659 return mIntrinsicHeight;
660 }
661 }
Jorim Jaggia6310292014-04-16 14:11:52 +0200662}