1 /*
2  * Copyright (C) 2015 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.settings.password;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.os.AsyncTask;
22 import android.os.Bundle;
23 import android.os.UserHandle;
24 import android.os.UserManager;
25 import android.util.Pair;
26 import android.widget.Toast;
27 
28 import androidx.fragment.app.Fragment;
29 
30 import com.android.internal.widget.LockPatternUtils;
31 import com.android.internal.widget.LockscreenCredential;
32 import com.android.settings.R;
33 
34 /**
35  * An invisible retained worker fragment to track the AsyncWork that saves (and optionally
36  * verifies if a challenge is given) the chosen lock credential (pattern/pin/password).
37  */
38 abstract class SaveChosenLockWorkerBase extends Fragment {
39 
40     private Listener mListener;
41     private boolean mFinished;
42     private Intent mResultData;
43 
44     protected LockPatternUtils mUtils;
45     protected boolean mHasChallenge;
46     protected long mChallenge;
47     protected boolean mWasSecureBefore;
48     protected int mUserId;
49     protected int mUnificationProfileId = UserHandle.USER_NULL;
50     protected LockscreenCredential mUnificationProfileCredential;
51 
52     private boolean mBlocking;
53 
54     @Override
onCreate(Bundle savedInstanceState)55     public void onCreate(Bundle savedInstanceState) {
56         super.onCreate(savedInstanceState);
57         setRetainInstance(true);
58     }
59 
setListener(Listener listener)60     public void setListener(Listener listener) {
61         if (mListener == listener) {
62             return;
63         }
64 
65         mListener = listener;
66         if (mFinished && mListener != null) {
67             mListener.onChosenLockSaveFinished(mWasSecureBefore, mResultData);
68         }
69     }
70 
prepare(LockPatternUtils utils, boolean credentialRequired, boolean hasChallenge, long challenge, int userId)71     protected void prepare(LockPatternUtils utils, boolean credentialRequired,
72             boolean hasChallenge, long challenge, int userId) {
73         mUtils = utils;
74         mUserId = userId;
75 
76         mHasChallenge = hasChallenge;
77         mChallenge = challenge;
78         // This will be a no-op for non managed profiles.
79         mWasSecureBefore = mUtils.isSecure(mUserId);
80 
81         Context context = getContext();
82         // If context is null, we're being invoked to change the setCredentialRequiredToDecrypt,
83         // and we made sure that this is the primary user already.
84         if (context == null || UserManager.get(context).getUserInfo(mUserId).isPrimary()) {
85             mUtils.setCredentialRequiredToDecrypt(credentialRequired);
86         }
87 
88         mFinished = false;
89         mResultData = null;
90     }
91 
start()92     protected void start() {
93         if (mBlocking) {
94             finish(saveAndVerifyInBackground().second);
95         } else {
96             new Task().execute();
97         }
98     }
99 
100     /**
101      * Executes the save and verify work in background.
102      * @return pair where the first is a boolean confirming whether the change was successful or not
103      * and second is the Intent which has the challenge token or is null.
104      */
saveAndVerifyInBackground()105     protected abstract Pair<Boolean, Intent> saveAndVerifyInBackground();
106 
finish(Intent resultData)107     protected void finish(Intent resultData) {
108         mFinished = true;
109         mResultData = resultData;
110         if (mListener != null) {
111             mListener.onChosenLockSaveFinished(mWasSecureBefore, mResultData);
112         }
113         if (mUnificationProfileCredential != null) {
114             mUnificationProfileCredential.zeroize();
115         }
116     }
117 
setBlocking(boolean blocking)118     public void setBlocking(boolean blocking) {
119         mBlocking = blocking;
120     }
121 
setProfileToUnify(int profileId, LockscreenCredential credential)122     public void setProfileToUnify(int profileId, LockscreenCredential credential) {
123         mUnificationProfileId = profileId;
124         mUnificationProfileCredential = credential.duplicate();
125     }
126 
unifyProfileCredentialIfRequested()127     protected void unifyProfileCredentialIfRequested() {
128         if (mUnificationProfileId != UserHandle.USER_NULL) {
129             mUtils.setSeparateProfileChallengeEnabled(mUnificationProfileId, false,
130                     mUnificationProfileCredential);
131         }
132     }
133 
134     private class Task extends AsyncTask<Void, Void, Pair<Boolean, Intent>> {
135 
136         @Override
doInBackground(Void... params)137         protected Pair<Boolean, Intent> doInBackground(Void... params){
138             return saveAndVerifyInBackground();
139         }
140 
141         @Override
onPostExecute(Pair<Boolean, Intent> resultData)142         protected void onPostExecute(Pair<Boolean, Intent> resultData) {
143             if (!resultData.first) {
144                 Toast.makeText(getContext(), R.string.lockpassword_credential_changed,
145                         Toast.LENGTH_LONG).show();
146             }
147             finish(resultData.second);
148         }
149     }
150 
151     interface Listener {
onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData)152         void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData);
153     }
154 }
155