Merge "Add Private Space settings page" into main
This commit is contained in:
@@ -1175,13 +1175,38 @@
|
||||
|
||||
<!-- Title for the subpage in the "Security & privacy". This page consists of the more security and privacy settings. Can be navigated by Settings -> Security & privacy -> More security & privacy [CHAR LIMIT=NONE] -->
|
||||
<string name="more_security_privacy_settings">More security & privacy</string>
|
||||
<!-- Title for the section that has security entries in the More security & privacy page. [CHAR LIMIT=60] -->
|
||||
<!-- Title for the section that has security entries in the More security & privacy page. Also used for Private Space security category. [CHAR LIMIT=60] -->
|
||||
<string name="security_header">Security</string>
|
||||
<!-- Title for the section that has privacy entries in the More security & privacy page. [CHAR LIMIT=60] -->
|
||||
<string name="privacy_header">Privacy</string>
|
||||
<!-- Title for the section that has work profile entries in the More security & privacy page. [CHAR LIMIT=60] -->
|
||||
<string name="work_profile_category_header">Work profile</string>
|
||||
|
||||
<!-- Title for the Private Space page. [CHAR LIMIT=60] -->
|
||||
<string name="private_space_title">Private Space</string>
|
||||
<!-- Summary for the Private Space page. [CHAR LIMIT=NONE] -->
|
||||
<string name="private_space_summary">Hide apps in a private folder</string>
|
||||
<!-- Title for the Private Space one lock preference. [CHAR LIMIT=60] -->
|
||||
<string name="private_space_one_lock_title">Unlock using screen lock</string>
|
||||
<!-- Title for the preference to hide Private Space. [CHAR LIMIT=60] -->
|
||||
<string name="private_space_hide_title">Show Private Space</string>
|
||||
<!-- System category for the Private Space page. [CHAR LIMIT=30] -->
|
||||
<string name="private_space_category_system">System</string>
|
||||
<!-- Title for the preference to create Private Space. [CHAR LIMIT=60] -->
|
||||
<string name="private_space_create_title">Create Private Space</string>
|
||||
<!-- Title for the preference to delete Private Space. [CHAR LIMIT=60] -->
|
||||
<string name="private_space_delete_title">Delete Private Space</string>
|
||||
<!-- Toast to show when the private space was created. [CHAR LIMIT=NONE] -->
|
||||
<string name="private_space_created">Private Space successfully created</string>
|
||||
<!-- Toast to show when the private space already exists. [CHAR LIMIT=NONE] -->
|
||||
<string name="private_space_already_exists">Private Space already exists</string>
|
||||
<!-- Toast to show when the private space could not be created. [CHAR LIMIT=NONE] -->
|
||||
<string name="private_space_create_failed">Private Space could not be created</string>
|
||||
<!-- Toast to show when the private space was deleted. [CHAR LIMIT=NONE] -->
|
||||
<string name="private_space_deleted">Private Space successfully deleted</string>
|
||||
<!-- Toast to show when the private space could not be deleted. [CHAR LIMIT=NONE] -->
|
||||
<string name="private_space_delete_failed">Private Space could not be deleted</string>
|
||||
|
||||
<!-- Text shown when "Add fingerprint" button is disabled -->
|
||||
<string name="fingerprint_add_max">You can add up to <xliff:g id="count" example="5">%d</xliff:g> fingerprints</string>
|
||||
<!-- Text shown when users has enrolled a maximum number of fingerprints [CHAR LIMIT=NONE] -->
|
||||
|
||||
58
res/xml/private_space_settings.xml
Normal file
58
res/xml/private_space_settings.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="private_space_title"
|
||||
android:title="@string/private_space_title">
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/security_header">
|
||||
|
||||
<SwitchPreference
|
||||
android:key="private_space_use_one_lock"
|
||||
android:title="@string/private_space_one_lock_title"
|
||||
settings:controller="com.android.settings.privatespace.UseOneLockController"
|
||||
settings:searchable="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="private_space_hidden"
|
||||
android:title="@string/private_space_hide_title"
|
||||
settings:controller="com.android.settings.privatespace.HidePrivateSpaceController"
|
||||
settings:searchable="false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/private_space_category_system">
|
||||
|
||||
<Preference
|
||||
android:key="private_space_create"
|
||||
android:title="@string/private_space_create_title"
|
||||
settings:controller="com.android.settings.privatespace.CreatePrivateSpaceController"
|
||||
settings:searchable="false" />
|
||||
|
||||
<Preference
|
||||
android:key="private_space_delete"
|
||||
android:title="@string/private_space_delete_title"
|
||||
settings:controller="com.android.settings.privatespace.DeletePrivateSpaceController"
|
||||
settings:searchable="false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
// TODO(b/293569406): Remove this when we have the setup flow in place to create PS
|
||||
/**
|
||||
* Temp Controller to create the private space from the PS Settings page. This is to allow PM, UX,
|
||||
* and other folks to play around with PS before the PS setup flow is ready.
|
||||
*/
|
||||
public final class CreatePrivateSpaceController extends BasePreferenceController {
|
||||
|
||||
public CreatePrivateSpaceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PrivateSpaceMaintainer.getInstance(mContext).doesPrivateSpaceExist()) {
|
||||
showPrivateSpaceAlreadyExistsToast();
|
||||
return super.handlePreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
if (PrivateSpaceMaintainer.getInstance(mContext).createPrivateSpace()) {
|
||||
showPrivateSpaceCreatedToast();
|
||||
} else {
|
||||
showPrivateSpaceCreationFailedToast();
|
||||
}
|
||||
return super.handlePreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
private void showPrivateSpaceCreatedToast() {
|
||||
Toast.makeText(mContext, R.string.private_space_created, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private void showPrivateSpaceCreationFailedToast() {
|
||||
Toast.makeText(mContext, R.string.private_space_create_failed, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private void showPrivateSpaceAlreadyExistsToast() {
|
||||
Toast.makeText(mContext, R.string.private_space_already_exists, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_INTERNAL;
|
||||
import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NONE;
|
||||
import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NO_PRIVATE_SPACE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/** Controller to delete the private space from the PS Settings page */
|
||||
public class DeletePrivateSpaceController extends BasePreferenceController {
|
||||
private static final String TAG = "DeletePrivateSpaceController";
|
||||
private final PrivateSpaceMaintainer mPrivateSpaceMaintainer;
|
||||
|
||||
static class Injector {
|
||||
PrivateSpaceMaintainer injectPrivateSpaceMaintainer(Context context) {
|
||||
return PrivateSpaceMaintainer.getInstance(context);
|
||||
}
|
||||
}
|
||||
|
||||
public DeletePrivateSpaceController(Context context, String preferenceKey) {
|
||||
this(context, preferenceKey, new Injector());
|
||||
}
|
||||
|
||||
DeletePrivateSpaceController(Context context, String preferenceKey, Injector injector) {
|
||||
super(context, preferenceKey);
|
||||
mPrivateSpaceMaintainer = injector.injectPrivateSpaceMaintainer(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PrivateSpaceMaintainer.ErrorDeletingPrivateSpace error =
|
||||
mPrivateSpaceMaintainer.deletePrivateSpace();
|
||||
if (error == DELETE_PS_ERROR_NONE) {
|
||||
showSuccessfulDeletionToast();
|
||||
} else if (error == DELETE_PS_ERROR_INTERNAL) {
|
||||
showDeletionInternalErrorToast();
|
||||
} else if (error == DELETE_PS_ERROR_NO_PRIVATE_SPACE) {
|
||||
// Ideally this should never happen as PS Settings is not available when there's no
|
||||
// Private Profile.
|
||||
Log.e(TAG, "Unexpected attempt to delete non-existent PS");
|
||||
}
|
||||
return super.handlePreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
/** Shows a toast saying that the private space was deleted */
|
||||
@VisibleForTesting
|
||||
public void showSuccessfulDeletionToast() {
|
||||
Toast.makeText(mContext, R.string.private_space_deleted, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
/** Shows a toast saying that the private space could not be deleted */
|
||||
@VisibleForTesting
|
||||
public void showDeletionInternalErrorToast() {
|
||||
Toast.makeText(mContext, R.string.private_space_delete_failed, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 android.content.Context;
|
||||
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/** Represents the preference controller for (un)hiding the Private Space */
|
||||
public final class HidePrivateSpaceController extends TogglePreferenceController {
|
||||
public HidePrivateSpaceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
// TODO(b/293569406) Need to check this from a persistent store, maybe like SettingsProvider
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
// TODO(b/293569406) Need to save this to a persistent store, maybe like SettingsProvider
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.util.FeatureFlagUtils;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Fragment representing the Private Space dashboard in Settings. */
|
||||
@SearchIndexable
|
||||
public class PrivateSpaceDashboardFragment extends DashboardFragment {
|
||||
private static final String TAG = "PrivateSpaceDashboardFragment";
|
||||
private static final String KEY_CREATE_PROFILE_PREFERENCE = "private_space_create";
|
||||
private static final String KEY_DELETE_PROFILE_PREFERENCE = "private_space_delete";
|
||||
private static final String KEY_ONE_LOCK_PREFERENCE = "private_space_use_one_lock";
|
||||
private static final String KEY_PS_HIDDEN_PREFERENCE = "private_space_hidden";
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.private_space_settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.PRIVATE_SPACE_SETTINGS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.private_space_settings) {
|
||||
@Override
|
||||
protected boolean isPageSearchEnabled(Context context) {
|
||||
// Temporary workaround for hiding PS Settings until the trunk stable feature
|
||||
// flag is available.
|
||||
// TODO(b/295516544): Remove this workaround when trunk stable feature flag is
|
||||
// available.
|
||||
return SafetyCenterManagerWrapper.get().isEnabled(context)
|
||||
&& FeatureFlagUtils.isEnabled(context,
|
||||
FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getNonIndexableKeys(Context context) {
|
||||
List<String> keys = super.getNonIndexableKeys(context);
|
||||
keys.add(KEY_CREATE_PROFILE_PREFERENCE);
|
||||
keys.add(KEY_DELETE_PROFILE_PREFERENCE);
|
||||
keys.add(KEY_ONE_LOCK_PREFERENCE);
|
||||
keys.add(KEY_PS_HIDDEN_PREFERENCE);
|
||||
return keys;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.content.Context;
|
||||
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 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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 android.app.PendingIntent;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.UserManager;
|
||||
import android.safetycenter.SafetyEvent;
|
||||
import android.safetycenter.SafetySourceData;
|
||||
import android.safetycenter.SafetySourceStatus;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
|
||||
import com.android.settingslib.transition.SettingsTransitionHelper;
|
||||
|
||||
/** Private Space safety source for the Safety Center */
|
||||
public final class PrivateSpaceSafetySource {
|
||||
public static final String SAFETY_SOURCE_ID = "AndroidPrivateSpace";
|
||||
private static final String TAG = "PrivateSpaceSafetySource";
|
||||
|
||||
private PrivateSpaceSafetySource() {}
|
||||
|
||||
/** Sets lock screen safety data for Safety Center. */
|
||||
public static void setSafetySourceData(Context context,
|
||||
SafetyEvent safetyEvent) {
|
||||
if (!SafetyCenterManagerWrapper.get().isEnabled(context)) {
|
||||
Log.i(TAG, "Safety Center disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the profile type - we don't want to show this for anything other than primary user.
|
||||
UserManager userManager = context.getSystemService(UserManager.class);
|
||||
if (userManager != null && !userManager.isMainUser()) {
|
||||
Log.i(TAG, "setSafetySourceData not main user");
|
||||
return;
|
||||
}
|
||||
|
||||
// Temporary workaround to help prevent the PS Settings showing up in droidfood builds.
|
||||
// TODO(b/295516544): remove this when the trunk stable feature flag for PS is available.
|
||||
if (!FeatureFlagUtils.isEnabled(context,
|
||||
FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS)) {
|
||||
// Setting null safetySourceData so that an old entry gets cleared out and this way
|
||||
// provide a response since SC always expects one on rescan.
|
||||
SafetyCenterManagerWrapper.get().setSafetySourceData(
|
||||
context,
|
||||
SAFETY_SOURCE_ID,
|
||||
/* safetySourceData */ null,
|
||||
safetyEvent
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
PendingIntent pendingIntent = getPendingIntentForPsDashboard(context);
|
||||
|
||||
SafetySourceStatus status = new SafetySourceStatus.Builder(
|
||||
context.getString(R.string.private_space_title),
|
||||
context.getString(R.string.private_space_summary),
|
||||
SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED)
|
||||
.setPendingIntent(pendingIntent).build();
|
||||
SafetySourceData safetySourceData =
|
||||
new SafetySourceData.Builder().setStatus(status).build();
|
||||
|
||||
Log.d(TAG, "Setting safety source data");
|
||||
SafetyCenterManagerWrapper.get().setSafetySourceData(
|
||||
context,
|
||||
SAFETY_SOURCE_ID,
|
||||
safetySourceData,
|
||||
safetyEvent
|
||||
);
|
||||
}
|
||||
|
||||
private static PendingIntent getPendingIntentForPsDashboard(Context context) {
|
||||
Intent privateSpaceDashboardIntent = new SubSettingLauncher(context)
|
||||
.setDestination(PrivateSpaceDashboardFragment.class.getName())
|
||||
.setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE)
|
||||
.setSourceMetricsCategory(SettingsEnums.PRIVATE_SPACE_SETTINGS)
|
||||
.toIntent()
|
||||
.setIdentifier(SAFETY_SOURCE_ID);
|
||||
|
||||
return PendingIntent
|
||||
.getActivity(
|
||||
context,
|
||||
/* requestCode */ 0,
|
||||
privateSpaceDashboardIntent,
|
||||
PendingIntent.FLAG_IMMUTABLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 android.content.Context;
|
||||
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/** Represents the preference controller for using the same lock as the screen lock */
|
||||
public class UseOneLockController extends TogglePreferenceController {
|
||||
public UseOneLockController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
// TODO(b/293569406) Need to save this to a persistent store, maybe like SettingsProvider
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
// TODO(b/293569406) Need to save this to a persistent store, maybe like SettingsProvider
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import android.content.Intent;
|
||||
import android.safetycenter.SafetyCenterManager;
|
||||
import android.safetycenter.SafetyEvent;
|
||||
|
||||
import com.android.settings.privatespace.PrivateSpaceSafetySource;
|
||||
import com.android.settings.security.ScreenLockPreferenceDetailsUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -79,11 +80,16 @@ public class SafetySourceBroadcastReceiver extends BroadcastReceiver {
|
||||
if (sourceIds.contains(BiometricsSafetySource.SAFETY_SOURCE_ID)) {
|
||||
BiometricsSafetySource.setSafetySourceData(context, safetyEvent);
|
||||
}
|
||||
|
||||
if (sourceIds.contains(PrivateSpaceSafetySource.SAFETY_SOURCE_ID)) {
|
||||
PrivateSpaceSafetySource.setSafetySourceData(context, safetyEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private static void refreshAllSafetySources(Context context, SafetyEvent safetyEvent) {
|
||||
LockScreenSafetySource.setSafetySourceData(context,
|
||||
new ScreenLockPreferenceDetailsUtils(context), safetyEvent);
|
||||
BiometricsSafetySource.setSafetySourceData(context, safetyEvent);
|
||||
PrivateSpaceSafetySource.setSafetySourceData(context, safetyEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_INTERNAL;
|
||||
import static com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NONE;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DeletePrivateSpaceControllerTest {
|
||||
@Mock private PrivateSpaceMaintainer mPrivateSpaceMaintainer;
|
||||
@Mock private Context mContext;
|
||||
|
||||
private Preference mPreference;
|
||||
private DeletePrivateSpaceController mDeletePrivateSpaceController;
|
||||
|
||||
/** Required setup before a test. */
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = ApplicationProvider.getApplicationContext();
|
||||
final String preferenceKey = "private_space_delete";
|
||||
|
||||
mPreference = new Preference(ApplicationProvider.getApplicationContext());
|
||||
mPreference.setKey(preferenceKey);
|
||||
|
||||
mDeletePrivateSpaceController =
|
||||
new DeletePrivateSpaceController(
|
||||
mContext,
|
||||
preferenceKey,
|
||||
new DeletePrivateSpaceController.Injector() {
|
||||
@Override
|
||||
PrivateSpaceMaintainer injectPrivateSpaceMaintainer(Context context) {
|
||||
return mPrivateSpaceMaintainer;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Tests that the controller is always available. */
|
||||
@Test
|
||||
public void getAvailabilityStatus_returnsAvailable() {
|
||||
assertThat(mDeletePrivateSpaceController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
/** Tests that on click it attempts to delete the PS. */
|
||||
@Test
|
||||
public void handlePreferenceTreeClick_attemptsToDeletePrivateSpace() {
|
||||
doReturn(DELETE_PS_ERROR_NONE).when(mPrivateSpaceMaintainer).deletePrivateSpace();
|
||||
DeletePrivateSpaceController spy = Mockito.spy(mDeletePrivateSpaceController);
|
||||
doNothing().when(spy).showSuccessfulDeletionToast();
|
||||
spy.handlePreferenceTreeClick(mPreference);
|
||||
|
||||
verify(mPrivateSpaceMaintainer).deletePrivateSpace();
|
||||
}
|
||||
|
||||
/** Tests that on deletion of PS relevant toast is shown. */
|
||||
@Test
|
||||
public void handlePreferenceTreeClick_onDeletion_showsDeletedToast() {
|
||||
doReturn(DELETE_PS_ERROR_NONE).when(mPrivateSpaceMaintainer).deletePrivateSpace();
|
||||
DeletePrivateSpaceController spy = Mockito.spy(mDeletePrivateSpaceController);
|
||||
doNothing().when(spy).showSuccessfulDeletionToast();
|
||||
spy.handlePreferenceTreeClick(mPreference);
|
||||
|
||||
verify(spy).showSuccessfulDeletionToast();
|
||||
}
|
||||
|
||||
/** Tests that on failing to delete the PS relevant toast is shown. */
|
||||
@Test
|
||||
public void handlePreferenceTreeClick_onDeletionError_showsDeletionFailedToast() {
|
||||
doReturn(DELETE_PS_ERROR_INTERNAL).when(mPrivateSpaceMaintainer).deletePrivateSpace();
|
||||
DeletePrivateSpaceController spy = Mockito.spy(mDeletePrivateSpaceController);
|
||||
doNothing().when(spy).showDeletionInternalErrorToast();
|
||||
spy.handlePreferenceTreeClick(mPreference);
|
||||
|
||||
verify(spy).showDeletionInternalErrorToast();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class HidePrivateSpaceControllerTest {
|
||||
@Mock private Context mContext;
|
||||
private HidePrivateSpaceController mHidePrivateSpaceController;
|
||||
|
||||
/** Required setup before a test. */
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = ApplicationProvider.getApplicationContext();
|
||||
final String preferenceKey = "private_space_hidden";
|
||||
|
||||
mHidePrivateSpaceController = new HidePrivateSpaceController(mContext, preferenceKey);
|
||||
}
|
||||
|
||||
/** Tests that the controller is always available. */
|
||||
@Test
|
||||
public void getAvailabilityStatus_returnsAvailable() {
|
||||
assertThat(mHidePrivateSpaceController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED;
|
||||
import static com.android.settings.privatespace.PrivateSpaceSafetySource.SAFETY_SOURCE_ID;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.safetycenter.SafetyEvent;
|
||||
import android.safetycenter.SafetySourceData;
|
||||
import android.safetycenter.SafetySourceStatus;
|
||||
import android.util.FeatureFlagUtils;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PrivateSpaceSafetySourceTest {
|
||||
private static final SafetyEvent EVENT_TYPE_DEVICE_REBOOTED =
|
||||
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build();
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
@Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
|
||||
|
||||
/** Required setup before a test. */
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
|
||||
|
||||
FeatureFlagUtils
|
||||
.setEnabled(mContext, FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS, true);
|
||||
}
|
||||
|
||||
/** Required setup after a test. */
|
||||
@After
|
||||
public void tearDown() {
|
||||
SafetyCenterManagerWrapper.sInstance = null;
|
||||
}
|
||||
|
||||
/** Tests that when SC is disabled we don't set any data. */
|
||||
@Test
|
||||
public void onDeviceRebootedEvent_whenSafetyCenterDisabled_doesNotSetData() {
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(false);
|
||||
|
||||
PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED);
|
||||
|
||||
verify(mSafetyCenterManagerWrapper, never()).setSafetySourceData(
|
||||
any(), any(), any(), any());
|
||||
}
|
||||
|
||||
/** Tests that when SC is enabled we set data. */
|
||||
@Test
|
||||
public void onDeviceRebootedEvent_whenSafetyCenterEnabled_setsData() {
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true);
|
||||
|
||||
PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED);
|
||||
|
||||
verify(mSafetyCenterManagerWrapper).setSafetySourceData(
|
||||
any(), eq(SAFETY_SOURCE_ID), any(), eq(EVENT_TYPE_DEVICE_REBOOTED));
|
||||
}
|
||||
|
||||
// TODO(b/295516544): Modify this test for the new trunk stable flag instead when available.
|
||||
/** Tests that when the feature is disabled null data is set. */
|
||||
@Test
|
||||
public void setSafetySourceData_whenFeatureDisabled_setsNullData() {
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true);
|
||||
FeatureFlagUtils
|
||||
.setEnabled(mContext, FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS, false);
|
||||
|
||||
PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED);
|
||||
|
||||
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
|
||||
verify(mSafetyCenterManagerWrapper).setSafetySourceData(
|
||||
any(), eq(SAFETY_SOURCE_ID), captor.capture(), eq(EVENT_TYPE_DEVICE_REBOOTED));
|
||||
SafetySourceData safetySourceData = captor.getValue();
|
||||
assertThat(safetySourceData).isNull();
|
||||
|
||||
FeatureFlagUtils
|
||||
.setEnabled(mContext, FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS, true);
|
||||
}
|
||||
|
||||
/** Tests that setSafetySourceData sets the source status enabled. */
|
||||
@Test
|
||||
public void setSafetySourceData_setsEnabled() {
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true);
|
||||
|
||||
PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED);
|
||||
|
||||
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
|
||||
verify(mSafetyCenterManagerWrapper).setSafetySourceData(
|
||||
any(), eq(SAFETY_SOURCE_ID), captor.capture(), eq(EVENT_TYPE_DEVICE_REBOOTED));
|
||||
SafetySourceData safetySourceData = captor.getValue();
|
||||
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
|
||||
assertThat(safetySourceStatus.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
/** Tests that setSafetySourceData sets the PS settings page intent. */
|
||||
@Test
|
||||
public void setSafetySourceData_setsPsIntent() {
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mContext)).thenReturn(true);
|
||||
|
||||
PrivateSpaceSafetySource.setSafetySourceData(mContext, EVENT_TYPE_DEVICE_REBOOTED);
|
||||
|
||||
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
|
||||
verify(mSafetyCenterManagerWrapper).setSafetySourceData(
|
||||
any(), eq(SAFETY_SOURCE_ID), captor.capture(), eq(EVENT_TYPE_DEVICE_REBOOTED));
|
||||
SafetySourceData safetySourceData = captor.getValue();
|
||||
SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
|
||||
assertThat(safetySourceStatus.getPendingIntent().getIntent().getIdentifier())
|
||||
.isEqualTo(SAFETY_SOURCE_ID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class UseOneLockControllerTest {
|
||||
@Mock private Context mContext;
|
||||
private UseOneLockController mUseOneLockController;
|
||||
|
||||
/** Required setup before a test. */
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = ApplicationProvider.getApplicationContext();
|
||||
final String preferenceKey = "private_space_use_one_lock";
|
||||
|
||||
mUseOneLockController = new UseOneLockController(mContext, preferenceKey);
|
||||
}
|
||||
|
||||
/** Tests that the controller is always available. */
|
||||
@Test
|
||||
public void getAvailabilityStatus_returnsAvailable() {
|
||||
assertThat(mUseOneLockController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,7 @@ import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOUR
|
||||
import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCE_IDS;
|
||||
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED;
|
||||
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -33,11 +31,14 @@ import static org.mockito.Mockito.when;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.safetycenter.SafetyEvent;
|
||||
import android.safetycenter.SafetySourceData;
|
||||
import android.util.FeatureFlagUtils;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.privatespace.PrivateSpaceSafetySource;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -216,6 +217,62 @@ public class SafetySourceBroadcastReceiverTest {
|
||||
assertThat(captor.getValue()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that on receiving the refresh broadcast request with the PS source id, the PS data
|
||||
* is set.
|
||||
*/
|
||||
@Test
|
||||
public void onReceive_onRefresh_withPrivateSpaceSourceId_setsPrivateSpaceData() {
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||
Intent intent =
|
||||
new Intent()
|
||||
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
||||
.putExtra(
|
||||
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
||||
new String[] {PrivateSpaceSafetySource.SAFETY_SOURCE_ID})
|
||||
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
|
||||
|
||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
|
||||
verify(mSafetyCenterManagerWrapper, times(1))
|
||||
.setSafetySourceData(any(), captor.capture(), any(), any());
|
||||
|
||||
assertThat(captor.getValue()).isEqualTo(PrivateSpaceSafetySource.SAFETY_SOURCE_ID);
|
||||
}
|
||||
|
||||
/** Tests that the PS source sets null data when it's disabled. */
|
||||
// TODO(b/295516544): Modify this test for the new trunk stable flag instead when available.
|
||||
@Test
|
||||
public void onReceive_onRefresh_withPrivateSpaceFeatureDisabled_setsNullData() {
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||
FeatureFlagUtils
|
||||
.setEnabled(
|
||||
mApplicationContext,
|
||||
FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS,
|
||||
false);
|
||||
|
||||
Intent intent =
|
||||
new Intent()
|
||||
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
||||
.putExtra(
|
||||
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
||||
new String[] {PrivateSpaceSafetySource.SAFETY_SOURCE_ID})
|
||||
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
|
||||
|
||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
|
||||
verify(mSafetyCenterManagerWrapper, times(1))
|
||||
.setSafetySourceData(any(), any(), captor.capture(), any());
|
||||
|
||||
assertThat(captor.getValue()).isEqualTo(null);
|
||||
|
||||
FeatureFlagUtils
|
||||
.setEnabled(
|
||||
mApplicationContext,
|
||||
FeatureFlagUtils.SETTINGS_PRIVATE_SPACE_SETTINGS,
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onReceive_onBootCompleted_setsBootCompleteEvent() {
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||
@@ -223,22 +280,22 @@ public class SafetySourceBroadcastReceiverTest {
|
||||
|
||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||
ArgumentCaptor<SafetyEvent> captor = ArgumentCaptor.forClass(SafetyEvent.class);
|
||||
verify(mSafetyCenterManagerWrapper, times(2))
|
||||
verify(mSafetyCenterManagerWrapper, times(3))
|
||||
.setSafetySourceData(any(), any(), any(), captor.capture());
|
||||
|
||||
SafetyEvent bootEvent = new SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build();
|
||||
assertThat(captor.getAllValues())
|
||||
.containsExactlyElementsIn(Arrays.asList(bootEvent, bootEvent));
|
||||
.containsExactlyElementsIn(Arrays.asList(bootEvent, bootEvent, bootEvent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onReceive_onBootCompleted_sendsBiometricAndLockscreenData() {
|
||||
public void onReceive_onBootCompleted_sendsAllSafetySourcesData() {
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||
Intent intent = new Intent().setAction(Intent.ACTION_BOOT_COMPLETED);
|
||||
|
||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
|
||||
verify(mSafetyCenterManagerWrapper, times(2))
|
||||
verify(mSafetyCenterManagerWrapper, times(3))
|
||||
.setSafetySourceData(any(), captor.capture(), any(), any());
|
||||
List<String> safetySourceIdList = captor.getAllValues();
|
||||
|
||||
@@ -246,5 +303,7 @@ public class SafetySourceBroadcastReceiverTest {
|
||||
id -> id.equals(LockScreenSafetySource.SAFETY_SOURCE_ID))).isTrue();
|
||||
assertThat(safetySourceIdList.stream().anyMatch(
|
||||
id -> id.equals(BiometricsSafetySource.SAFETY_SOURCE_ID))).isTrue();
|
||||
assertThat(safetySourceIdList.stream().anyMatch(
|
||||
id -> id.equals(PrivateSpaceSafetySource.SAFETY_SOURCE_ID))).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user