This add below changes on selecting private space setting: 1. Prompt user to setup device lock if not already set 2. If device lock is set authenticate user first before displaying private space settings page Screenshot - https://screenshot.googleplex.com/4SrYHbBMJfVuoRy.png https://screenshot.googleplex.com/6vNWm7Lg83vfnH8.png RecordingLink - https://drive.google.com/file/d/1r4zb3ILPRqwvP5tlwfjQ9GgnDAW4vZg6/view?usp=drive_link Bug: 289016927 Test: atest PrivateSpaceSettingsAuthenticatorTest , atest SecuritySettingsTest Change-Id: I0e5dfb30213843c0dec60a17d01c30cd91db89b0
192 lines
6.8 KiB
Java
192 lines
6.8 KiB
Java
/*
|
|
* Copyright (C) 2023 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.settings.privatespace;
|
|
|
|
import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
|
|
|
|
import android.app.ActivityManager;
|
|
import android.app.IActivityManager;
|
|
import android.app.KeyguardManager;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.pm.UserInfo;
|
|
import android.os.RemoteException;
|
|
import android.os.UserHandle;
|
|
import android.os.UserManager;
|
|
import android.util.ArraySet;
|
|
import android.util.Log;
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
import com.android.internal.annotations.GuardedBy;
|
|
|
|
import java.util.List;
|
|
|
|
// TODO(b/293569406): Update the javadoc when we have the setup flow in place to create PS
|
|
/** A class to help with the creation / deletion of Private Space */
|
|
public class PrivateSpaceMaintainer {
|
|
private static final String TAG = "PrivateSpaceMaintainer";
|
|
@GuardedBy("this")
|
|
private static PrivateSpaceMaintainer sPrivateSpaceMaintainer;
|
|
|
|
private final Context mContext;
|
|
private final UserManager mUserManager;
|
|
@GuardedBy("this")
|
|
private UserHandle mUserHandle;
|
|
private final KeyguardManager mKeyguardManager;
|
|
|
|
public enum ErrorDeletingPrivateSpace {
|
|
DELETE_PS_ERROR_NONE,
|
|
DELETE_PS_ERROR_NO_PRIVATE_SPACE,
|
|
DELETE_PS_ERROR_INTERNAL
|
|
}
|
|
|
|
/**
|
|
* Returns true if the private space was successfully created.
|
|
*
|
|
* <p> This method should be used by the Private Space Setup Flow ONLY.
|
|
*/
|
|
final synchronized boolean createPrivateSpace() {
|
|
// Check if Private space already exists
|
|
if (doesPrivateSpaceExist()) {
|
|
return true;
|
|
}
|
|
// a name indicating that the profile was created from the PS Settings page
|
|
final String userName = "psSettingsUser";
|
|
|
|
if (mUserHandle == null) {
|
|
try {
|
|
mUserHandle = mUserManager.createProfile(
|
|
userName, USER_TYPE_PROFILE_PRIVATE, new ArraySet<>());
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Error creating private space", e);
|
|
return false;
|
|
}
|
|
|
|
if (mUserHandle == null) {
|
|
Log.e(TAG, "Failed to create private space");
|
|
return false;
|
|
}
|
|
|
|
IActivityManager am = ActivityManager.getService();
|
|
try {
|
|
am.startProfile(mUserHandle.getIdentifier());
|
|
} catch (RemoteException e) {
|
|
Log.e(TAG, "Failed to start private profile");
|
|
return false;
|
|
}
|
|
|
|
Log.i(TAG, "Private space created with id: " + mUserHandle.getIdentifier());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Returns the {@link ErrorDeletingPrivateSpace} enum representing the result of operation.
|
|
*
|
|
* <p> This method should be used ONLY by the delete-PS controller in the PS Settings page.
|
|
*/
|
|
public synchronized ErrorDeletingPrivateSpace deletePrivateSpace() {
|
|
if (!doesPrivateSpaceExist()) {
|
|
return ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NO_PRIVATE_SPACE;
|
|
}
|
|
|
|
try {
|
|
Log.i(TAG, "Deleting Private space with id: " + mUserHandle.getIdentifier());
|
|
if (mUserManager.removeUser(mUserHandle)) {
|
|
Log.i(TAG, "Private space deleted");
|
|
mUserHandle = null;
|
|
|
|
return ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NONE;
|
|
} else {
|
|
Log.e(TAG, "Failed to delete private space");
|
|
}
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Error deleting private space", e);
|
|
}
|
|
return ErrorDeletingPrivateSpace.DELETE_PS_ERROR_INTERNAL;
|
|
}
|
|
|
|
/** Returns true if the Private space exists. */
|
|
public synchronized boolean doesPrivateSpaceExist() {
|
|
if (mUserHandle != null) {
|
|
return true;
|
|
}
|
|
|
|
List<UserInfo> users = mUserManager.getProfiles(0);
|
|
for (UserInfo user : users) {
|
|
if (user.isPrivateProfile()) {
|
|
mUserHandle = user.getUserHandle();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** Returns true when the PS is locked or when PS doesn't exist, false otherwise. */
|
|
public synchronized boolean isPrivateSpaceLocked() {
|
|
if (!doesPrivateSpaceExist()) {
|
|
return true;
|
|
}
|
|
|
|
return mUserManager.isQuietModeEnabled(mUserHandle);
|
|
}
|
|
|
|
/**
|
|
* Returns an intent to prompt the user to confirm private profile credentials if it is set
|
|
* otherwise returns intent to confirm device credentials.
|
|
*/
|
|
@Nullable
|
|
public synchronized Intent getPrivateProfileLockCredentialIntent() {
|
|
//TODO(b/307281644): To replace with check for doesPrivateSpaceExist() method once Auth
|
|
// changes are merged.
|
|
if (isPrivateProfileLockSet()) {
|
|
return mKeyguardManager.createConfirmDeviceCredentialIntent(
|
|
/* title= */ null, /* description= */null, mUserHandle.getIdentifier());
|
|
}
|
|
// TODO(b/304796434) Need to try changing this intent to use BiometricPrompt
|
|
return mKeyguardManager.createConfirmDeviceCredentialIntent(
|
|
/* title= */ null, /* description= */ null);
|
|
}
|
|
|
|
/** Returns the instance of {@link PrivateSpaceMaintainer} */
|
|
public static synchronized PrivateSpaceMaintainer getInstance(Context context) {
|
|
if (sPrivateSpaceMaintainer == null) {
|
|
sPrivateSpaceMaintainer = new PrivateSpaceMaintainer(context);
|
|
}
|
|
return sPrivateSpaceMaintainer;
|
|
}
|
|
|
|
private PrivateSpaceMaintainer(Context context) {
|
|
mContext = context.getApplicationContext();
|
|
mUserManager = mContext.getSystemService(UserManager.class);
|
|
mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
|
|
}
|
|
|
|
|
|
// TODO(b/307281644): Remove this method once new auth change is merged
|
|
/**
|
|
* Returns true if private space exists and a separate private profile lock is set
|
|
* otherwise false when the private space does not exit or exists but does not have a
|
|
* separate profile lock.
|
|
*/
|
|
@GuardedBy("this")
|
|
private boolean isPrivateProfileLockSet() {
|
|
return doesPrivateSpaceExist()
|
|
&& mKeyguardManager.isDeviceSecure(mUserHandle.getIdentifier());
|
|
}
|
|
}
|