Snap for 7213262 from d2ca004392 to sc-v2-release

Change-Id: I515a9b429340a1d229169fc06d8755eebea2b793
This commit is contained in:
android-build-team Robot
2021-03-17 01:08:11 +00:00
19 changed files with 554 additions and 52 deletions

View File

@@ -1873,7 +1873,7 @@
<!-- Used in the settings screen to secure NFC [CHAR LIMIT=NONE] --> <!-- Used in the settings screen to secure NFC [CHAR LIMIT=NONE] -->
<string name="nfc_secure_settings_title">Require device unlock for NFC</string> <string name="nfc_secure_settings_title">Require device unlock for NFC</string>
<!-- Description of Secure NFC in the 1st level settings screen. [CHAR LIMIT=NONE] --> <!-- Description of Secure NFC in the 1st level settings screen. [CHAR LIMIT=NONE] -->
<string name="nfc_secure_toggle_summary" product="default">Allow NFC Payment and Transit use only when screen is unlocked</string> <string name="nfc_secure_toggle_summary" product="default">Allow NFC use only when screen is unlocked</string>
<!-- Used to enter the Android Beam sharing preferences screen. This phrase is a trademark. [CHAR LIMIT=32] --> <!-- Used to enter the Android Beam sharing preferences screen. This phrase is a trademark. [CHAR LIMIT=32] -->
<string name="android_beam_settings_title">Android Beam</string> <string name="android_beam_settings_title">Android Beam</string>
@@ -2847,6 +2847,10 @@
<string name="adaptive_sleep_contextual_slice_title">Turn on screen attention</string> <string name="adaptive_sleep_contextual_slice_title">Turn on screen attention</string>
<!-- Description about the contextual adaptive sleep card [CHAR LIMIT=NONE]--> <!-- Description about the contextual adaptive sleep card [CHAR LIMIT=NONE]-->
<string name="adaptive_sleep_contextual_slice_summary">Keep screen on when looking at it</string> <string name="adaptive_sleep_contextual_slice_summary">Keep screen on when looking at it</string>
<!-- auto_rotate settings screen, title about the required permission is missing [CHAR LIMIT=NONE]-->
<string name="auto_rotate_summary_no_permission">Camera access is required for Face Detection. Tap to manage permissions for Device Personalization Services</string>
<!-- auto_rotate settings screen, text for the camera permission button [CHAR LIMIT=NONE]-->
<string name="auto_rotate_manage_permission_button">Manage permissions</string>
<!-- Night display screen, setting option name to enable night display (renamed "Night Light" with title caps). [CHAR LIMIT=30] --> <!-- Night display screen, setting option name to enable night display (renamed "Night Light" with title caps). [CHAR LIMIT=30] -->
<string name="night_display_title">Night Light</string> <string name="night_display_title">Night Light</string>
@@ -9800,6 +9804,18 @@
<!-- Runtime permissions preference summary, which describes what the permission manager does. [CHAR LIMIT=NONE] --> <!-- Runtime permissions preference summary, which describes what the permission manager does. [CHAR LIMIT=NONE] -->
<string name="runtime_permissions_summary_control_app_access">Control app access to your data</string> <string name="runtime_permissions_summary_control_app_access">Control app access to your data</string>
<!-- Label for showing apps that have not been used for months. [CHAR LIMIT=40]-->
<string name="unused_apps">Unused apps</string>
<!-- Summary of number of apps that have not been used for months. [CHAR LIMIT=40]-->
<plurals name="unused_apps_summary">
<item quantity="one"><xliff:g id="count" example="1">%d</xliff:g> unused app</item>
<item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> unused apps</item>
</plurals>
<!-- Label of a switch preference that controls whether the system will remove the permissions and free up space when the app has not been used for months [CHAR LIMIT=40]-->
<string name="unused_apps_switch">Remove permissions and free up space</string>
<!-- Label for showing all apps in list [CHAR LIMIT=30] --> <!-- Label for showing all apps in list [CHAR LIMIT=30] -->
<string name="filter_all_apps">All apps</string> <string name="filter_all_apps">All apps</string>
<!-- Label for showing enabled apps in list [CHAR LIMIT=30] --> <!-- Label for showing enabled apps in list [CHAR LIMIT=30] -->
@@ -10506,6 +10522,9 @@
<string name="admin_device_owner_message">Your admin can monitor and manage apps and data <string name="admin_device_owner_message">Your admin can monitor and manage apps and data
associated with this device, including settings, permissions, corporate access, associated with this device, including settings, permissions, corporate access,
network activity, and the device\'s location information.</string> network activity, and the device\'s location information.</string>
<!-- Shown in admin details page to warn user about policies the admin can set on a financed device. [CHAR LIMIT=NONE] -->
<string name="admin_financed_message">Your device admin may be able to access data associated
with this device and change this device\s settings.</string>
<!-- Turn off a conditional state of the device (e.g. airplane mode, or hotspot) [CHAR LIMIT=30] --> <!-- Turn off a conditional state of the device (e.g. airplane mode, or hotspot) [CHAR LIMIT=30] -->
<string name="condition_turn_off">Turn off</string> <string name="condition_turn_off">Turn off</string>

