Home | History | Annotate | Download | only in phone
      1 /*
      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 
     17 package com.android.systemui.statusbar.phone;
     18 
     19 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
     20 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
     21 
     22 import android.app.ActivityManager;
     23 import android.app.ActivityManagerNative;
     24 import android.app.ActivityOptions;
     25 import android.app.admin.DevicePolicyManager;
     26 import android.content.BroadcastReceiver;
     27 import android.content.ComponentName;
     28 import android.content.Context;
     29 import android.content.Intent;
     30 import android.content.IntentFilter;
     31 import android.content.ServiceConnection;
     32 import android.content.pm.ActivityInfo;
     33 import android.content.pm.PackageManager;
     34 import android.content.pm.ResolveInfo;
     35 import android.content.res.Configuration;
     36 import android.os.AsyncTask;
     37 import android.os.Bundle;
     38 import android.os.IBinder;
     39 import android.os.Message;
     40 import android.os.Messenger;
     41 import android.os.RemoteException;
     42 import android.os.UserHandle;
     43 import android.provider.MediaStore;
     44 import android.service.media.CameraPrewarmService;
     45 import android.telecom.TelecomManager;
     46 import android.util.AttributeSet;
     47 import android.util.Log;
     48 import android.util.TypedValue;
     49 import android.view.View;
     50 import android.view.ViewGroup;
     51 import android.view.WindowManager;
     52 import android.view.accessibility.AccessibilityNodeInfo;
     53 import android.widget.FrameLayout;
     54 import android.widget.TextView;
     55 
     56 import com.android.internal.widget.LockPatternUtils;
     57 import com.android.keyguard.KeyguardUpdateMonitor;
     58 import com.android.keyguard.KeyguardUpdateMonitorCallback;
     59 import com.android.systemui.EventLogConstants;
     60 import com.android.systemui.EventLogTags;
     61 import com.android.systemui.Interpolators;
     62 import com.android.systemui.R;
     63 import com.android.systemui.assist.AssistManager;
     64 import com.android.systemui.statusbar.CommandQueue;
     65 import com.android.systemui.statusbar.KeyguardAffordanceView;
     66 import com.android.systemui.statusbar.KeyguardIndicationController;
     67 import com.android.systemui.statusbar.policy.AccessibilityController;
     68 import com.android.systemui.statusbar.policy.FlashlightController;
     69 import com.android.systemui.statusbar.policy.PreviewInflater;
     70 
     71 /**
     72  * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
     73  * text.
     74  */
     75 public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
     76         UnlockMethodCache.OnUnlockMethodChangedListener,
     77         AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {
     78 
     79     final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
     80 
     81     public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance";
     82     public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture";
     83     public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap";
     84 
     85     public static final String EXTRA_CAMERA_LAUNCH_SOURCE
     86             = "com.android.systemui.camera_launch_source";
     87 
     88     private static final Intent SECURE_CAMERA_INTENT =
     89             new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
     90                     .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
     91     public static final Intent INSECURE_CAMERA_INTENT =
     92             new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
     93     private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
     94     private static final int DOZE_ANIMATION_STAGGER_DELAY = 48;
     95     private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
     96 
     97     private KeyguardAffordanceView mCameraImageView;
     98     private KeyguardAffordanceView mLeftAffordanceView;
     99     private LockIcon mLockIcon;
    100     private TextView mIndicationText;
    101     private ViewGroup mPreviewContainer;
    102 
    103     private View mLeftPreview;
    104     private View mCameraPreview;
    105 
    106     private ActivityStarter mActivityStarter;
    107     private UnlockMethodCache mUnlockMethodCache;
    108     private LockPatternUtils mLockPatternUtils;
    109     private FlashlightController mFlashlightController;
    110     private PreviewInflater mPreviewInflater;
    111     private KeyguardIndicationController mIndicationController;
    112     private AccessibilityController mAccessibilityController;
    113     private PhoneStatusBar mPhoneStatusBar;
    114 
    115     private boolean mUserSetupComplete;
    116     private boolean mPrewarmBound;
    117     private Messenger mPrewarmMessenger;
    118     private final ServiceConnection mPrewarmConnection = new ServiceConnection() {
    119 
    120         @Override
    121         public void onServiceConnected(ComponentName name, IBinder service) {
    122             mPrewarmMessenger = new Messenger(service);
    123         }
    124 
    125         @Override
    126         public void onServiceDisconnected(ComponentName name) {
    127             mPrewarmMessenger = null;
    128         }
    129     };
    130 
    131     private boolean mLeftIsVoiceAssist;
    132     private AssistManager mAssistManager;
    133 
    134     public KeyguardBottomAreaView(Context context) {
    135         this(context, null);
    136     }
    137 
    138     public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
    139         this(context, attrs, 0);
    140     }
    141 
    142     public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
    143         this(context, attrs, defStyleAttr, 0);
    144     }
    145 
    146     public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
    147             int defStyleRes) {
    148         super(context, attrs, defStyleAttr, defStyleRes);
    149     }
    150 
    151     private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
    152         @Override
    153         public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
    154             super.onInitializeAccessibilityNodeInfo(host, info);
    155             String label = null;
    156             if (host == mLockIcon) {
    157                 label = getResources().getString(R.string.unlock_label);
    158             } else if (host == mCameraImageView) {
    159                 label = getResources().getString(R.string.camera_label);
    160             } else if (host == mLeftAffordanceView) {
    161                 if (mLeftIsVoiceAssist) {
    162                     label = getResources().getString(R.string.voice_assist_label);
    163                 } else {
    164                     label = getResources().getString(R.string.phone_label);
    165                 }
    166             }
    167             info.addAction(new AccessibilityAction(ACTION_CLICK, label));
    168         }
    169 
    170         @Override
    171         public boolean performAccessibilityAction(View host, int action, Bundle args) {
    172             if (action == ACTION_CLICK) {
    173                 if (host == mLockIcon) {
    174                     mPhoneStatusBar.animateCollapsePanels(
    175                             CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
    176                     return true;
    177                 } else if (host == mCameraImageView) {
    178                     launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
    179                     return true;
    180                 } else if (host == mLeftAffordanceView) {
    181                     launchLeftAffordance();
    182                     return true;
    183                 }
    184             }
    185             return super.performAccessibilityAction(host, action, args);
    186         }
    187     };
    188 
    189     @Override
    190     protected void onFinishInflate() {
    191         super.onFinishInflate();
    192         mLockPatternUtils = new LockPatternUtils(mContext);
    193         mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container);
    194         mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
    195         mLeftAffordanceView = (KeyguardAffordanceView) findViewById(R.id.left_button);
    196         mLockIcon = (LockIcon) findViewById(R.id.lock_icon);
    197         mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text);
    198         watchForCameraPolicyChanges();
    199         updateCameraVisibility();
    200         mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
    201         mUnlockMethodCache.addListener(this);
    202         mLockIcon.update();
    203         setClipChildren(false);
    204         setClipToPadding(false);
    205         mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext));
    206         inflateCameraPreview();
    207         mLockIcon.setOnClickListener(this);
    208         mLockIcon.setOnLongClickListener(this);
    209         mCameraImageView.setOnClickListener(this);
    210         mLeftAffordanceView.setOnClickListener(this);
    211         initAccessibility();
    212     }
    213 
    214     private void initAccessibility() {
    215         mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate);
    216         mLeftAffordanceView.setAccessibilityDelegate(mAccessibilityDelegate);
    217         mCameraImageView.setAccessibilityDelegate(mAccessibilityDelegate);
    218     }
    219 
    220     @Override
    221     protected void onConfigurationChanged(Configuration newConfig) {
    222         super.onConfigurationChanged(newConfig);
    223         int indicationBottomMargin = getResources().getDimensionPixelSize(
    224                 R.dimen.keyguard_indication_margin_bottom);
    225         MarginLayoutParams mlp = (MarginLayoutParams) mIndicationText.getLayoutParams();
    226         if (mlp.bottomMargin != indicationBottomMargin) {
    227             mlp.bottomMargin = indicationBottomMargin;
    228             mIndicationText.setLayoutParams(mlp);
    229         }
    230 
    231         // Respect font size setting.
    232         mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
    233                 getResources().getDimensionPixelSize(
    234                         com.android.internal.R.dimen.text_size_small_material));
    235 
    236         ViewGroup.LayoutParams lp = mCameraImageView.getLayoutParams();
    237         lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
    238         lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
    239         mCameraImageView.setLayoutParams(lp);
    240         mCameraImageView.setImageDrawable(mContext.getDrawable(R.drawable.ic_camera_alt_24dp));
    241 
    242         lp = mLockIcon.getLayoutParams();
    243         lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
    244         lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
    245         mLockIcon.setLayoutParams(lp);
    246         mLockIcon.update(true /* force */);
    247 
    248         lp = mLeftAffordanceView.getLayoutParams();
    249         lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
    250         lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
    251         mLeftAffordanceView.setLayoutParams(lp);
    252         updateLeftAffordanceIcon();
    253     }
    254 
    255     public void setActivityStarter(ActivityStarter activityStarter) {
    256         mActivityStarter = activityStarter;
    257     }
    258 
    259     public void setFlashlightController(FlashlightController flashlightController) {
    260         mFlashlightController = flashlightController;
    261     }
    262 
    263     public void setAccessibilityController(AccessibilityController accessibilityController) {
    264         mAccessibilityController = accessibilityController;
    265         mLockIcon.setAccessibilityController(accessibilityController);
    266         accessibilityController.addStateChangedCallback(this);
    267     }
    268 
    269     public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
    270         mPhoneStatusBar = phoneStatusBar;
    271         updateCameraVisibility(); // in case onFinishInflate() was called too early
    272     }
    273 
    274     public void setUserSetupComplete(boolean userSetupComplete) {
    275         mUserSetupComplete = userSetupComplete;
    276         updateCameraVisibility();
    277         updateLeftAffordanceIcon();
    278     }
    279 
    280     private Intent getCameraIntent() {
    281         KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
    282         boolean canSkipBouncer = updateMonitor.getUserCanSkipBouncer(
    283                 KeyguardUpdateMonitor.getCurrentUser());
    284         boolean secure = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
    285         return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
    286     }
    287 
    288     /**
    289      * Resolves the intent to launch the camera application.
    290      */
    291     public ResolveInfo resolveCameraIntent() {
    292         return mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
    293                 PackageManager.MATCH_DEFAULT_ONLY,
    294                 KeyguardUpdateMonitor.getCurrentUser());
    295     }
    296 
    297     private void updateCameraVisibility() {
    298         if (mCameraImageView == null) {
    299             // Things are not set up yet; reply hazy, ask again later
    300             return;
    301         }
    302         ResolveInfo resolved = resolveCameraIntent();
    303         boolean visible = !isCameraDisabledByDpm() && resolved != null
    304                 && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
    305                 && mUserSetupComplete;
    306         mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
    307     }
    308 
    309     private void updateLeftAffordanceIcon() {
    310         mLeftIsVoiceAssist = canLaunchVoiceAssist();
    311         int drawableId;
    312         int contentDescription;
    313         boolean visible = mUserSetupComplete;
    314         if (mLeftIsVoiceAssist) {
    315             drawableId = R.drawable.ic_mic_26dp;
    316             contentDescription = R.string.accessibility_voice_assist_button;
    317         } else {
    318             visible &= isPhoneVisible();
    319             drawableId = R.drawable.ic_phone_24dp;
    320             contentDescription = R.string.accessibility_phone_button;
    321         }
    322         mLeftAffordanceView.setVisibility(visible ? View.VISIBLE : View.GONE);
    323         mLeftAffordanceView.setImageDrawable(mContext.getDrawable(drawableId));
    324         mLeftAffordanceView.setContentDescription(mContext.getString(contentDescription));
    325     }
    326 
    327     public boolean isLeftVoiceAssist() {
    328         return mLeftIsVoiceAssist;
    329     }
    330 
    331     private boolean isPhoneVisible() {
    332         PackageManager pm = mContext.getPackageManager();
    333         return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
    334                 && pm.resolveActivity(PHONE_INTENT, 0) != null;
    335     }
    336 
    337     private boolean isCameraDisabledByDpm() {
    338         final DevicePolicyManager dpm =
    339                 (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
    340         if (dpm != null && mPhoneStatusBar != null) {
    341             try {
    342                 final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
    343                 final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
    344                 final  boolean disabledBecauseKeyguardSecure =
    345                         (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
    346                                 && mPhoneStatusBar.isKeyguardSecure();
    347                 return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
    348             } catch (RemoteException e) {
    349                 Log.e(TAG, "Can't get userId", e);
    350             }
    351         }
    352         return false;
    353     }
    354 
    355     private void watchForCameraPolicyChanges() {
    356         final IntentFilter filter = new IntentFilter();
    357         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    358         getContext().registerReceiverAsUser(mDevicePolicyReceiver,
    359                 UserHandle.ALL, filter, null, null);
    360         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
    361     }
    362 
    363     @Override
    364     public void onStateChanged(boolean accessibilityEnabled, boolean touchExplorationEnabled) {
    365         mCameraImageView.setClickable(touchExplorationEnabled);
    366         mLeftAffordanceView.setClickable(touchExplorationEnabled);
    367         mCameraImageView.setFocusable(accessibilityEnabled);
    368         mLeftAffordanceView.setFocusable(accessibilityEnabled);
    369         mLockIcon.update();
    370     }
    371 
    372     @Override
    373     public void onClick(View v) {
    374         if (v == mCameraImageView) {
    375             launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
    376         } else if (v == mLeftAffordanceView) {
    377             launchLeftAffordance();
    378         } if (v == mLockIcon) {
    379             if (!mAccessibilityController.isAccessibilityEnabled()) {
    380                 handleTrustCircleClick();
    381             } else {
    382                 mPhoneStatusBar.animateCollapsePanels(
    383                         CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
    384             }
    385         }
    386     }
    387 
    388     @Override
    389     public boolean onLongClick(View v) {
    390         handleTrustCircleClick();
    391         return true;
    392     }
    393 
    394     private void handleTrustCircleClick() {
    395         EventLogTags.writeSysuiLockscreenGesture(
    396                 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK, 0 /* lengthDp - N/A */,
    397                 0 /* velocityDp - N/A */);
    398         mIndicationController.showTransientIndication(
    399                 R.string.keyguard_indication_trust_disabled);
    400         mLockPatternUtils.requireCredentialEntry(KeyguardUpdateMonitor.getCurrentUser());
    401     }
    402 
    403     public void bindCameraPrewarmService() {
    404         Intent intent = getCameraIntent();
    405         ActivityInfo targetInfo = PreviewInflater.getTargetActivityInfo(mContext, intent,
    406                 KeyguardUpdateMonitor.getCurrentUser(), true /* onlyDirectBootAware */);
    407         if (targetInfo != null && targetInfo.metaData != null) {
    408             String clazz = targetInfo.metaData.getString(
    409                     MediaStore.META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE);
    410             if (clazz != null) {
    411                 Intent serviceIntent = new Intent();
    412                 serviceIntent.setClassName(targetInfo.packageName, clazz);
    413                 serviceIntent.setAction(CameraPrewarmService.ACTION_PREWARM);
    414                 try {
    415                     if (getContext().bindServiceAsUser(serviceIntent, mPrewarmConnection,
    416                             Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
    417                             new UserHandle(UserHandle.USER_CURRENT))) {
    418                         mPrewarmBound = true;
    419                     }
    420                 } catch (SecurityException e) {
    421                     Log.w(TAG, "Unable to bind to prewarm service package=" + targetInfo.packageName
    422                             + " class=" + clazz, e);
    423                 }
    424             }
    425         }
    426     }
    427 
    428     public void unbindCameraPrewarmService(boolean launched) {
    429         if (mPrewarmBound) {
    430             if (mPrewarmMessenger != null && launched) {
    431                 try {
    432                     mPrewarmMessenger.send(Message.obtain(null /* handler */,
    433                             CameraPrewarmService.MSG_CAMERA_FIRED));
    434                 } catch (RemoteException e) {
    435                     Log.w(TAG, "Error sending camera fired message", e);
    436                 }
    437             }
    438             mContext.unbindService(mPrewarmConnection);
    439             mPrewarmBound = false;
    440         }
    441     }
    442 
    443     public void launchCamera(String source) {
    444         final Intent intent = getCameraIntent();
    445         intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source);
    446         boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
    447                 mContext, intent, KeyguardUpdateMonitor.getCurrentUser());
    448         if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
    449             AsyncTask.execute(new Runnable() {
    450                 @Override
    451                 public void run() {
    452                     int result = ActivityManager.START_CANCELED;
    453 
    454                     // Normally an activity will set it's requested rotation
    455                     // animation on its window. However when launching an activity
    456                     // causes the orientation to change this is too late. In these cases
    457                     // the default animation is used. This doesn't look good for
    458                     // the camera (as it rotates the camera contents out of sync
    459                     // with physical reality). So, we ask the WindowManager to
    460                     // force the crossfade animation if an orientation change
    461                     // happens to occur during the launch.
    462                     ActivityOptions o = ActivityOptions.makeBasic();
    463                     o.setRotationAnimationHint(
    464                             WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
    465                     try {
    466                         result = ActivityManagerNative.getDefault().startActivityAsUser(
    467                                 null, getContext().getBasePackageName(),
    468                                 intent,
    469                                 intent.resolveTypeIfNeeded(getContext().getContentResolver()),
    470                                 null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, o.toBundle(),
    471                                 UserHandle.CURRENT.getIdentifier());
    472                     } catch (RemoteException e) {
    473                         Log.w(TAG, "Unable to start camera activity", e);
    474                     }
    475                     mActivityStarter.preventNextAnimation();
    476                     final boolean launched = isSuccessfulLaunch(result);
    477                     post(new Runnable() {
    478                         @Override
    479                         public void run() {
    480                             unbindCameraPrewarmService(launched);
    481                         }
    482                     });
    483                 }
    484             });
    485         } else {
    486 
    487             // We need to delay starting the activity because ResolverActivity finishes itself if
    488             // launched behind lockscreen.
    489             mActivityStarter.startActivity(intent, false /* dismissShade */,
    490                     new ActivityStarter.Callback() {
    491                         @Override
    492                         public void onActivityStarted(int resultCode) {
    493                             unbindCameraPrewarmService(isSuccessfulLaunch(resultCode));
    494                         }
    495                     });
    496         }
    497     }
    498 
    499     private static boolean isSuccessfulLaunch(int result) {
    500         return result == ActivityManager.START_SUCCESS
    501                 || result == ActivityManager.START_DELIVERED_TO_TOP
    502                 || result == ActivityManager.START_TASK_TO_FRONT;
    503     }
    504 
    505     public void launchLeftAffordance() {
    506         if (mLeftIsVoiceAssist) {
    507             launchVoiceAssist();
    508         } else {
    509             launchPhone();
    510         }
    511     }
    512 
    513     private void launchVoiceAssist() {
    514         Runnable runnable = new Runnable() {
    515             @Override
    516             public void run() {
    517                 mAssistManager.launchVoiceAssistFromKeyguard();
    518                 mActivityStarter.preventNextAnimation();
    519             }
    520         };
    521         if (mPhoneStatusBar.isKeyguardCurrentlySecure()) {
    522             AsyncTask.execute(runnable);
    523         } else {
    524             mPhoneStatusBar.executeRunnableDismissingKeyguard(runnable, null /* cancelAction */,
    525                     false /* dismissShade */, false /* afterKeyguardGone */, true /* deferred */);
    526         }
    527     }
    528 
    529     private boolean canLaunchVoiceAssist() {
    530         return mAssistManager.canVoiceAssistBeLaunchedFromKeyguard();
    531     }
    532 
    533     private void launchPhone() {
    534         final TelecomManager tm = TelecomManager.from(mContext);
    535         if (tm.isInCall()) {
    536             AsyncTask.execute(new Runnable() {
    537                 @Override
    538                 public void run() {
    539                     tm.showInCallScreen(false /* showDialpad */);
    540                 }
    541             });
    542         } else {
    543             mActivityStarter.startActivity(PHONE_INTENT, false /* dismissShade */);
    544         }
    545     }
    546 
    547 
    548     @Override
    549     protected void onVisibilityChanged(View changedView, int visibility) {
    550         super.onVisibilityChanged(changedView, visibility);
    551         if (changedView == this && visibility == VISIBLE) {
    552             mLockIcon.update();
    553             updateCameraVisibility();
    554         }
    555     }
    556 
    557     public KeyguardAffordanceView getLeftView() {
    558         return mLeftAffordanceView;
    559     }
    560 
    561     public KeyguardAffordanceView getRightView() {
    562         return mCameraImageView;
    563     }
    564 
    565     public View getLeftPreview() {
    566         return mLeftPreview;
    567     }
    568 
    569     public View getRightPreview() {
    570         return mCameraPreview;
    571     }
    572 
    573     public LockIcon getLockIcon() {
    574         return mLockIcon;
    575     }
    576 
    577     public View getIndicationView() {
    578         return mIndicationText;
    579     }
    580 
    581     @Override
    582     public boolean hasOverlappingRendering() {
    583         return false;
    584     }
    585 
    586     @Override
    587     public void onUnlockMethodStateChanged() {
    588         mLockIcon.update();
    589         updateCameraVisibility();
    590     }
    591 
    592     private void inflateCameraPreview() {
    593         View previewBefore = mCameraPreview;
    594         boolean visibleBefore = false;
    595         if (previewBefore != null) {
    596             mPreviewContainer.removeView(previewBefore);
    597             visibleBefore = previewBefore.getVisibility() == View.VISIBLE;
    598         }
    599         mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent());
    600         if (mCameraPreview != null) {
    601             mPreviewContainer.addView(mCameraPreview);
    602             mCameraPreview.setVisibility(visibleBefore ? View.VISIBLE : View.INVISIBLE);
    603         }
    604     }
    605 
    606     private void updateLeftPreview() {
    607         View previewBefore = mLeftPreview;
    608         if (previewBefore != null) {
    609             mPreviewContainer.removeView(previewBefore);
    610         }
    611         if (mLeftIsVoiceAssist) {
    612             mLeftPreview = mPreviewInflater.inflatePreviewFromService(
    613                     mAssistManager.getVoiceInteractorComponentName());
    614         } else {
    615             mLeftPreview = mPreviewInflater.inflatePreview(PHONE_INTENT);
    616         }
    617         if (mLeftPreview != null) {
    618             mPreviewContainer.addView(mLeftPreview);
    619             mLeftPreview.setVisibility(View.INVISIBLE);
    620         }
    621     }
    622 
    623     public void startFinishDozeAnimation() {
    624         long delay = 0;
    625         if (mLeftAffordanceView.getVisibility() == View.VISIBLE) {
    626             startFinishDozeAnimationElement(mLeftAffordanceView, delay);
    627             delay += DOZE_ANIMATION_STAGGER_DELAY;
    628         }
    629         startFinishDozeAnimationElement(mLockIcon, delay);
    630         delay += DOZE_ANIMATION_STAGGER_DELAY;
    631         if (mCameraImageView.getVisibility() == View.VISIBLE) {
    632             startFinishDozeAnimationElement(mCameraImageView, delay);
    633         }
    634         mIndicationText.setAlpha(0f);
    635         mIndicationText.animate()
    636                 .alpha(1f)
    637                 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
    638                 .setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
    639     }
    640 
    641     private void startFinishDozeAnimationElement(View element, long delay) {
    642         element.setAlpha(0f);
    643         element.setTranslationY(element.getHeight() / 2);
    644         element.animate()
    645                 .alpha(1f)
    646                 .translationY(0f)
    647                 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
    648                 .setStartDelay(delay)
    649                 .setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
    650     }
    651 
    652     private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() {
    653         @Override
    654         public void onReceive(Context context, Intent intent) {
    655             post(new Runnable() {
    656                 @Override
    657                 public void run() {
    658                     updateCameraVisibility();
    659                 }
    660             });
    661         }
    662     };
    663 
    664     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
    665             new KeyguardUpdateMonitorCallback() {
    666         @Override
    667         public void onUserSwitchComplete(int userId) {
    668             updateCameraVisibility();
    669         }
    670 
    671         @Override
    672         public void onStartedWakingUp() {
    673             mLockIcon.setDeviceInteractive(true);
    674         }
    675 
    676         @Override
    677         public void onFinishedGoingToSleep(int why) {
    678             mLockIcon.setDeviceInteractive(false);
    679         }
    680 
    681         @Override
    682         public void onScreenTurnedOn() {
    683             mLockIcon.setScreenOn(true);
    684         }
    685 
    686         @Override
    687         public void onScreenTurnedOff() {
    688             mLockIcon.setScreenOn(false);
    689         }
    690 
    691         @Override
    692         public void onKeyguardVisibilityChanged(boolean showing) {
    693             mLockIcon.update();
    694         }
    695 
    696         @Override
    697         public void onFingerprintRunningStateChanged(boolean running) {
    698             mLockIcon.update();
    699         }
    700 
    701         @Override
    702         public void onStrongAuthStateChanged(int userId) {
    703             mLockIcon.update();
    704         }
    705     };
    706 
    707     public void setKeyguardIndicationController(
    708             KeyguardIndicationController keyguardIndicationController) {
    709         mIndicationController = keyguardIndicationController;
    710     }
    711 
    712     public void setAssistManager(AssistManager assistManager) {
    713         mAssistManager = assistManager;
    714         updateLeftAffordance();
    715     }
    716 
    717     public void updateLeftAffordance() {
    718         updateLeftAffordanceIcon();
    719         updateLeftPreview();
    720     }
    721 
    722     public void onKeyguardShowingChanged() {
    723         updateLeftAffordance();
    724         inflateCameraPreview();
    725     }
    726 }
    727