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 
17 package com.android.tv.settings.users;
18 
19 import android.content.Context;
20 import android.os.Bundle;
21 import android.os.Handler;
22 import android.os.HandlerThread;
23 import android.os.Looper;
24 
25 import com.android.tv.settings.dialog.PinDialogFragment;
26 
27 import java.util.function.Consumer;
28 
29 /**
30  * Fragment that handles the PIN dialog for Restricted Profile actions.
31  */
32 public class RestrictedProfilePinDialogFragment extends PinDialogFragment {
33     private static final String TAG = RestrictedProfilePinDialogFragment.class.getSimpleName();
34 
35     private static final  String SHARED_PREFERENCE_NAME = "RestrictedProfilePinDialogFragment";
36     private static final String PREF_DISABLE_PIN_UNTIL = "disable_pin_until";
37 
38     private RestrictedProfilePinStorage mRestrictedProfilePinStorage;
39 
40     private HandlerThread mBackgroundThread;
41     private Handler mBackgroundThreadHandler;
42     private Handler mUiThreadHandler;
43 
newInstance(@inDialogType int type)44     public static RestrictedProfilePinDialogFragment newInstance(@PinDialogType int type) {
45         RestrictedProfilePinDialogFragment fragment = new RestrictedProfilePinDialogFragment();
46         final Bundle b = new Bundle(1);
47         b.putInt(PinDialogFragment.ARG_TYPE, type);
48         fragment.setArguments(b);
49         return fragment;
50     }
51 
52     @Override
onAttach(Context context)53     public void onAttach(Context context) {
54         super.onAttach(context);
55 
56         mBackgroundThread = new HandlerThread(TAG);
57         mBackgroundThread.start();
58         mBackgroundThreadHandler = new Handler(mBackgroundThread.getLooper());
59         mUiThreadHandler = new Handler(Looper.getMainLooper());
60 
61         mBackgroundThreadHandler.post(() -> {
62             mRestrictedProfilePinStorage = RestrictedProfilePinStorage.newInstance(getContext());
63             mRestrictedProfilePinStorage.bind();
64         });
65     }
66 
67     @Override
onDetach()68     public void onDetach() {
69         mRestrictedProfilePinStorage.unbind();
70         mRestrictedProfilePinStorage = null;
71         mUiThreadHandler = null;
72         mBackgroundThreadHandler = null;
73         mBackgroundThread.quitSafely();
74         mBackgroundThread = null;
75         super.onDetach();
76     }
77 
78     /**
79      * Returns the time until we should disable the PIN dialog (because the user input wrong
80      * PINs repeatedly).
81      */
getDisablePinUntil(Context context)82     public static long getDisablePinUntil(Context context) {
83         return context.getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE)
84                       .getLong(PREF_DISABLE_PIN_UNTIL, 0);
85     }
86 
87     /**
88      * Saves the time until we should disable the PIN dialog (because the user input wrong PINs
89      * repeatedly).
90      */
setDisablePinUntil(Context context, long timeMillis)91     public static void setDisablePinUntil(Context context, long timeMillis) {
92         context.getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE)
93                 .edit()
94                 .putLong(PREF_DISABLE_PIN_UNTIL, timeMillis)
95                 .apply();
96     }
97 
98     @Override
getPinDisabledUntil()99     public long getPinDisabledUntil() {
100         return getDisablePinUntil(getActivity());
101     }
102 
103     @Override
setPinDisabledUntil(long retryDisableTimeout)104     public void setPinDisabledUntil(long retryDisableTimeout) {
105         setDisablePinUntil(getActivity(), retryDisableTimeout);
106     }
107 
108     @Override
setPin(String pin, String originalPin, Consumer<Boolean> consumer)109     public void setPin(String pin, String originalPin, Consumer<Boolean> consumer) {
110         // Set pin on the background thread and consume the result on the UI thread.
111         mBackgroundThreadHandler.post(() -> {
112             mRestrictedProfilePinStorage.setPin(pin, originalPin);
113             mUiThreadHandler.post(() -> consumer.accept(true));
114         });
115     }
116 
117     @Override
deletePin(String oldPin, Consumer<Boolean> consumer)118     public void deletePin(String oldPin, Consumer<Boolean> consumer) {
119         // Delete the pin on the background thread and consume the result on the UI thread.
120         mBackgroundThreadHandler.post(() -> {
121             mRestrictedProfilePinStorage.deletePin(oldPin);
122             mUiThreadHandler.post(() -> consumer.accept(true));
123         });
124     }
125 
126     @Override
isPinCorrect(String pin, Consumer<Boolean> consumer)127     public void isPinCorrect(String pin, Consumer<Boolean> consumer) {
128         // Check if the pin is correct and consume the result on the UI thread.
129         mBackgroundThreadHandler.post(() -> {
130             boolean isPinCorrect = mRestrictedProfilePinStorage.isPinCorrect(pin);
131             mUiThreadHandler.post(() -> consumer.accept(isPinCorrect));
132         });
133     }
134 
135     @Override
isPinSet(Consumer<Boolean> consumer)136     public void isPinSet(Consumer<Boolean> consumer) {
137         // Check if the pin is set and consume the result on the UI thread.
138         mBackgroundThreadHandler.post(() -> {
139             boolean isPinSet = mRestrictedProfilePinStorage.isPinSet();
140             mUiThreadHandler.post(() -> consumer.accept(isPinSet));
141         });
142     }
143 }
144