1 /*
2  * Copyright (C) 2018 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.car.settings.security;
18 
19 import android.content.Context;
20 import android.os.Bundle;
21 import android.os.UserHandle;
22 import android.view.View;
23 import android.widget.TextView;
24 
25 import androidx.annotation.LayoutRes;
26 import androidx.annotation.StringRes;
27 
28 import com.android.car.settings.R;
29 import com.android.car.settings.common.BaseFragment;
30 import com.android.internal.widget.LockPatternUtils;
31 import com.android.internal.widget.LockPatternView;
32 import com.android.internal.widget.LockscreenCredential;
33 
34 import java.util.List;
35 
36 /**
37  * Fragment for confirming existing lock pattern
38  */
39 public class ConfirmLockPatternFragment extends BaseFragment {
40 
41     private static final String FRAGMENT_TAG_CHECK_LOCK_WORKER = "check_lock_worker";
42     // Time we wait before clearing a wrong pattern and the error message.
43     private static final long CLEAR_WRONG_ATTEMPT_TIMEOUT_MS = 2500L;
44 
45     private LockPatternView mLockPatternView;
46     private TextView mMsgView;
47 
48     private LockPatternUtils mLockPatternUtils;
49     private CheckLockWorker mCheckLockWorker;
50     private CheckLockListener mCheckLockListener;
51 
52     private int mUserId;
53     private List<LockPatternView.Cell> mPattern;
54 
55     @Override
56     @LayoutRes
getLayoutId()57     protected int getLayoutId() {
58         return R.layout.confirm_lock_pattern;
59     }
60 
61     @Override
62     @StringRes
getTitleId()63     protected int getTitleId() {
64         return R.string.security_settings_title;
65     }
66 
67     @Override
onAttach(Context context)68     public void onAttach(Context context) {
69         super.onAttach(context);
70         if ((getActivity() instanceof CheckLockListener)) {
71             mCheckLockListener = (CheckLockListener) getActivity();
72         } else {
73             throw new RuntimeException("The activity must implement CheckLockListener");
74         }
75     }
76 
77     @Override
onCreate(Bundle savedInstanceState)78     public void onCreate(Bundle savedInstanceState) {
79         super.onCreate(savedInstanceState);
80         mLockPatternUtils = new LockPatternUtils(getContext());
81         mUserId = UserHandle.myUserId();
82     }
83 
84     @Override
onViewCreated(View view, Bundle savedInstanceState)85     public void onViewCreated(View view, Bundle savedInstanceState) {
86         super.onViewCreated(view, savedInstanceState);
87 
88         mMsgView = (TextView) view.findViewById(R.id.message);
89         mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
90         mLockPatternView.setFadePattern(false);
91         mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(mUserId));
92         mLockPatternView.setOnPatternListener(mLockPatternListener);
93 
94         if (savedInstanceState != null) {
95             mCheckLockWorker = (CheckLockWorker) getFragmentManager().findFragmentByTag(
96                     FRAGMENT_TAG_CHECK_LOCK_WORKER);
97         }
98     }
99 
100     @Override
onStart()101     public void onStart() {
102         super.onStart();
103         if (mCheckLockWorker != null) {
104             mCheckLockWorker.setListener(this::onCheckCompleted);
105         }
106     }
107 
108     @Override
onStop()109     public void onStop() {
110         super.onStop();
111         if (mCheckLockWorker != null) {
112             mCheckLockWorker.setListener(null);
113         }
114     }
115 
116     private Runnable mClearErrorRunnable = () -> {
117         mLockPatternView.clearPattern();
118         mMsgView.setText("");
119     };
120 
121     private LockPatternView.OnPatternListener mLockPatternListener =
122             new LockPatternView.OnPatternListener() {
123 
124                 public void onPatternStart() {
125                     mLockPatternView.removeCallbacks(mClearErrorRunnable);
126                     mMsgView.setText("");
127                 }
128 
129                 public void onPatternCleared() {
130                     mLockPatternView.removeCallbacks(mClearErrorRunnable);
131                 }
132 
133                 public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
134                 }
135 
136                 public void onPatternDetected(List<LockPatternView.Cell> pattern) {
137                     mLockPatternView.setEnabled(false);
138 
139                     if (mCheckLockWorker == null) {
140                         mCheckLockWorker = new CheckLockWorker();
141                         mCheckLockWorker.setListener(
142                                 ConfirmLockPatternFragment.this::onCheckCompleted);
143 
144                         getFragmentManager()
145                                 .beginTransaction()
146                                 .add(mCheckLockWorker, FRAGMENT_TAG_CHECK_LOCK_WORKER)
147                                 .commitNow();
148                     }
149 
150                     mPattern = pattern;
151                     mCheckLockWorker.checkPattern(mUserId, pattern);
152                 }
153             };
154 
onCheckCompleted(boolean lockMatched)155     private void onCheckCompleted(boolean lockMatched) {
156         if (lockMatched) {
157             mCheckLockListener.onLockVerified(LockscreenCredential.createPattern(mPattern));
158         } else {
159             mLockPatternView.setEnabled(true);
160             mMsgView.setText(R.string.lockpattern_pattern_wrong);
161 
162             // Set timer to clear wrong pattern
163             mLockPatternView.removeCallbacks(mClearErrorRunnable);
164             mLockPatternView.postDelayed(mClearErrorRunnable, CLEAR_WRONG_ATTEMPT_TIMEOUT_MS);
165         }
166     }
167 }
168