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