blob: a6618cbbd26b93ad6f215cb3792fd15e0704b066 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tv.settings.system;
import static android.os.UserHandle.USER_SYSTEM;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.UserManager;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.FragmentActivity;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
import com.android.tv.settings.dialog.PinDialogFragment;
import com.android.tv.settings.users.RestrictedProfilePinDialogFragment;
import com.android.tv.settings.users.RestrictedProfilePinService;
import java.util.Objects;
/**
* Triggered instead of the home screen when user-selected home app isn't encryption aware.
*/
public class FallbackHome extends FragmentActivity implements PinDialogFragment.ResultListener {
private static final String TAG = "FallbackHome";
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
maybeFinish();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
maybeStartPinDialog();
maybeFinish();
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
maybeFinish();
}
};
void maybeFinish() {
if (isUserUnlocked()) {
final Intent homeIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME);
final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, 0);
if (Objects.equals(getPackageName(), homeInfo.activityInfo.packageName)) {
Log.d(TAG, "User unlocked but no home; let's hope someone enables one soon?");
mHandler.sendEmptyMessageDelayed(0, 500);
} else {
Log.d(TAG, "User unlocked and real home found; let's go!");
finish();
}
}
}
/**
* If we have file-based encryption and a restricted profile we must request PIN entry on boot.
*
* Unlike a normal password, the restricted profile PIN is set on USER_OWNER in order to
* prevent switching out. Under FBE this means that the underlying USER_SYSTEM will remain
* encrypted and in RUNNING_LOCKED state. In order for various system functions to work
* we will need to decrypt first.
*/
@VisibleForTesting
void maybeStartPinDialog() {
if (isUserUnlocked() || !hasLockscreenSecurity(getUserId()) || !isFileEncryptionEnabled()) {
return;
}
unlockDevice();
}
private void unlockDevice() {
try (LockscreenCredential pin = getPinFromSharedPreferences()) {
if (pin == null || pin.isNone()) {
showPinDialogToUnlockDevice();
} else {
// Give LockSettings the pin. This unlocks the device.
unlockDeviceWithPin(pin);
}
}
}
@VisibleForTesting
void unlockDeviceWithPin(LockscreenCredential pin) {
try {
getLockSettings().checkCredential(pin, USER_SYSTEM, null);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@VisibleForTesting
void showPinDialogToUnlockDevice() {
// Prompt the user with a dialog to dial the pin and unlock the device.
RestrictedProfilePinDialogFragment restrictedProfilePinDialogFragment =
RestrictedProfilePinDialogFragment.newInstance(
PinDialogFragment.PIN_DIALOG_TYPE_ENTER_PIN);
restrictedProfilePinDialogFragment.show(getSupportFragmentManager(),
PinDialogFragment.DIALOG_TAG);
}
@VisibleForTesting
LockscreenCredential getPinFromSharedPreferences() {
SharedPreferences sp = getSharedPreferences(RestrictedProfilePinService.PIN_STORE_NAME,
Context.MODE_PRIVATE);
return LockscreenCredential.createPinOrNone(
sp.getString(RestrictedProfilePinService.PIN_STORE_NAME, null));
}
@VisibleForTesting
boolean isUserUnlocked() {
return getSystemService(UserManager.class).isUserUnlocked();
}
@VisibleForTesting
boolean hasLockscreenSecurity(final int userId) {
final LockPatternUtils lpu = new LockPatternUtils(this);
return lpu.isLockPasswordEnabled(userId) || lpu.isLockPatternEnabled(userId);
}
@VisibleForTesting
boolean isFileEncryptionEnabled() {
return LockPatternUtils.isFileEncryptionEnabled();
}
@VisibleForTesting
ILockSettings getLockSettings() {
return new LockPatternUtils(this).getLockSettings();
}
@Override
public void pinFragmentDone(int requestCode, boolean success) {
maybeStartPinDialog();
maybeFinish();
}
}