diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7e10006638d..01c38d83734 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1873,7 +1873,7 @@
Require device unlock for NFC
- Allow NFC Payment and Transit use only when screen is unlocked
+ Allow NFC use only when screen is unlocked
Android Beam
@@ -2847,6 +2847,10 @@
Turn on screen attention
Keep screen on when looking at it
+
+ Camera access is required for Face Detection. Tap to manage permissions for Device Personalization Services
+
+ Manage permissions
Night Light
@@ -9800,6 +9804,18 @@
Control app access to your data
+
+ Unused apps
+
+
+
+ - %d unused app
+ - %d unused apps
+
+
+
+ Remove permissions and free up space
+
All apps
@@ -10506,6 +10522,9 @@
Your admin can monitor and manage apps and data
associated with this device, including settings, permissions, corporate access,
network activity, and the device\'s location information.
+
+ Your device admin may be able to access data associated
+ with this device and change this device\’s settings.
Turn off
diff --git a/res/xml/app_and_notification.xml b/res/xml/app_and_notification.xml
index 49d8e9b85fd..8b4c912485c 100644
--- a/res/xml/app_and_notification.xml
+++ b/res/xml/app_and_notification.xml
@@ -83,6 +83,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- * Controllers defined in xml are automatically {@link Lifecycle#addObserver(LifecycleObserver)
- * wired up} to the settings lifecycle if they implement {@link LifecycleObserver}.
*/
public abstract class BasePreferenceController extends AbstractPreferenceController implements
Sliceable {
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 7acbd1997c5..1b2be809a6d 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -27,7 +27,6 @@ import android.util.Log;
import androidx.annotation.CallSuper;
import androidx.annotation.VisibleForTesting;
-import androidx.lifecycle.LifecycleObserver;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
@@ -45,6 +44,7 @@ import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.PrimarySwitchPreference;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.ProviderTile;
diff --git a/src/com/android/settings/display/SmartAutoRotatePermissionController.java b/src/com/android/settings/display/SmartAutoRotatePermissionController.java
index 484db31f371..caa306d6a9d 100644
--- a/src/com/android/settings/display/SmartAutoRotatePermissionController.java
+++ b/src/com/android/settings/display/SmartAutoRotatePermissionController.java
@@ -22,11 +22,12 @@ import static com.android.settings.display.SmartAutoRotateController.isRotationR
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
-import android.text.TextUtils;
-import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.BannerMessagePreference;
/**
* The controller of camera based rotate permission warning preference. The preference appears when
@@ -44,6 +45,18 @@ public class SmartAutoRotatePermissionController extends BasePreferenceControlle
mIntent.setData(Uri.parse("package:" + packageName));
}
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ final BannerMessagePreference preference =
+ (BannerMessagePreference) screen.findPreference(getPreferenceKey());
+ preference
+ .setPositiveButtonText(R.string.auto_rotate_manage_permission_button)
+ .setPositiveButtonOnClickListener(v -> {
+ mContext.startActivity(mIntent);
+ });
+ }
+
@Override
@AvailabilityStatus
public int getAvailabilityStatus() {
@@ -51,13 +64,4 @@ public class SmartAutoRotatePermissionController extends BasePreferenceControlle
? AVAILABLE_UNSEARCHABLE
: UNSUPPORTED_ON_DEVICE;
}
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- if (TextUtils.equals(getPreferenceKey(), preference.getKey())) {
- mContext.startActivity(mIntent);
- return true;
- }
- return super.handlePreferenceTreeClick(preference);
- }
}
diff --git a/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java b/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java
index cf23c94c74b..1140291a2a1 100644
--- a/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java
+++ b/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelper.java
@@ -141,17 +141,14 @@ public class ActionDisabledByAdminDialogHelper {
}
private boolean isNotCurrentUserOrProfile(ComponentName admin, int userId) {
- return !isFinancedDevice()
- && (!RestrictedLockUtilsInternal.isAdminInCurrentUserOrProfile(mActivity, admin)
- || !RestrictedLockUtils.isCurrentUserOrProfile(mActivity, userId));
+ return !RestrictedLockUtilsInternal.isAdminInCurrentUserOrProfile(mActivity, admin)
+ || !RestrictedLockUtils.isCurrentUserOrProfile(mActivity, userId);
}
@VisibleForTesting
void setAdminSupportIcon(View root, ComponentName admin, int userId) {
ImageView supportIconView = root.requireViewById(R.id.admin_support_icon);
- if (isFinancedDevice()) {
- supportIconView.setVisibility(View.GONE);
- } else if (isNotCurrentUserOrProfile(admin, userId)) {
+ if (isNotCurrentUserOrProfile(admin, userId)) {
supportIconView.setImageDrawable(
mActivity.getDrawable(com.android.internal.R.drawable.ic_info));
diff --git a/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelperTest.java b/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelperTest.java
index b245017b680..5c3dacd46de 100644
--- a/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelperTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/ActionDisabledByAdminDialogHelperTest.java
@@ -36,10 +36,8 @@ import android.content.pm.UserInfo;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
-import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
@@ -108,20 +106,6 @@ public class ActionDisabledByAdminDialogHelperTest {
Settings.DeviceAdminSettingsActivity.class.getName()));
}
- @Test
- public void testSetAdminSupportIconForFinancedDevice_adminSupportIconIsGone() {
- final ShadowDevicePolicyManager dpmShadow = ShadowDevicePolicyManager.getShadow();
- final ViewGroup view = new FrameLayout(mActivity);
- final ImageView supportIconImageView = createAdminSupportIconImageView(view, mActivity);
- final ComponentName component = new ComponentName("some.package.name",
- "some.package.name.SomeClass");
- setupFinancedDevice(dpmShadow);
-
- mHelper.setAdminSupportIcon(view, component, 123);
-
- assertEquals(View.GONE, supportIconImageView.getVisibility());
- }
-
@Test
public void testSetAdminSupportTitle() {
final ViewGroup view = new FrameLayout(mActivity);
@@ -260,14 +244,6 @@ public class ActionDisabledByAdminDialogHelperTest {
verify(builder, never()).setNeutralButton(anyInt(), any());
}
- private static ImageView createAdminSupportIconImageView(final ViewGroup view,
- final Activity activity) {
- final ImageView supportIconView = new ImageView(activity);
- supportIconView.setId(R.id.admin_support_icon);
- view.addView(supportIconView);
- return supportIconView;
- }
-
private static TextView createAdminSupportDialogTitleTextView(final ViewGroup view,
final Activity activity) {
final TextView textView = new TextView(activity);
diff --git a/tests/unit/src/com/android/settings/applications/HibernatedAppsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/HibernatedAppsPreferenceControllerTest.java
new file mode 100644
index 00000000000..cf4c53e157c
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/HibernatedAppsPreferenceControllerTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 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.applications;
+
+import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
+
+import static com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED;
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.provider.DeviceConfig;
+
+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;
+
+/**
+ * TODO(b/181172051): test getNumberHibernated() when the API implemented
+ */
+@RunWith(AndroidJUnit4.class)
+public class HibernatedAppsPreferenceControllerTest {
+
+ private static final String KEY = "key";
+ private Context mContext;
+ private HibernatedAppsPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
+ "true", false);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mController = new HibernatedAppsPreferenceController(mContext, KEY);
+ }
+
+ @Test
+ public void getAvailabilityStatus_featureDisabled_shouldNotReturnAvailable() {
+ DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
+ "false", true);
+
+ assertThat((mController).getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceControllerTest.java
new file mode 100644
index 00000000000..e27942a6e69
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/appinfo/HibernationSwitchPreferenceControllerTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2021 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.applications.appinfo;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED;
+import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
+
+import static com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED;
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.provider.DeviceConfig;
+
+import androidx.preference.SwitchPreference;
+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.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class HibernationSwitchPreferenceControllerTest {
+ private static final int PACKAGE_UID = 1;
+ private static final String INVALID_PACKAGE_NAME = "invalid_package";
+ private static final String KEY = "key";
+ private static final String VALID_PACKAGE_NAME = "package";
+ private static final String EXEMPTED_PACKAGE_NAME = "exempted_package";
+ private static final String UNEXEMPTED_PACKAGE_NAME = "unexempted_package";
+ @Mock
+ private AppOpsManager mAppOpsManager;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private SwitchPreference mPreference;
+
+ private HibernationSwitchPreferenceController mController;
+ private Context mContext;
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
+ when(mPackageManager.getPackageUidAsUser(eq(VALID_PACKAGE_NAME), anyInt()))
+ .thenReturn(PACKAGE_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(INVALID_PACKAGE_NAME), anyInt()))
+ .thenThrow(new PackageManager.NameNotFoundException());
+ when(mPackageManager.getTargetSdkVersion(eq(EXEMPTED_PACKAGE_NAME)))
+ .thenReturn(android.os.Build.VERSION_CODES.Q);
+ when(mPackageManager.getTargetSdkVersion(eq(UNEXEMPTED_PACKAGE_NAME)))
+ .thenReturn(android.os.Build.VERSION_CODES.S);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
+ "true", true /* makeDefault */);
+ mController = new HibernationSwitchPreferenceController(mContext, KEY);
+ when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
+ }
+
+ @Test
+ public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable() {
+ mController.setPackage(VALID_PACKAGE_NAME);
+ DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
+ "false", true /* makeDefault */);
+
+ assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_invalidPackage_shouldReturnNotAvailable() {
+ mController.setPackage(INVALID_PACKAGE_NAME);
+
+ assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_validPackage_shouldReturnAvailable() {
+ mController.setPackage(VALID_PACKAGE_NAME);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void updateState_exemptedByDefaultPackage_shouldNotCheck() {
+ when(mAppOpsManager.unsafeCheckOpNoThrow(
+ eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(EXEMPTED_PACKAGE_NAME)))
+ .thenReturn(MODE_DEFAULT);
+ mController.setPackage(EXEMPTED_PACKAGE_NAME);
+
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(false);
+ }
+
+ @Test
+ public void updateState_exemptedPackageOverrideByUser_shouldCheck() {
+ when(mAppOpsManager.unsafeCheckOpNoThrow(
+ eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(EXEMPTED_PACKAGE_NAME)))
+ .thenReturn(MODE_ALLOWED);
+ mController.setPackage(EXEMPTED_PACKAGE_NAME);
+
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(true);
+ }
+
+ @Test
+ public void updateState_unexemptedPackageOverrideByUser_shouldNotCheck() {
+ when(mAppOpsManager.unsafeCheckOpNoThrow(
+ eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(UNEXEMPTED_PACKAGE_NAME)))
+ .thenReturn(MODE_IGNORED);
+ mController.setPackage(UNEXEMPTED_PACKAGE_NAME);
+
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(false);
+ }
+}