• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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