2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 package com.android.systemui.statusbar.phone;
19 import android.app.ActivityManager;
20 import android.app.ActivityManagerNative;
21 import android.app.admin.DevicePolicyManager;
22 import android.content.BroadcastReceiver;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.ServiceConnection;
28 import android.content.pm.ActivityInfo;
29 import android.content.pm.PackageManager;
30 import android.content.pm.ResolveInfo;
31 import android.content.res.Configuration;
32 import android.os.AsyncTask;
33 import android.os.Bundle;
34 import android.os.IBinder;
35 import android.os.Message;
36 import android.os.Messenger;
37 import android.os.RemoteException;
38 import android.os.UserHandle;
39 import android.provider.MediaStore;
40 import android.service.media.CameraPrewarmService;
41 import android.telecom.TelecomManager;
42 import android.util.AttributeSet;
43 import android.util.Log;
44 import android.util.TypedValue;
45 import android.view.View;
46 import android.view.ViewGroup;
47 import android.view.accessibility.AccessibilityNodeInfo;
48 import android.widget.FrameLayout;
49 import android.widget.TextView;
51 import com.android.internal.widget.LockPatternUtils;
52 import com.android.keyguard.KeyguardUpdateMonitor;
53 import com.android.keyguard.KeyguardUpdateMonitorCallback;
54 import com.android.systemui.EventLogConstants;
55 import com.android.systemui.EventLogTags;
56 import com.android.systemui.Interpolators;
57 import com.android.systemui.R;
58 import com.android.systemui.assist.AssistManager;
59 import com.android.systemui.statusbar.CommandQueue;
60 import com.android.systemui.statusbar.KeyguardAffordanceView;
61 import com.android.systemui.statusbar.KeyguardIndicationController;
62 import com.android.systemui.statusbar.policy.AccessibilityController;
63 import com.android.systemui.statusbar.policy.FlashlightController;
64 import com.android.systemui.statusbar.policy.PreviewInflater;
66 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
67 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
70 * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
73 public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
74 UnlockMethodCache.OnUnlockMethodChangedListener,
75 AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {
77 final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
79 public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance";
80 public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture";
81 public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap";
83 public static final String EXTRA_CAMERA_LAUNCH_SOURCE
84 = "com.android.systemui.camera_launch_source";
86 private static final Intent SECURE_CAMERA_INTENT =
87 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
88 .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
89 public static final Intent INSECURE_CAMERA_INTENT =
90 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
91 private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
92 private static final int DOZE_ANIMATION_STAGGER_DELAY = 48;
93 private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
95 private KeyguardAffordanceView mCameraImageView;
96 private KeyguardAffordanceView mLeftAffordanceView;
97 private LockIcon mLockIcon;
98 private TextView mIndicationText;
99 private ViewGroup mPreviewContainer;
101 private View mLeftPreview;
102 private View mCameraPreview;
104 private ActivityStarter mActivityStarter;
105 private UnlockMethodCache mUnlockMethodCache;
106 private LockPatternUtils mLockPatternUtils;
107 private FlashlightController mFlashlightController;
108 private PreviewInflater mPreviewInflater;
109 private KeyguardIndicationController mIndicationController;
110 private AccessibilityController mAccessibilityController;
111 private PhoneStatusBar mPhoneStatusBar;
113 private boolean mUserSetupComplete;
114 private boolean mPrewarmBound;
115 private Messenger mPrewarmMessenger;
116 private final ServiceConnection mPrewarmConnection = new ServiceConnection() {
119 public void onServiceConnected(ComponentName name, IBinder service) {
120 mPrewarmMessenger = new Messenger(service);
124 public void onServiceDisconnected(ComponentName name) {
125 mPrewarmMessenger = null;
129 private boolean mLeftIsVoiceAssist;
130 private AssistManager mAssistManager;
132 public KeyguardBottomAreaView(Context context) {
136 public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
137 this(context, attrs, 0);
140 public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
141 this(context, attrs, defStyleAttr, 0);
144 public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
146 super(context, attrs, defStyleAttr, defStyleRes);
149 private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
151 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
152 super.onInitializeAccessibilityNodeInfo(host, info);
154 if (host == mLockIcon) {
155 label = getResources().getString(R.string.unlock_label);
156 } else if (host == mCameraImageView) {
157 label = getResources().getString(R.string.camera_label);
158 } else if (host == mLeftAffordanceView) {
159 if (mLeftIsVoiceAssist) {
160 label = getResources().getString(R.string.voice_assist_label);
162 label = getResources().getString(R.string.phone_label);
165 info.addAction(new AccessibilityAction(ACTION_CLICK, label));
169 public boolean performAccessibilityAction(View host, int action, Bundle args) {
170 if (action == ACTION_CLICK) {
171 if (host == mLockIcon) {
172 mPhoneStatusBar.animateCollapsePanels(
173 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
175 } else if (host == mCameraImageView) {
176 launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
178 } else if (host == mLeftAffordanceView) {
179 launchLeftAffordance();
183 return super.performAccessibilityAction(host, action, args);
188 protected void onFinishInflate() {
189 super.onFinishInflate();
190 mLockPatternUtils = new LockPatternUtils(mContext);
191 mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container);
192 mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
193 mLeftAffordanceView = (KeyguardAffordanceView) findViewById(R.id.left_button);
194 mLockIcon = (LockIcon) findViewById(R.id.lock_icon);
195 mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text);
196 watchForCameraPolicyChanges();
197 updateCameraVisibility();
198 mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
199 mUnlockMethodCache.addListener(this);
201 setClipChildren(false);
202 setClipToPadding(false);
203 mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext));
204 inflateCameraPreview();
205 mLockIcon.setOnClickListener(this);
206 mLockIcon.setOnLongClickListener(this);
207 mCameraImageView.setOnClickListener(this);
208 mLeftAffordanceView.setOnClickListener(this);
212 private void initAccessibility() {
213 mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate);
214 mLeftAffordanceView.setAccessibilityDelegate(mAccessibilityDelegate);
215 mCameraImageView.setAccessibilityDelegate(mAccessibilityDelegate);
219 protected void onConfigurationChanged(Configuration newConfig) {
220 super.onConfigurationChanged(newConfig);
221 int indicationBottomMargin = getResources().getDimensionPixelSize(
222 R.dimen.keyguard_indication_margin_bottom);
223 MarginLayoutParams mlp = (MarginLayoutParams) mIndicationText.getLayoutParams();
224 if (mlp.bottomMargin != indicationBottomMargin) {
225 mlp.bottomMargin = indicationBottomMargin;
226 mIndicationText.setLayoutParams(mlp);
229 // Respect font size setting.
230 mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
231 getResources().getDimensionPixelSize(
232 com.android.internal.R.dimen.text_size_small_material));
234 ViewGroup.LayoutParams lp = mCameraImageView.getLayoutParams();
235 lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
236 lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
237 mCameraImageView.setLayoutParams(lp);
238 mCameraImageView.setImageDrawable(mContext.getDrawable(R.drawable.ic_camera_alt_24dp));
240 lp = mLockIcon.getLayoutParams();
241 lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
242 lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
243 mLockIcon.setLayoutParams(lp);
244 mLockIcon.update(true /* force */);
246 lp = mLeftAffordanceView.getLayoutParams();
247 lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
248 lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
249 mLeftAffordanceView.setLayoutParams(lp);
250 updateLeftAffordanceIcon();
253 public void setActivityStarter(ActivityStarter activityStarter) {
254 mActivityStarter = activityStarter;
257 public void setFlashlightController(FlashlightController flashlightController) {
258 mFlashlightController = flashlightController;
261 public void setAccessibilityController(AccessibilityController accessibilityController) {
262 mAccessibilityController = accessibilityController;
263 mLockIcon.setAccessibilityController(accessibilityController);
264 accessibilityController.addStateChangedCallback(this);
267 public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
268 mPhoneStatusBar = phoneStatusBar;
269 updateCameraVisibility(); // in case onFinishInflate() was called too early
272 public void setUserSetupComplete(boolean userSetupComplete) {
273 mUserSetupComplete = userSetupComplete;
274 updateCameraVisibility();
275 updateLeftAffordanceIcon();
278 private Intent getCameraIntent() {
279 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
280 boolean canSkipBouncer = updateMonitor.getUserCanSkipBouncer(
281 KeyguardUpdateMonitor.getCurrentUser());
282 boolean secure = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
283 return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
287 * Resolves the intent to launch the camera application.
289 public ResolveInfo resolveCameraIntent() {
290 return mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
291 PackageManager.MATCH_DEFAULT_ONLY,
292 KeyguardUpdateMonitor.getCurrentUser());
295 private void updateCameraVisibility() {
296 if (mCameraImageView == null) {
297 // Things are not set up yet; reply hazy, ask again later
300 ResolveInfo resolved = resolveCameraIntent();
301 boolean visible = !isCameraDisabledByDpm() && resolved != null
302 && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
303 && mUserSetupComplete;
304 mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
307 private void updateLeftAffordanceIcon() {
308 mLeftIsVoiceAssist = canLaunchVoiceAssist();
310 int contentDescription;
311 boolean visible = mUserSetupComplete;
312 if (mLeftIsVoiceAssist) {
313 drawableId = R.drawable.ic_mic_26dp;
314 contentDescription = R.string.accessibility_voice_assist_button;
316 visible &= isPhoneVisible();
317 drawableId = R.drawable.ic_phone_24dp;
318 contentDescription = R.string.accessibility_phone_button;
320 mLeftAffordanceView.setVisibility(visible ? View.VISIBLE : View.GONE);
321 mLeftAffordanceView.setImageDrawable(mContext.getDrawable(drawableId));
322 mLeftAffordanceView.setContentDescription(mContext.getString(contentDescription));
325 public boolean isLeftVoiceAssist() {
326 return mLeftIsVoiceAssist;
329 private boolean isPhoneVisible() {
330 PackageManager pm = mContext.getPackageManager();
331 return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
332 && pm.resolveActivity(PHONE_INTENT, 0) != null;
335 private boolean isCameraDisabledByDpm() {
336 final DevicePolicyManager dpm =
337 (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
338 if (dpm != null && mPhoneStatusBar != null) {
340 final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
341 final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
342 final boolean disabledBecauseKeyguardSecure =
343 (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
344 && mPhoneStatusBar.isKeyguardSecure();
345 return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
346 } catch (RemoteException e) {
347 Log.e(TAG, "Can't get userId", e);
353 private void watchForCameraPolicyChanges() {
354 final IntentFilter filter = new IntentFilter();
355 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
356 getContext().registerReceiverAsUser(mDevicePolicyReceiver,
357 UserHandle.ALL, filter, null, null);
358 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
362 public void onStateChanged(boolean accessibilityEnabled, boolean touchExplorationEnabled) {
363 mCameraImageView.setClickable(touchExplorationEnabled);
364 mLeftAffordanceView.setClickable(touchExplorationEnabled);
365 mCameraImageView.setFocusable(accessibilityEnabled);
366 mLeftAffordanceView.setFocusable(accessibilityEnabled);
371 public void onClick(View v) {
372 if (v == mCameraImageView) {
373 launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
374 } else if (v == mLeftAffordanceView) {
375 launchLeftAffordance();
376 } if (v == mLockIcon) {
377 if (!mAccessibilityController.isAccessibilityEnabled()) {
378 handleTrustCircleClick();
380 mPhoneStatusBar.animateCollapsePanels(
381 CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
387 public boolean onLongClick(View v) {
388 handleTrustCircleClick();
392 private void handleTrustCircleClick() {
393 EventLogTags.writeSysuiLockscreenGesture(
394 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK, 0 /* lengthDp - N/A */,
395 0 /* velocityDp - N/A */);
396 mIndicationController.showTransientIndication(
397 R.string.keyguard_indication_trust_disabled);
398 mLockPatternUtils.requireCredentialEntry(KeyguardUpdateMonitor.getCurrentUser());
401 public void bindCameraPrewarmService() {
402 Intent intent = getCameraIntent();
403 ActivityInfo targetInfo = PreviewInflater.getTargetActivityInfo(mContext, intent,
404 KeyguardUpdateMonitor.getCurrentUser());
405 if (targetInfo != null && targetInfo.metaData != null) {
406 String clazz = targetInfo.metaData.getString(
407 MediaStore.META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE);
409 Intent serviceIntent = new Intent();
410 serviceIntent.setClassName(targetInfo.packageName, clazz);
411 serviceIntent.setAction(CameraPrewarmService.ACTION_PREWARM);
413 if (getContext().bindServiceAsUser(serviceIntent, mPrewarmConnection,
414 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
415 new UserHandle(UserHandle.USER_CURRENT))) {
416 mPrewarmBound = true;
418 } catch (SecurityException e) {
419 Log.w(TAG, "Unable to bind to prewarm service package=" + targetInfo.packageName
420 + " class=" + clazz, e);
426 public void unbindCameraPrewarmService(boolean launched) {
428 if (mPrewarmMessenger != null && launched) {
430 mPrewarmMessenger.send(Message.obtain(null /* handler */,
431 CameraPrewarmService.MSG_CAMERA_FIRED));
432 } catch (RemoteException e) {
433 Log.w(TAG, "Error sending camera fired message", e);
436 mContext.unbindService(mPrewarmConnection);
437 mPrewarmBound = false;
441 public void launchCamera(String source) {
442 final Intent intent = getCameraIntent();
443 intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source);
444 boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
445 mContext, intent, KeyguardUpdateMonitor.getCurrentUser());
446 if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
447 AsyncTask.execute(new Runnable() {
450 int result = ActivityManager.START_CANCELED;
452 result = ActivityManagerNative.getDefault().startActivityAsUser(
453 null, getContext().getBasePackageName(),
455 intent.resolveTypeIfNeeded(getContext().getContentResolver()),
456 null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
457 UserHandle.CURRENT.getIdentifier());
458 } catch (RemoteException e) {
459 Log.w(TAG, "Unable to start camera activity", e);
461 mActivityStarter.preventNextAnimation();
462 final boolean launched = isSuccessfulLaunch(result);
463 post(new Runnable() {
466 unbindCameraPrewarmService(launched);
473 // We need to delay starting the activity because ResolverActivity finishes itself if
474 // launched behind lockscreen.
475 mActivityStarter.startActivity(intent, false /* dismissShade */,
476 new ActivityStarter.Callback() {
478 public void onActivityStarted(int resultCode) {
479 unbindCameraPrewarmService(isSuccessfulLaunch(resultCode));
485 private static boolean isSuccessfulLaunch(int result) {
486 return result == ActivityManager.START_SUCCESS
487 || result == ActivityManager.START_DELIVERED_TO_TOP
488 || result == ActivityManager.START_TASK_TO_FRONT;
491 public void launchLeftAffordance() {
492 if (mLeftIsVoiceAssist) {
499 private void launchVoiceAssist() {
500 Runnable runnable = new Runnable() {
503 mAssistManager.launchVoiceAssistFromKeyguard();
504 mActivityStarter.preventNextAnimation();
507 if (mPhoneStatusBar.isKeyguardCurrentlySecure()) {
508 AsyncTask.execute(runnable);
510 mPhoneStatusBar.executeRunnableDismissingKeyguard(runnable, null /* cancelAction */,
511 false /* dismissShade */, false /* afterKeyguardGone */, true /* deferred */);
515 private boolean canLaunchVoiceAssist() {
516 return mAssistManager.canVoiceAssistBeLaunchedFromKeyguard();
519 private void launchPhone() {
520 final TelecomManager tm = TelecomManager.from(mContext);
522 AsyncTask.execute(new Runnable() {
525 tm.showInCallScreen(false /* showDialpad */);
529 mActivityStarter.startActivity(PHONE_INTENT, false /* dismissShade */);
535 protected void onVisibilityChanged(View changedView, int visibility) {
536 super.onVisibilityChanged(changedView, visibility);
537 if (changedView == this && visibility == VISIBLE) {
539 updateCameraVisibility();
543 public KeyguardAffordanceView getLeftView() {
544 return mLeftAffordanceView;
547 public KeyguardAffordanceView getRightView() {
548 return mCameraImageView;
551 public View getLeftPreview() {
555 public View getRightPreview() {
556 return mCameraPreview;
559 public LockIcon getLockIcon() {
563 public View getIndicationView() {
564 return mIndicationText;
568 public boolean hasOverlappingRendering() {
573 public void onUnlockMethodStateChanged() {
575 updateCameraVisibility();
578 private void inflateCameraPreview() {
579 mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent());
580 if (mCameraPreview != null) {
581 mPreviewContainer.addView(mCameraPreview);
582 mCameraPreview.setVisibility(View.INVISIBLE);
586 private void updateLeftPreview() {
587 View previewBefore = mLeftPreview;
588 if (previewBefore != null) {
589 mPreviewContainer.removeView(previewBefore);
591 if (mLeftIsVoiceAssist) {
592 mLeftPreview = mPreviewInflater.inflatePreviewFromService(
593 mAssistManager.getVoiceInteractorComponentName());
595 mLeftPreview = mPreviewInflater.inflatePreview(PHONE_INTENT);
597 if (mLeftPreview != null) {
598 mPreviewContainer.addView(mLeftPreview);
599 mLeftPreview.setVisibility(View.INVISIBLE);
603 public void startFinishDozeAnimation() {
605 if (mLeftAffordanceView.getVisibility() == View.VISIBLE) {
606 startFinishDozeAnimationElement(mLeftAffordanceView, delay);
607 delay += DOZE_ANIMATION_STAGGER_DELAY;
609 startFinishDozeAnimationElement(mLockIcon, delay);
610 delay += DOZE_ANIMATION_STAGGER_DELAY;
611 if (mCameraImageView.getVisibility() == View.VISIBLE) {
612 startFinishDozeAnimationElement(mCameraImageView, delay);
614 mIndicationText.setAlpha(0f);
615 mIndicationText.animate()
617 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
618 .setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
621 private void startFinishDozeAnimationElement(View element, long delay) {
622 element.setAlpha(0f);
623 element.setTranslationY(element.getHeight() / 2);
627 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
628 .setStartDelay(delay)
629 .setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
632 private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() {
634 public void onReceive(Context context, Intent intent) {
635 post(new Runnable() {
638 updateCameraVisibility();
644 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
645 new KeyguardUpdateMonitorCallback() {
647 public void onUserSwitchComplete(int userId) {
648 updateCameraVisibility();
652 public void onStartedWakingUp() {
653 mLockIcon.setDeviceInteractive(true);
657 public void onFinishedGoingToSleep(int why) {
658 mLockIcon.setDeviceInteractive(false);
662 public void onScreenTurnedOn() {
663 mLockIcon.setScreenOn(true);
667 public void onScreenTurnedOff() {
668 mLockIcon.setScreenOn(false);
672 public void onKeyguardVisibilityChanged(boolean showing) {
677 public void onFingerprintRunningStateChanged(boolean running) {
682 public void onStrongAuthStateChanged(int userId) {
687 public void setKeyguardIndicationController(
688 KeyguardIndicationController keyguardIndicationController) {
689 mIndicationController = keyguardIndicationController;
692 public void setAssistManager(AssistManager assistManager) {
693 mAssistManager = assistManager;
694 updateLeftAffordance();
697 public void updateLeftAffordance() {
698 updateLeftAffordanceIcon();