View File

@@ -83,6 +83,16 @@
<intent android:action="android.intent.action.MANAGE_PERMISSIONS"/> <intent android:action="android.intent.action.MANAGE_PERMISSIONS"/>
</Preference> </Preference>
<Preference
android:key="hibernated_apps"
android:title="@string/unused_apps"
android:summary="@string/summary_placeholder"
android:order="13"
settings:keywords="app_hibernation_key"
settings:controller="com.android.settings.applications.HibernatedAppsPreferenceController">
<intent android:action="android.intent.action.MANAGE_UNUSED_APPS"/>
</Preference>
<com.android.settingslib.RestrictedPreference <com.android.settingslib.RestrictedPreference
android:key="app_and_notif_cell_broadcast_settings" android:key="app_and_notif_cell_broadcast_settings"
android:title="@string/cell_broadcast_settings" android:title="@string/cell_broadcast_settings"

View File

@@ -120,6 +120,19 @@
android:title="@string/sms_application_title" android:title="@string/sms_application_title"
android:summary="@string/summary_placeholder" /> android:summary="@string/summary_placeholder" />
<PreferenceCategory
android:key="app_hibernation_info"
android:title="@string/unused_apps"
settings:controller=
"com.android.settings.applications.appinfo.AppHibernationPreferenceCategoryController">
<SwitchPreference
android:key="hibernation_switch"
android:title="@string/unused_apps_switch"
settings:controller=
"com.android.settings.applications.appinfo.HibernationSwitchPreferenceController" />
</PreferenceCategory>
<!-- Advanced apps settings --> <!-- Advanced apps settings -->
<PreferenceCategory <PreferenceCategory
android:key="advanced_app_info" android:key="advanced_app_info"

View File

@@ -134,6 +134,19 @@
android:title="@string/sms_application_title" android:title="@string/sms_application_title"
android:summary="@string/summary_placeholder" /> android:summary="@string/summary_placeholder" />
<PreferenceCategory
android:key="app_hibernation_info"
android:title="@string/unused_apps"
settings:controller=
"com.android.settings.applications.appinfo.AppHibernationPreferenceCategoryController">
<SwitchPreference
android:key="hibernation_switch"
android:title="@string/unused_apps_switch"
settings:controller=
"com.android.settings.applications.appinfo.HibernationSwitchPreferenceController" />
</PreferenceCategory>
<!-- Advanced apps settings --> <!-- Advanced apps settings -->
<PreferenceCategory <PreferenceCategory
android:key="advanced_app_info" android:key="advanced_app_info"

View File

@@ -66,6 +66,16 @@
android:key="dashboard_tile_placeholder" android:key="dashboard_tile_placeholder"
android:order="10"/> android:order="10"/>
<Preference
android:key="hibernated_apps"
android:title="@string/unused_apps"
android:summary="@string/summary_placeholder"
android:order="15"
settings:keywords="app_hibernation_key"
settings:controller="com.android.settings.applications.HibernatedAppsPreferenceController">
<intent android:action="android.intent.action.MANAGE_UNUSED_APPS"/>
</Preference>
<Preference <Preference
android:key="special_access_v2" android:key="special_access_v2"
android:fragment="com.android.settings.applications.specialaccess.SpecialAccessSettings" android:fragment="com.android.settings.applications.specialaccess.SpecialAccessSettings"

View File

