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.content.Context;
20
21import com.android.internal.widget.LockPatternUtils;
22import com.android.keyguard.KeyguardUpdateMonitor;
23import com.android.keyguard.KeyguardUpdateMonitorCallback;
24
25import java.util.ArrayList;
26
27/**
28 * Caches whether the current unlock method is insecure, taking trust into account. This information
29 * might be a little bit out of date and should not be used for actual security decisions; it should
30 * be only used for visual indications.
31 */
32public class UnlockMethodCache {
33
34    private static UnlockMethodCache sInstance;
35
36    private final LockPatternUtils mLockPatternUtils;
37    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
38    private final ArrayList<OnUnlockMethodChangedListener> mListeners = new ArrayList<>();
39    /** Whether the user configured a secure unlock method (PIN, password, etc.) */
40    private boolean mSecure;
41    /** Whether the unlock method is currently insecure (insecure method or trusted environment) */
42    private boolean mCurrentlyInsecure;
43    private boolean mTrustManaged;
44    private boolean mFaceUnlockRunning;
45
46    private UnlockMethodCache(Context ctx) {
47        mLockPatternUtils = new LockPatternUtils(ctx);
48        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(ctx);
49        KeyguardUpdateMonitor.getInstance(ctx).registerCallback(mCallback);
50        update(true /* updateAlways */);
51    }
52
53    public static UnlockMethodCache getInstance(Context context) {
54        if (sInstance == null) {
55            sInstance = new UnlockMethodCache(context);
56        }
57        return sInstance;
58    }
59
60    /**
61     * @return whether the user configured a secure unlock method like PIN, password, etc.
62     */
63    public boolean isMethodSecure() {
64        return mSecure;
65    }
66
67    /**
68     * @return whether the lockscreen is currently insecure, i. e. the bouncer won't be shown
69     */
70    public boolean isCurrentlyInsecure() {
71        return mCurrentlyInsecure;
72    }
73
74    public void addListener(OnUnlockMethodChangedListener listener) {
75        mListeners.add(listener);
76    }
77
78    public void removeListener(OnUnlockMethodChangedListener listener) {
79        mListeners.remove(listener);
80    }
81
82    private void update(boolean updateAlways) {
83        int user = mLockPatternUtils.getCurrentUser();
84        boolean secure = mLockPatternUtils.isSecure();
85        boolean currentlyInsecure = !secure ||  mKeyguardUpdateMonitor.getUserHasTrust(user);
86        boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
87        boolean faceUnlockRunning = mKeyguardUpdateMonitor.isFaceUnlockRunning(user)
88                && trustManaged;
89        boolean changed = secure != mSecure || currentlyInsecure != mCurrentlyInsecure ||
90                trustManaged != mTrustManaged  || faceUnlockRunning != mFaceUnlockRunning;
91        if (changed || updateAlways) {
92            mSecure = secure;
93            mCurrentlyInsecure = currentlyInsecure;
94            mTrustManaged = trustManaged;
95            mFaceUnlockRunning = faceUnlockRunning;
96            notifyListeners();
97        }
98    }
99
100    private void notifyListeners() {
101        for (OnUnlockMethodChangedListener listener : mListeners) {
102            listener.onUnlockMethodStateChanged();
103        }
104    }
105
106    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
107        @Override
108        public void onUserSwitchComplete(int userId) {
109            update(false /* updateAlways */);
110        }
111
112        @Override
113        public void onTrustChanged(int userId) {
114            update(false /* updateAlways */);
115        }
116
117        @Override
118        public void onTrustManagedChanged(int userId) {
119            update(false /* updateAlways */);
120        }
121
122        @Override
123        public void onScreenTurnedOn() {
124            update(false /* updateAlways */);
125        }
126
127        @Override
128        public void onFingerprintRecognized(int userId) {
129            update(false /* updateAlways */);
130        }
131
132        @Override
133        public void onFaceUnlockStateChanged(boolean running, int userId) {
134            update(false /* updateAlways */);
135        }
136    };
137
138    public boolean isTrustManaged() {
139        return mTrustManaged;
140    }
141
142    public boolean isFaceUnlockRunning() {
143        return mFaceUnlockRunning;
144    }
145
146    public static interface OnUnlockMethodChangedListener {
147        void onUnlockMethodStateChanged();
148    }
149}
150