KeyguardBottomAreaView.java revision 4ebcdfdd4294cc52a68fb150bc7a34f005290ea3
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 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; 25import android.content.pm.PackageManager; 26import android.content.pm.ResolveInfo; 27import android.os.RemoteException; 28import android.os.UserHandle; 29import android.provider.MediaStore; 30import android.util.AttributeSet; 31import android.util.Log; 32import android.view.View; 33import android.view.ViewGroup; 34import android.view.accessibility.AccessibilityManager; 35import android.widget.FrameLayout; 36 37import com.android.internal.widget.LockPatternUtils; 38import com.android.keyguard.KeyguardUpdateMonitor; 39import com.android.keyguard.KeyguardUpdateMonitorCallback; 40import com.android.systemui.R; 41import com.android.systemui.statusbar.KeyguardIndicationController; 42import com.android.systemui.statusbar.policy.FlashlightController; 43import com.android.systemui.statusbar.KeyguardAffordanceView; 44import com.android.systemui.statusbar.policy.PreviewInflater; 45 46/** 47 * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status 48 * text. 49 */ 50public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener, 51 UnlockMethodCache.OnUnlockMethodChangedListener { 52 53 final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView"; 54 55 private static final Intent SECURE_CAMERA_INTENT = 56 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE) 57 .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 58 private static final Intent INSECURE_CAMERA_INTENT = 59 new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); 60 private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL); 61 62 private KeyguardAffordanceView mCameraImageView; 63 private KeyguardAffordanceView mPhoneImageView; 64 private KeyguardAffordanceView mLockIcon; 65 private View mIndicationText; 66 private ViewGroup mPreviewContainer; 67 68 private View mPhonePreview; 69 private View mCameraPreview; 70 71 private ActivityStarter mActivityStarter; 72 private UnlockMethodCache mUnlockMethodCache; 73 private LockPatternUtils mLockPatternUtils; 74 private FlashlightController mFlashlightController; 75 private PreviewInflater mPreviewInflater; 76 private KeyguardIndicationController mIndicationController; 77 private boolean mFaceUnlockRunning; 78 79 public KeyguardBottomAreaView(Context context) { 80 super(context); 81 } 82 83 public KeyguardBottomAreaView(Context context, AttributeSet attrs) { 84 super(context, attrs); 85 } 86 87 public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) { 88 super(context, attrs, defStyleAttr); 89 } 90 91 public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr, 92 int defStyleRes) { 93 super(context, attrs, defStyleAttr, defStyleRes); 94 } 95 96 @Override 97 protected void onFinishInflate() { 98 super.onFinishInflate(); 99 mLockPatternUtils = new LockPatternUtils(mContext); 100 mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container); 101 mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button); 102 mPhoneImageView = (KeyguardAffordanceView) findViewById(R.id.phone_button); 103 mLockIcon = (KeyguardAffordanceView) findViewById(R.id.lock_icon); 104 mIndicationText = findViewById(R.id.keyguard_indication_text); 105 watchForCameraPolicyChanges(); 106 watchForAccessibilityChanges(); 107 updateCameraVisibility(); 108 updatePhoneVisibility(); 109 mUnlockMethodCache = UnlockMethodCache.getInstance(getContext()); 110 mUnlockMethodCache.addListener(this); 111 updateLockIcon(); 112 setClipChildren(false); 113 setClipToPadding(false); 114 mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext)); 115 inflatePreviews(); 116 mLockIcon.setOnClickListener(this); 117 } 118 119 public void setActivityStarter(ActivityStarter activityStarter) { 120 mActivityStarter = activityStarter; 121 } 122 123 public void setFlashlightController(FlashlightController flashlightController) { 124 mFlashlightController = flashlightController; 125 } 126 127 private Intent getCameraIntent() { 128 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); 129 boolean currentUserHasTrust = updateMonitor.getUserHasTrust( 130 mLockPatternUtils.getCurrentUser()); 131 return mLockPatternUtils.isSecure() && !currentUserHasTrust 132 ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT; 133 } 134 135 private void updateCameraVisibility() { 136 ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(), 137 PackageManager.MATCH_DEFAULT_ONLY, 138 mLockPatternUtils.getCurrentUser()); 139 boolean visible = !isCameraDisabledByDpm() && resolved != null; 140 mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE); 141 } 142 143 private void updatePhoneVisibility() { 144 boolean visible = isPhoneVisible(); 145 mPhoneImageView.setVisibility(visible ? View.VISIBLE : View.GONE); 146 } 147 148 private boolean isPhoneVisible() { 149 PackageManager pm = mContext.getPackageManager(); 150 return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) 151 && pm.resolveActivity(PHONE_INTENT, 0) != null; 152 } 153 154 private boolean isCameraDisabledByDpm() { 155 final DevicePolicyManager dpm = 156 (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE); 157 if (dpm != null) { 158 try { 159 final int userId = ActivityManagerNative.getDefault().getCurrentUser().id; 160 final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId); 161 final boolean disabledBecauseKeyguardSecure = 162 (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0 163 && KeyguardTouchDelegate.getInstance(getContext()).isSecure(); 164 return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure; 165 } catch (RemoteException e) { 166 Log.e(TAG, "Can't get userId", e); 167 } 168 } 169 return false; 170 } 171 172 private void watchForCameraPolicyChanges() { 173 final IntentFilter filter = new IntentFilter(); 174 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 175 getContext().registerReceiverAsUser(mDevicePolicyReceiver, 176 UserHandle.ALL, filter, null, null); 177 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback); 178 } 179 180 private void watchForAccessibilityChanges() { 181 final AccessibilityManager am = 182 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 183 184 // Set the initial state 185 enableAccessibility(am.isTouchExplorationEnabled()); 186 187 // Watch for changes 188 am.addTouchExplorationStateChangeListener( 189 new AccessibilityManager.TouchExplorationStateChangeListener() { 190 @Override 191 public void onTouchExplorationStateChanged(boolean enabled) { 192 enableAccessibility(enabled); 193 } 194 }); 195 } 196 197 private void enableAccessibility(boolean touchExplorationEnabled) { 198 mCameraImageView.setOnClickListener(touchExplorationEnabled ? this : null); 199 mCameraImageView.setClickable(touchExplorationEnabled); 200 mPhoneImageView.setOnClickListener(touchExplorationEnabled ? this : null); 201 mPhoneImageView.setClickable(touchExplorationEnabled); 202 } 203 204 @Override 205 public void onClick(View v) { 206 if (v == mCameraImageView) { 207 launchCamera(); 208 } else if (v == mPhoneImageView) { 209 launchPhone(); 210 } if (v == mLockIcon) { 211 mIndicationController.showTransientIndication( 212 R.string.keyguard_indication_trust_disabled); 213 mLockPatternUtils.requireCredentialEntry(mLockPatternUtils.getCurrentUser()); 214 } 215 } 216 217 public void launchCamera() { 218 mFlashlightController.killFlashlight(); 219 Intent intent = getCameraIntent(); 220 if (intent == SECURE_CAMERA_INTENT && 221 !mPreviewInflater.wouldLaunchResolverActivity(intent)) { 222 mContext.startActivityAsUser(intent, UserHandle.CURRENT); 223 } else { 224 mActivityStarter.startActivity(intent); 225 } 226 } 227 228 public void launchPhone() { 229 mActivityStarter.startActivity(PHONE_INTENT); 230 } 231 232 233 @Override 234 protected void onVisibilityChanged(View changedView, int visibility) { 235 super.onVisibilityChanged(changedView, visibility); 236 if (changedView == this && visibility == VISIBLE) { 237 updateLockIcon(); 238 updateCameraVisibility(); 239 } 240 } 241 242 private void updateLockIcon() { 243 if (getVisibility() != VISIBLE) { 244 return; 245 } 246 // TODO: Real icon for facelock. 247 int iconRes = mFaceUnlockRunning ? R.drawable.ic_account_circle 248 : mUnlockMethodCache.isMethodInsecure() ? R.drawable.ic_lock_open_24dp 249 : R.drawable.ic_lock_24dp; 250 mLockIcon.setImageResource(iconRes); 251 boolean trustManaged = mUnlockMethodCache.isTrustManaged(); 252 mLockIcon.setBackgroundResource(trustManaged && !mFaceUnlockRunning 253 ? R.drawable.trust_circle : 0); 254 mLockIcon.setClickable(trustManaged); 255 } 256 257 public KeyguardAffordanceView getPhoneView() { 258 return mPhoneImageView; 259 } 260 261 public KeyguardAffordanceView getCameraView() { 262 return mCameraImageView; 263 } 264 265 public View getPhonePreview() { 266 return mPhonePreview; 267 } 268 269 public View getCameraPreview() { 270 return mCameraPreview; 271 } 272 273 public KeyguardAffordanceView getLockIcon() { 274 return mLockIcon; 275 } 276 277 public View getIndicationView() { 278 return mIndicationText; 279 } 280 281 @Override 282 public boolean hasOverlappingRendering() { 283 return false; 284 } 285 286 @Override 287 public void onMethodSecureChanged(boolean methodSecure) { 288 updateLockIcon(); 289 updateCameraVisibility(); 290 } 291 292 private void inflatePreviews() { 293 mPhonePreview = mPreviewInflater.inflatePreview(PHONE_INTENT); 294 mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent()); 295 if (mPhonePreview != null) { 296 mPreviewContainer.addView(mPhonePreview); 297 mPhonePreview.setVisibility(View.INVISIBLE); 298 } 299 if (mCameraPreview != null) { 300 mPreviewContainer.addView(mCameraPreview); 301 mCameraPreview.setVisibility(View.INVISIBLE); 302 } 303 } 304 305 private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() { 306 public void onReceive(Context context, Intent intent) { 307 post(new Runnable() { 308 @Override 309 public void run() { 310 updateCameraVisibility(); 311 } 312 }); 313 } 314 }; 315 316 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback = 317 new KeyguardUpdateMonitorCallback() { 318 @Override 319 public void onUserSwitchComplete(int userId) { 320 updateCameraVisibility(); 321 } 322 323 @Override 324 public void onFaceUnlockStateChanged(boolean running) { 325 mFaceUnlockRunning = running; 326 updateLockIcon(); 327 } 328 }; 329 330 public void setKeyguardIndicationController( 331 KeyguardIndicationController keyguardIndicationController) { 332 mIndicationController = keyguardIndicationController; 333 } 334} 335