1 /* 2 * Copyright (C) 2016 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.system; 18 19 import static android.os.UserHandle.USER_SYSTEM; 20 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.SharedPreferences; 26 import android.content.pm.ResolveInfo; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.os.Message; 30 import android.os.RemoteException; 31 import android.os.UserManager; 32 import android.util.Log; 33 34 import androidx.annotation.VisibleForTesting; 35 import androidx.fragment.app.FragmentActivity; 36 37 import com.android.internal.widget.ILockSettings; 38 import com.android.internal.widget.LockPatternUtils; 39 import com.android.internal.widget.LockscreenCredential; 40 import com.android.tv.settings.dialog.PinDialogFragment; 41 import com.android.tv.settings.users.RestrictedProfilePinDialogFragment; 42 import com.android.tv.settings.users.RestrictedProfilePinService; 43 44 import java.util.Objects; 45 46 /** 47 * Triggered instead of the home screen when user-selected home app isn't encryption aware. 48 */ 49 public class FallbackHome extends FragmentActivity implements PinDialogFragment.ResultListener { 50 51 private static final String TAG = "FallbackHome"; 52 53 private Handler mHandler = new Handler() { 54 @Override 55 public void handleMessage(Message msg) { 56 maybeFinish(); 57 } 58 }; 59 60 @Override onCreate(Bundle savedInstanceState)61 protected void onCreate(Bundle savedInstanceState) { 62 super.onCreate(savedInstanceState); 63 registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); 64 65 maybeStartPinDialog(); 66 maybeFinish(); 67 } 68 69 @Override onDestroy()70 protected void onDestroy() { 71 super.onDestroy(); 72 unregisterReceiver(mReceiver); 73 } 74 75 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 76 @Override 77 public void onReceive(Context context, Intent intent) { 78 maybeFinish(); 79 } 80 }; 81 maybeFinish()82 void maybeFinish() { 83 if (isUserUnlocked()) { 84 final Intent homeIntent = new Intent(Intent.ACTION_MAIN) 85 .addCategory(Intent.CATEGORY_HOME); 86 final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, 0); 87 if (Objects.equals(getPackageName(), homeInfo.activityInfo.packageName)) { 88 Log.d(TAG, "User unlocked but no home; let's hope someone enables one soon?"); 89 mHandler.sendEmptyMessageDelayed(0, 500); 90 } else { 91 Log.d(TAG, "User unlocked and real home found; let's go!"); 92 finish(); 93 } 94 } 95 } 96 97 /** 98 * If we have file-based encryption and a restricted profile we must request PIN entry on boot. 99 * 100 * Unlike a normal password, the restricted profile PIN is set on USER_OWNER in order to 101 * prevent switching out. Under FBE this means that the underlying USER_SYSTEM will remain 102 * encrypted and in RUNNING_LOCKED state. In order for various system functions to work 103 * we will need to decrypt first. 104 */ 105 @VisibleForTesting maybeStartPinDialog()106 void maybeStartPinDialog() { 107 if (isUserUnlocked() || !hasLockscreenSecurity(getUserId()) || !isFileEncryptionEnabled()) { 108 return; 109 } 110 111 unlockDevice(); 112 } 113 unlockDevice()114 private void unlockDevice() { 115 LockscreenCredential pin = getPinFromSharedPreferences(); 116 117 if (pin == null || pin.isNone()) { 118 showPinDialogToUnlockDevice(); 119 } else { 120 // Give LockSettings the pin. This unlocks the device. 121 unlockDeviceWithPin(pin); 122 } 123 } 124 125 @VisibleForTesting unlockDeviceWithPin(LockscreenCredential pin)126 void unlockDeviceWithPin(LockscreenCredential pin) { 127 try { 128 getLockSettings().checkCredential(pin, USER_SYSTEM, null); 129 } catch (RemoteException e) { 130 e.printStackTrace(); 131 } 132 } 133 134 @VisibleForTesting showPinDialogToUnlockDevice()135 void showPinDialogToUnlockDevice() { 136 // Prompt the user with a dialog to dial the pin and unlock the device. 137 RestrictedProfilePinDialogFragment restrictedProfilePinDialogFragment = 138 RestrictedProfilePinDialogFragment.newInstance( 139 PinDialogFragment.PIN_DIALOG_TYPE_ENTER_PIN); 140 restrictedProfilePinDialogFragment.show(getSupportFragmentManager(), 141 PinDialogFragment.DIALOG_TAG); 142 } 143 144 @VisibleForTesting getPinFromSharedPreferences()145 LockscreenCredential getPinFromSharedPreferences() { 146 SharedPreferences sp = getSharedPreferences(RestrictedProfilePinService.PIN_STORE_NAME, 147 Context.MODE_PRIVATE); 148 return LockscreenCredential.createPinOrNone( 149 sp.getString(RestrictedProfilePinService.PIN_STORE_NAME, null)); 150 } 151 152 @VisibleForTesting isUserUnlocked()153 boolean isUserUnlocked() { 154 return getSystemService(UserManager.class).isUserUnlocked(); 155 } 156 157 @VisibleForTesting hasLockscreenSecurity(final int userId)158 boolean hasLockscreenSecurity(final int userId) { 159 final LockPatternUtils lpu = new LockPatternUtils(this); 160 return lpu.isLockPasswordEnabled(userId) || lpu.isLockPatternEnabled(userId); 161 } 162 163 @VisibleForTesting isFileEncryptionEnabled()164 boolean isFileEncryptionEnabled() { 165 return LockPatternUtils.isFileEncryptionEnabled(); 166 } 167 168 @VisibleForTesting getLockSettings()169 ILockSettings getLockSettings() { 170 return new LockPatternUtils(this).getLockSettings(); 171 } 172 173 @Override pinFragmentDone(int requestCode, boolean success)174 public void pinFragmentDone(int requestCode, boolean success) { 175 maybeStartPinDialog(); 176 maybeFinish(); 177 } 178 } 179