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.annotation.WorkerThread;
20 import android.os.AsyncTask;
21 import android.os.Bundle;
22 
23 import androidx.annotation.VisibleForTesting;
24 import androidx.fragment.app.Fragment;
25 
26 import com.android.car.settings.common.Logger;
27 import com.android.internal.widget.LockPatternUtils;
28 import com.android.internal.widget.LockscreenCredential;
29 
30 /**
31  * An invisible retained worker fragment to track the AsyncWork that saves
32  * the chosen lock credential (pattern/pin/password).
33  */
34 public class SaveLockWorker extends Fragment {
35     /**
36      * Callback when lock save has finished
37      */
38     interface Listener {
onChosenLockSaveFinished(boolean isSaveSuccessful)39         void onChosenLockSaveFinished(boolean isSaveSuccessful);
40     }
41 
42     private static final Logger LOG = new Logger(SaveLockWorker.class);
43 
44     private Listener mListener;
45     private boolean mFinished;
46     private boolean mIsSaveSuccessful;
47     private LockPatternUtils mUtils;
48     private int mUserId;
49 
50     private LockscreenCredential mEnteredCredential;
51     private LockscreenCredential mCurrentCredential;
52     private int mRequestedQuality;
53 
getUtils()54     final LockPatternUtils getUtils() {
55         return mUtils;
56     }
57 
getUserId()58     final int getUserId() {
59         return mUserId;
60     }
61 
isFinished()62     final boolean isFinished() {
63         return mFinished;
64     }
65 
66     @Override
onCreate(Bundle savedInstanceState)67     public void onCreate(Bundle savedInstanceState) {
68         super.onCreate(savedInstanceState);
69         setRetainInstance(true);
70     }
71 
init(int userId)72     final void init(int userId) {
73         mUtils = new LockPatternUtils(getContext());
74         mUserId = userId;
75     }
76 
start(int userId, LockscreenCredential enteredCredential, LockscreenCredential currentCredential)77     void start(int userId, LockscreenCredential enteredCredential,
78             LockscreenCredential currentCredential) {
79         init(userId);
80         mEnteredCredential = enteredCredential;
81         mCurrentCredential = currentCredential != null ? currentCredential
82                 : LockscreenCredential.createNone();
83         start();
84     }
85     /**
86      * Start executing the async task.
87      */
start()88     private void start() {
89         mFinished = false;
90         new Task().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
91     }
92 
93     /**
94      * Set the listener to get callback when finished saving the chosen lock.
95      */
setListener(Listener listener)96     public void setListener(Listener listener) {
97         if (mListener != listener) {
98             mListener = listener;
99             if (mFinished && mListener != null) {
100                 mListener.onChosenLockSaveFinished(mIsSaveSuccessful);
101             }
102         }
103     }
104 
105     @VisibleForTesting
saveAndVerifyInBackground(Void... params)106     boolean saveAndVerifyInBackground(Void... params) {
107         boolean isSaveSuccessful = true;
108 
109         try {
110             saveLock();
111         } catch (Exception e) {
112             LOG.e("Save lock exception", e);
113             isSaveSuccessful = false;
114         }
115 
116         return isSaveSuccessful;
117     }
118 
finish(boolean isSaveSuccessful)119     private void finish(boolean isSaveSuccessful) {
120         mFinished = true;
121         mIsSaveSuccessful = isSaveSuccessful;
122         if (mListener != null) {
123             mListener.onChosenLockSaveFinished(isSaveSuccessful);
124         }
125     }
126 
127     /**
128      * Executes the save and verify work in background.
129      */
130     @WorkerThread
saveLock()131     void saveLock() {
132         final int userId = getUserId();
133 
134         // If called after setLockCredential, this will always be true
135         boolean isPatternEverChosen = getUtils().isPatternEverChosen(userId);
136 
137         getUtils().setLockCredential(mEnteredCredential, mCurrentCredential, userId);
138 
139         if (mEnteredCredential.isPattern() && !isPatternEverChosen) {
140             getUtils().setVisiblePatternEnabled(true, userId);
141         }
142     }
143 
144     // Save chosen lock task.
145     private class Task extends AsyncTask<Void, Void, Boolean> {
146         @Override
doInBackground(Void... params)147         protected Boolean doInBackground(Void... params) {
148             return saveAndVerifyInBackground();
149         }
150 
151         @Override
onPostExecute(Boolean isSaveSuccessful)152         protected void onPostExecute(Boolean isSaveSuccessful) {
153             finish(isSaveSuccessful);
154         }
155     }
156 }
157