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