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 
72     @Override
onDestroy()73     public void onDestroy() {
74         super.onDestroy();
75 
76         PasswordHelper.zeroizeCredentials(mEnteredCredential, mCurrentCredential);
77     }
78 
init(int userId)79     final void init(int userId) {
80         mUtils = new LockPatternUtils(getContext());
81         mUserId = userId;
82     }
83 
start(int userId, LockscreenCredential enteredCredential, LockscreenCredential currentCredential)84     void start(int userId, LockscreenCredential enteredCredential,
85             LockscreenCredential currentCredential) {
86         init(userId);
87         mEnteredCredential = enteredCredential;
88         mCurrentCredential = currentCredential != null ? currentCredential
89                 : LockscreenCredential.createNone();
90         start();
91     }
92     /**
93      * Start executing the async task.
94      */
start()95     private void start() {
96         mFinished = false;
97         new Task().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
98     }
99 
100     /**
101      * Set the listener to get callback when finished saving the chosen lock.
102      */
setListener(Listener listener)103     public void setListener(Listener listener) {
104         if (mListener != listener) {
105             mListener = listener;
106             if (mFinished && mListener != null) {
107                 mListener.onChosenLockSaveFinished(mIsSaveSuccessful);
108             }
109         }
110     }
111 
112     @VisibleForTesting
saveAndVerifyInBackground(Void... params)113     boolean saveAndVerifyInBackground(Void... params) {
114         boolean isSaveSuccessful = true;
115 
116         try {
117             saveLock();
118         } catch (Exception e) {
119             LOG.e("Save lock exception", e);
120             isSaveSuccessful = false;
121         }
122 
123         return isSaveSuccessful;
124     }
125 
finish(boolean isSaveSuccessful)126     private void finish(boolean isSaveSuccessful) {
127         mFinished = true;
128         mIsSaveSuccessful = isSaveSuccessful;
129         if (mListener != null) {
130             mListener.onChosenLockSaveFinished(isSaveSuccessful);
131         }
132     }
133 
134     /**
135      * Executes the save and verify work in background.
136      */
137     @WorkerThread
saveLock()138     void saveLock() {
139         getUtils().setLockCredential(mEnteredCredential, mCurrentCredential, getUserId());
140     }
141 
142     // Save chosen lock task.
143     private class Task extends AsyncTask<Void, Void, Boolean> {
144         @Override
doInBackground(Void... params)145         protected Boolean doInBackground(Void... params) {
146             return saveAndVerifyInBackground();
147         }
148 
149         @Override
onPostExecute(Boolean isSaveSuccessful)150         protected void onPostExecute(Boolean isSaveSuccessful) {
151             finish(isSaveSuccessful);
152         }
153     }
154 }
155