KeyguardBottomAreaView.java revision b6cdcbc66b4b862f83afde85b8e7109b6450b15e
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;
36import android.widget.ImageView;
37
38import com.android.internal.widget.LockPatternUtils;
39import com.android.keyguard.KeyguardUpdateMonitor;
40import com.android.keyguard.KeyguardUpdateMonitorCallback;
41import com.android.systemui.R;
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
76    public KeyguardBottomAreaView(Context context) {
77        super(context);
78    }
79
80    public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
81        super(context, attrs);
82    }
83
84    public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
85        super(context, attrs, defStyleAttr);
86    }
87
88    public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
89            int defStyleRes) {
90        super(context, attrs, defStyleAttr, defStyleRes);
91    }
92
93    @Override
94    protected void onFinishInflate() {
95        super.onFinishInflate();
96        mLockPatternUtils = new LockPatternUtils(mContext);
97        mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container);
98        mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
99        mPhoneImageView = (KeyguardAffordanceView) findViewById(R.id.phone_button);
100        mLockIcon = (KeyguardAffordanceView) findViewById(R.id.lock_icon);
101        mIndicationText = findViewById(R.id.keyguard_indication_text);
102        watchForCameraPolicyChanges();
103        watchForAccessibilityChanges();
104        updateCameraVisibility();
105        updatePhoneVisibility();
106        mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
107        mUnlockMethodCache.addListener(this);
108        updateTrust();
109        setClipChildren(false);
110        setClipToPadding(false);
111        inflatePreviews();
112    }
113
114    public void setActivityStarter(ActivityStarter activityStarter) {
115        mActivityStarter = activityStarter;
116    }
117
118    public void setFlashlightController(FlashlightController flashlightController) {
119        mFlashlightController = flashlightController;
120    }
121
122    private Intent getCameraIntent() {
123        KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
124        boolean currentUserHasTrust = updateMonitor.getUserHasTrust(
125                mLockPatternUtils.getCurrentUser());
126        return mLockPatternUtils.isSecure() && !currentUserHasTrust
127                ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
128    }
129
130    private void updateCameraVisibility() {
131        ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
132                PackageManager.MATCH_DEFAULT_ONLY,
133                mLockPatternUtils.getCurrentUser());
134        boolean visible = !isCameraDisabledByDpm() && resolved != null;
135        mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
136    }
137
138    private void updatePhoneVisibility() {
139        boolean visible = isPhoneVisible();
140        mPhoneImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
141    }
142
143    private boolean isPhoneVisible() {
144        PackageManager pm = mContext.getPackageManager();
145        return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
146                && pm.resolveActivity(PHONE_INTENT, 0) != null;
147    }
148
149    private boolean isCameraDisabledByDpm() {
150        final DevicePolicyManager dpm =
151                (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
152        if (dpm != null) {
153            try {
154                final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
155                final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
156                final  boolean disabledBecauseKeyguardSecure =
157                        (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
158                                && KeyguardTouchDelegate.getInstance(getContext()).isSecure();
159                return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
160            } catch (RemoteException e) {
161                Log.e(TAG, "Can't get userId", e);
162            }
163        }
164        return false;
165    }
166
167    private void watchForCameraPolicyChanges() {
168        final IntentFilter filter = new IntentFilter();
169        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
170        getContext().registerReceiverAsUser(mDevicePolicyReceiver,
171                UserHandle.ALL, filter, null, null);
172        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
173    }
174
175    private void watchForAccessibilityChanges() {
176        final AccessibilityManager am =
177                (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
178
179        // Set the initial state
180        enableAccessibility(am.isTouchExplorationEnabled());
181
182        // Watch for changes
183        am.addTouchExplorationStateChangeListener(
184                new AccessibilityManager.TouchExplorationStateChangeListener() {
185            @Override
186            public void onTouchExplorationStateChanged(boolean enabled) {
187                enableAccessibility(enabled);
188            }
189        });
190    }
191
192    private void enableAccessibility(boolean touchExplorationEnabled) {
193        mCameraImageView.setOnClickListener(touchExplorationEnabled ? this : null);
194        mCameraImageView.setClickable(touchExplorationEnabled);
195        mPhoneImageView.setOnClickListener(touchExplorationEnabled ? this : null);
196        mPhoneImageView.setClickable(touchExplorationEnabled);
197    }
198
199    @Override
200    public void onClick(View v) {
201        if (v == mCameraImageView) {
202            launchCamera();
203        } else if (v == mPhoneImageView) {
204            launchPhone();
205        }
206    }
207
208    public void launchCamera() {
209        mFlashlightController.killFlashlight();
210        Intent intent = getCameraIntent();
211        if (intent == SECURE_CAMERA_INTENT) {
212            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
213        } else {
214            mActivityStarter.startActivity(intent);
215        }
216    }
217
218    public void launchPhone() {
219        mActivityStarter.startActivity(PHONE_INTENT);
220    }
221
222
223    @Override
224    protected void onVisibilityChanged(View changedView, int visibility) {
225        super.onVisibilityChanged(changedView, visibility);
226        if (changedView == this && visibility == VISIBLE) {
227            updateTrust();
228            updateCameraVisibility();
229        }
230    }
231
232    private void updateTrust() {
233        if (getVisibility() != VISIBLE) {
234            return;
235        }
236        int iconRes = mUnlockMethodCache.isMethodInsecure()
237                ? R.drawable.ic_lock_open_24dp
238                : R.drawable.ic_lock_24dp;
239        mLockIcon.setImageResource(iconRes);
240    }
241
242    public KeyguardAffordanceView getPhoneView() {
243        return mPhoneImageView;
244    }
245
246    public KeyguardAffordanceView getCameraView() {
247        return mCameraImageView;
248    }
249
250    public View getPhonePreview() {
251        return mPhonePreview;
252    }
253
254    public View getCameraPreview() {
255        return mCameraPreview;
256    }
257
258    public KeyguardAffordanceView getLockIcon() {
259        return mLockIcon;
260    }
261
262    public View getIndicationView() {
263        return mIndicationText;
264    }
265
266    @Override
267    public boolean hasOverlappingRendering() {
268        return false;
269    }
270
271    @Override
272    public void onMethodSecureChanged(boolean methodSecure) {
273        updateTrust();
274        updateCameraVisibility();
275    }
276
277    private void inflatePreviews() {
278        PreviewInflater inflater = new PreviewInflater(mContext, new LockPatternUtils(mContext));
279        mPhonePreview = inflater.inflatePreview(PHONE_INTENT);
280        mCameraPreview = inflater.inflatePreview(getCameraIntent());
281        if (mPhonePreview != null) {
282            mPreviewContainer.addView(mPhonePreview);
283            mPhonePreview.setVisibility(View.INVISIBLE);
284        }
285        if (mCameraPreview != null) {
286            mPreviewContainer.addView(mCameraPreview);
287            mCameraPreview.setVisibility(View.INVISIBLE);
288        }
289    }
290
291    private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() {
292        public void onReceive(Context context, Intent intent) {
293            post(new Runnable() {
294                @Override
295                public void run() {
296                    updateCameraVisibility();
297                }
298            });
299        }
300    };
301
302    private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
303            new KeyguardUpdateMonitorCallback() {
304        @Override
305        public void onUserSwitchComplete(int userId) {
306            updateCameraVisibility();
307        }
308    };
309}
310