@@ -20,11 +20,10 @@
xmlns:settings="http://schemas.android.com/apk/res-auto" xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/accelerometer_title" > android:title="@string/accelerometer_title" >
<Preference <com.android.settingslib.widget.BannerMessagePreference
android:key="face_rotate_permission" android:key="face_rotate_permission"
android:title="@string/adaptive_sleep_title_no_permission" android:title="@string/adaptive_sleep_title_no_permission"
android:summary="@string/adaptive_sleep_summary_no_permission" android:summary="@string/auto_rotate_summary_no_permission"
android:icon="@drawable/ic_info_outline_24"
settings:controller="com.android.settings.display.SmartAutoRotatePermissionController" /> settings:controller="com.android.settings.display.SmartAutoRotatePermissionController" />
<SwitchPreference <SwitchPreference

View File

@@ -153,6 +153,9 @@ public final class Utils extends com.android.settingslib.Utils {
public static final String PROPERTY_LOCATION_INDICATOR_SETTINGS_ENABLED = public static final String PROPERTY_LOCATION_INDICATOR_SETTINGS_ENABLED =
"location_indicator_settings_enabled"; "location_indicator_settings_enabled";
/** Whether or not app hibernation is enabled on the device **/
public static final String PROPERTY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled";
/** /**
* Finds a matching activity for a preference's intent. If a matching * Finds a matching activity for a preference's intent. If a matching
* activity is not found, it will remove the preference. * activity is not found, it will remove the preference.

View File

@@ -0,0 +1,61 @@
/*
* 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 android.content.Context;
import android.provider.DeviceConfig;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
/**
* A preference controller handling the logic for updating summary of hibernated apps.
* TODO(b/181172051): add intent to launch Auto Revoke UI in app_and_notification.xml
*/
public final class HibernatedAppsPreferenceController extends BasePreferenceController {
private static final String TAG = "HibernatedAppsPrefController";
public HibernatedAppsPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
@Override
public int getAvailabilityStatus() {
return isHibernationEnabled() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@Override
public CharSequence getSummary() {
final int numHibernated = getNumHibernated();
return mContext.getResources().getQuantityString(
R.plurals.unused_apps_summary, numHibernated, numHibernated);
}
private int getNumHibernated() {
//TODO(b/181172051): hook into hibernation service to get the number of hibernated apps.
return 0;
}
private static boolean isHibernationEnabled() {
return DeviceConfig.getBoolean(
NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED, false);
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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 android.content.Context;
import com.android.settings.widget.PreferenceCategoryController;
/**
* A preference category controller serves as the parent for app hibernation related preference.
*/
public final class AppHibernationPreferenceCategoryController extends PreferenceCategoryController {
public AppHibernationPreferenceCategoryController(Context context, String key) {
super(context, key);
}
}

View File

@@ -170,6 +170,13 @@ public class AppInfoDashboardFragment extends DashboardFragment
use(ExtraAppInfoPreferenceController.class).setPackageName(packageName); use(ExtraAppInfoPreferenceController.class).setPackageName(packageName);
} }
final HibernationSwitchPreferenceController appHibernationSettings =
use(HibernationSwitchPreferenceController.class);
appHibernationSettings.setParentFragment(this);
appHibernationSettings.setPackage(packageName);
use(AppHibernationPreferenceCategoryController.class).setChildren(
Arrays.asList(appHibernationSettings));
final WriteSystemSettingsPreferenceController writeSystemSettings = final WriteSystemSettingsPreferenceController writeSystemSettings =
use(WriteSystemSettingsPreferenceController.class); use(WriteSystemSettingsPreferenceController.class);
writeSystemSettings.setParentFragment(this); writeSystemSettings.setParentFragment(this);

View File

@@ -0,0 +1,145 @@
/*
* 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 android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.util.Slog;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.google.common.annotations.VisibleForTesting;
/**
* A PreferenceController handling the logic for exempting hibernation of app
*/
public final class HibernationSwitchPreferenceController extends AppInfoPreferenceControllerBase
implements LifecycleObserver, AppOpsManager.OnOpChangedListener,
Preference.OnPreferenceChangeListener {
private static final String TAG = "HibernationSwitchPrefController";
private String mPackageName;
private final AppOpsManager mAppOpsManager;
private int mPackageUid;
@VisibleForTesting
boolean mIsPackageSet;
private boolean mIsPackageExemptByDefault;
public HibernationSwitchPreferenceController(Context context,
String preferenceKey) {
super(context, preferenceKey);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
if (mIsPackageSet) {
mAppOpsManager.startWatchingMode(
OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, mPackageName, this);
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
mAppOpsManager.stopWatchingMode(this);
}
@Override
public int getAvailabilityStatus() {
return isHibernationEnabled() && mIsPackageSet ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
/**
* Set the package. And also retrieve details from package manager. Some packages may be
* exempted from hibernation by default.
* @param packageName The name of the package whose hibernation state to be managed.
*/
void setPackage(@NonNull String packageName) {
mPackageName = packageName;
final PackageManager packageManager = mContext.getPackageManager();
// Q- packages exempt by default, except R- on Auto since Auto-Revoke was skipped in R
final int maxTargetSdkVersionForExemptApps =
packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
? android.os.Build.VERSION_CODES.R
: android.os.Build.VERSION_CODES.Q;
try {
mPackageUid = packageManager.getPackageUidAsUser(
packageName, mContext.getUserId());
mIsPackageExemptByDefault = packageManager.getTargetSdkVersion(packageName)
<= maxTargetSdkVersionForExemptApps;
mIsPackageSet = true;
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Package [" + mPackageName + "] is not found!");
mIsPackageSet = false;
}
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
((SwitchPreference) preference).setChecked(!isPackageHibernationExemptByUser());
}
@VisibleForTesting
boolean isPackageHibernationExemptByUser() {
if (!mIsPackageSet) return true;
final int mode = mAppOpsManager.unsafeCheckOpNoThrow(
OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, mPackageUid, mPackageName);
return mode == MODE_DEFAULT ? mIsPackageExemptByDefault : mode != MODE_ALLOWED;
}
@Override
public void onOpChanged(String op, String packageName) {
if (OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED.equals(op)
&& TextUtils.equals(mPackageName, packageName)) {
updateState(mPreference);
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object isChecked) {
try {
mAppOpsManager.setUidMode(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, mPackageUid,
(boolean) isChecked ? MODE_ALLOWED : MODE_IGNORED);
} catch (RuntimeException e) {
return false;
}
return true;
}
private static boolean isHibernationEnabled() {
return DeviceConfig.getBoolean(
NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED, false);
}
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.applications.specialaccess.deviceadmin; package com.android.settings.applications.specialaccess.deviceadmin;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AppOpsManager; import android.app.AppOpsManager;
@@ -661,7 +663,11 @@ public class DeviceAdminAdd extends Activity {
mAdminWarning.setText(R.string.admin_profile_owner_user_message); mAdminWarning.setText(R.string.admin_profile_owner_user_message);
} else { } else {
// Show device owner description. // Show device owner description.
mAdminWarning.setText(R.string.admin_device_owner_message); if (isFinancedDevice()) {
mAdminWarning.setText(R.string.admin_financed_message);
} else {
mAdminWarning.setText(R.string.admin_device_owner_message);
}
} }
mActionButton.setText(R.string.remove_device_admin); mActionButton.setText(R.string.remove_device_admin);
mActionButton.setEnabled(false); mActionButton.setEnabled(false);
@@ -759,6 +765,11 @@ public class DeviceAdminAdd extends Activity {
return info != null ? info.isManagedProfile() : false; return info != null ? info.isManagedProfile() : false;
} }
private boolean isFinancedDevice() {
return mDPM.isDeviceManaged() && mDPM.getDeviceOwnerType(
mDPM.getDeviceOwnerComponentOnAnyUser()) == DEVICE_OWNER_TYPE_FINANCED;
}
/** /**
* @return an {@link Optional} containing the admin with a given package name, if it exists, * @return an {@link Optional} containing the admin with a given package name, if it exists,
* or {@link Optional#empty()} otherwise. * or {@link Optional#empty()} otherwise.

View File

@@ -30,7 +30,6 @@ import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.lifecycle.LifecycleObserver;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
@@ -39,7 +38,6 @@ import com.android.settings.slices.SettingsSliceProvider;
import com.android.settings.slices.SliceData; import com.android.settings.slices.SliceData;
import com.android.settings.slices.Sliceable; import com.android.settings.slices.Sliceable;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.search.SearchIndexableRaw;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@@ -52,9 +50,6 @@ import java.util.List;
* Abstract class to consolidate utility between preference controllers and act as an interface * Abstract class to consolidate utility between preference controllers and act as an interface
* for Slices. The abstract classes that inherit from this class will act as the direct interfaces * for Slices. The abstract classes that inherit from this class will act as the direct interfaces
* for each type when plugging into Slices. * for each type when plugging into Slices.
* <p>
* 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 public abstract class BasePreferenceController extends AbstractPreferenceController implements
Sliceable { Sliceable {

View File

@@ -27,7 +27,6 @@ import android.util.Log;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.LifecycleObserver;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
@@ -45,6 +44,7 @@ import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.PrimarySwitchPreference; import com.android.settings.widget.PrimarySwitchPreference;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle; 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.CategoryKey;
import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.ProviderTile; import com.android.settingslib.drawer.ProviderTile;

View File

@@ -22,11 +22,12 @@ import static com.android.settings.display.SmartAutoRotateController.isRotationR
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; 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.settings.core.BasePreferenceController;
import com.android.settingslib.widget.BannerMessagePreference;
/** /**
* The controller of camera based rotate permission warning preference. The preference appears when * 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)); 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 @Override
@AvailabilityStatus @AvailabilityStatus
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
@@ -51,13 +64,4 @@ public class SmartAutoRotatePermissionController extends BasePreferenceControlle
? AVAILABLE_UNSEARCHABLE ? AVAILABLE_UNSEARCHABLE
: UNSUPPORTED_ON_DEVICE; : UNSUPPORTED_ON_DEVICE;
} }
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (TextUtils.equals(getPreferenceKey(), preference.getKey())) {
mContext.startActivity(mIntent);
return true;
}
return super.handlePreferenceTreeClick(preference);
}
} }

View File

@@ -141,17 +141,14 @@ public class ActionDisabledByAdminDialogHelper {
} }
private boolean isNotCurrentUserOrProfile(ComponentName admin, int userId) { private boolean isNotCurrentUserOrProfile(ComponentName admin, int userId) {
return !isFinancedDevice() return !RestrictedLockUtilsInternal.isAdminInCurrentUserOrProfile(mActivity, admin)
&& (!RestrictedLockUtilsInternal.isAdminInCurrentUserOrProfile(mActivity, admin) || !RestrictedLockUtils.isCurrentUserOrProfile(mActivity, userId);
|| !RestrictedLockUtils.isCurrentUserOrProfile(mActivity, userId));
} }
@VisibleForTesting @VisibleForTesting
void setAdminSupportIcon(View root, ComponentName admin, int userId) { void setAdminSupportIcon(View root, ComponentName admin, int userId) {
ImageView supportIconView = root.requireViewById(R.id.admin_support_icon); ImageView supportIconView = root.requireViewById(R.id.admin_support_icon);
if (isFinancedDevice()) { if (isNotCurrentUserOrProfile(admin, userId)) {
supportIconView.setVisibility(View.GONE);
} else if (isNotCurrentUserOrProfile(admin, userId)) {
supportIconView.setImageDrawable( supportIconView.setImageDrawable(
mActivity.getDrawable(com.android.internal.R.drawable.ic_info)); mActivity.getDrawable(com.android.internal.R.drawable.ic_info));

View File

@@ -36,10 +36,8 @@ import android.content.pm.UserInfo;
import android.os.Process; import android.os.Process;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
@@ -108,20 +106,6 @@ public class ActionDisabledByAdminDialogHelperTest {
Settings.DeviceAdminSettingsActivity.class.getName())); 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 @Test
public void testSetAdminSupportTitle() { public void testSetAdminSupportTitle() {
final ViewGroup view = new FrameLayout(mActivity); final ViewGroup view = new FrameLayout(mActivity);
@@ -260,14 +244,6 @@ public class ActionDisabledByAdminDialogHelperTest {
verify(builder, never()).setNeutralButton(anyInt(), any()); 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, private static TextView createAdminSupportDialogTitleTextView(final ViewGroup view,
final Activity activity) { final Activity activity) {
final TextView textView = new TextView(activity); final TextView textView = new TextView(activity);

View File

@@ -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);
}
}

View File

@@ -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);
}
}