diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 4fa39649718..eae5eaac7e7 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2362,7 +2362,6 @@ android:name="Settings$DataUsageSummaryActivity" android:label="@string/data_usage_summary_title" android:icon="@drawable/ic_settings_data_usage" - android:enabled="false" android:taskAffinity="com.android.settings" android:parentActivityName="Settings"> diff --git a/res/layout/battery_header.xml b/res/layout/battery_header.xml index df45d15fd6d..9f5bde99019 100644 --- a/res/layout/battery_header.xml +++ b/res/layout/battery_header.xml @@ -31,6 +31,7 @@ android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginStart="56dp" + android:layout_marginEnd="8dp" android:orientation="vertical"> diff --git a/res/layout/screen_zoom_preview_app_icon.xml b/res/layout/screen_zoom_preview_app_icon.xml index 7d7d983ff40..087afb832bc 100644 --- a/res/layout/screen_zoom_preview_app_icon.xml +++ b/res/layout/screen_zoom_preview_app_icon.xml @@ -14,33 +14,28 @@ limitations under the License. --> - + - + + - - - - - - \ No newline at end of file + android:ellipsize="end" + android:gravity="center_horizontal|top" + android:singleLine="true" + android:textAppearance="@android:style/TextAppearance.Material.Caption" /> + \ No newline at end of file diff --git a/res/layout/usage_view.xml b/res/layout/usage_view.xml index 16b4916eff5..c24f28974ac 100644 --- a/res/layout/usage_view.xml +++ b/res/layout/usage_view.xml @@ -80,8 +80,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:orientation="horizontal" - android:layoutDirection="ltr"> + android:orientation="horizontal"> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 08160ba3154..30d1e6c36e5 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -251,7 +251,6 @@ 8dp - 88dp 10dp 32sp 16sp diff --git a/res/values/strings.xml b/res/values/strings.xml index 51ec5901793..f0394c9e5e9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -289,7 +289,7 @@ Tap to pair with %1$s. Received files - + Files received via Bluetooth @@ -6999,6 +6999,9 @@ serial number, hardware version android security patch level, baseband version, kernel version + + dark theme + bug diff --git a/res/xml/app_and_notification.xml b/res/xml/app_and_notification.xml index 53e575f6f9a..dd661e08872 100644 --- a/res/xml/app_and_notification.xml +++ b/res/xml/app_and_notification.xml @@ -69,7 +69,7 @@ diff --git a/res/xml/battery_saver_settings.xml b/res/xml/battery_saver_settings.xml index 0460459d961..eb4954f8ca8 100644 --- a/res/xml/battery_saver_settings.xml +++ b/res/xml/battery_saver_settings.xml @@ -29,8 +29,8 @@ + android:max="15" + android:min="1" /> + settings:controller="com.android.settings.display.SystemUiThemePreferenceController" + settings:keywords="@string/keywords_systemui_theme" /> + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:settings="http://schemas.android.com/apk/res-auto" + android:key="special_app_access_screen" + android:title="@string/special_access"> + settings:keywords="@string/keywords_ignore_optimizations" + settings:controller="com.android.settings.applications.specialaccess.HighPowerAppsController"> @@ -33,7 +34,8 @@ + android:fragment="com.android.settings.DeviceAdminSettings" + settings:controller="com.android.settings.applications.specialaccess.DeviceAdministratorsController" /> + android:fragment="com.android.settings.notification.ZenAccessSettings" + settings:controller="com.android.settings.applications.specialaccess.ZenAccessController" /> + android:fragment="com.android.settings.notification.NotificationAccessSettings" + settings:controller="com.android.settings.applications.specialaccess.NotificationAccessController" /> + settings:keywords="@string/picture_in_picture_keywords" + settings:controller="com.android.settings.applications.specialaccess.PictureInPictureController" /> + android:fragment="com.android.settings.applications.PremiumSmsAccess" + settings:controller="com.android.settings.applications.specialaccess.PremiumSmsController" /> + android:fragment="com.android.settings.datausage.UnrestrictedDataAccess" + settings:controller="com.android.settings.applications.specialaccess.DataSaverController" /> + settings:keywords="@string/keywords_vr_listener" + settings:controller="com.android.settings.applications.specialaccess.EnabledVrListenersController"> diff --git a/src/com/android/settings/applications/SpecialAccessSettings.java b/src/com/android/settings/applications/SpecialAccessSettings.java deleted file mode 100644 index 7679b1faf9b..00000000000 --- a/src/com/android/settings/applications/SpecialAccessSettings.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.settings.applications; - -import android.app.ActivityManager; -import android.content.Context; -import android.os.Bundle; -import androidx.annotation.NonNull; -import android.provider.SearchIndexableResource; -import androidx.preference.Preference; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.search.Indexable; -import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.search.SearchIndexable; - -import java.util.ArrayList; -import java.util.List; - -@SearchIndexable -public class SpecialAccessSettings extends DashboardFragment { - - private static final String TAG = "SpecialAccessSettings"; - private static final String[] DISABLED_FEATURES_LOW_RAM = - new String[]{"notification_access", "zen_access", "enabled_vr_listeners", - "picture_in_picture"}; - - @Override - protected String getLogTag() { - return TAG; - } - - @Override - protected int getPreferenceScreenResId() { - return R.xml.special_access; - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - if (ActivityManager.isLowRamDeviceStatic()) { - for (String disabledFeature : DISABLED_FEATURES_LOW_RAM) { - Preference pref = findPreference(disabledFeature); - if (pref != null) { - removePreference(disabledFeature); - } - } - } - } - - @Override - protected List createPreferenceControllers(Context context) { - return buildPreferenceControllers(context); - } - - private static List buildPreferenceControllers( - @NonNull Context context) { - final List controllers = new ArrayList<>(); - controllers.add(new HighPowerAppsController(context)); - controllers.add(new DeviceAdministratorsController(context)); - controllers.add(new PremiumSmsController(context)); - controllers.add(new DataSaverController(context)); - controllers.add(new EnabledVrListenersController(context)); - return controllers; - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.SPECIAL_ACCESS; - } - - public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - @Override - public List getXmlResourcesToIndex(Context context, - boolean enabled) { - final ArrayList result = new ArrayList<>(); - - final SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = R.xml.special_access; - result.add(sir); - return result; - } - - @Override - public List createPreferenceControllers( - Context context) { - return buildPreferenceControllers(context); - } - }; -} diff --git a/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceController.java b/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceController.java deleted file mode 100644 index 79c22248a69..00000000000 --- a/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceController.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2017 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.app.Activity; -import android.app.ActivityManager; -import android.app.admin.DevicePolicyManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; -import android.os.Bundle; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; -import android.os.UserManager; -import androidx.annotation.VisibleForTesting; -import androidx.preference.PreferenceScreen; -import android.util.Log; -import android.webkit.IWebViewUpdateService; - -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.applications.ApplicationFeatureProvider; -import com.android.settings.core.BasePreferenceController; -import com.android.settings.overlay.FeatureFactory; -import com.android.settings.widget.ActionButtonPreference; -import com.android.settingslib.RestrictedLockUtils; -import com.android.settingslib.applications.AppUtils; -import com.android.settingslib.applications.ApplicationsState.AppEntry; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -public class AppActionButtonPreferenceController extends BasePreferenceController - implements AppInfoDashboardFragment.Callback { - - private static final String TAG = "AppActionButtonControl"; - private static final String KEY_ACTION_BUTTONS = "action_buttons"; - - @VisibleForTesting - ActionButtonPreference mActionButtons; - private final AppInfoDashboardFragment mParent; - private final String mPackageName; - private final HashSet mHomePackages = new HashSet<>(); - private final ApplicationFeatureProvider mApplicationFeatureProvider; - - private int mUserId; - private DevicePolicyManager mDpm; - private UserManager mUserManager; - private PackageManager mPm; - - private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final boolean enabled = getResultCode() != Activity.RESULT_CANCELED; - Log.d(TAG, "Got broadcast response: Restart status for " - + mParent.getAppEntry().info.packageName + " " + enabled); - updateForceStopButton(enabled); - } - }; - - public AppActionButtonPreferenceController(Context context, AppInfoDashboardFragment parent, - String packageName) { - super(context, KEY_ACTION_BUTTONS); - mParent = parent; - mPackageName = packageName; - mUserId = UserHandle.myUserId(); - mApplicationFeatureProvider = FeatureFactory.getFactory(context) - .getApplicationFeatureProvider(context); - } - - @Override - public int getAvailabilityStatus() { - return AppUtils.isInstant(mParent.getPackageInfo().applicationInfo) - ? DISABLED_FOR_USER : AVAILABLE; - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mActionButtons = ((ActionButtonPreference) screen.findPreference(KEY_ACTION_BUTTONS)) - .setButton2Text(R.string.force_stop) - .setButton2Positive(false) - .setButton2Enabled(false); - } - - @Override - public void refreshUi() { - if (mPm == null) { - mPm = mContext.getPackageManager(); - } - if (mDpm == null) { - mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); - } - if (mUserManager == null) { - mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - } - final AppEntry appEntry = mParent.getAppEntry(); - final PackageInfo packageInfo = mParent.getPackageInfo(); - - // Get list of "home" apps and trace through any meta-data references - final List homeActivities = new ArrayList(); - mPm.getHomeActivities(homeActivities); - mHomePackages.clear(); - for (int i = 0; i < homeActivities.size(); i++) { - final ResolveInfo ri = homeActivities.get(i); - final String activityPkg = ri.activityInfo.packageName; - mHomePackages.add(activityPkg); - - // Also make sure to include anything proxying for the home app - final Bundle metadata = ri.activityInfo.metaData; - if (metadata != null) { - final String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE); - if (signaturesMatch(metaPkg, activityPkg)) { - mHomePackages.add(metaPkg); - } - } - } - - checkForceStop(appEntry, packageInfo); - initUninstallButtons(appEntry, packageInfo); - } - - @VisibleForTesting - void initUninstallButtons(AppEntry appEntry, PackageInfo packageInfo) { - final boolean isBundled = (appEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; - boolean enabled; - if (isBundled) { - enabled = handleDisableable(appEntry, packageInfo); - } else { - enabled = initUninstallButtonForUserApp(); - } - // If this is a device admin, it can't be uninstalled or disabled. - // We do this here so the text of the button is still set correctly. - if (isBundled && mDpm.packageHasActiveAdmins(packageInfo.packageName)) { - enabled = false; - } - - // We don't allow uninstalling DO/PO on *any* users, because if it's a system app, - // "uninstall" is actually "downgrade to the system version + disable", and "downgrade" - // will clear data on all users. - if (Utils.isProfileOrDeviceOwner(mUserManager, mDpm, packageInfo.packageName)) { - enabled = false; - } - - // Don't allow uninstalling the device provisioning package. - if (Utils.isDeviceProvisioningPackage(mContext.getResources(), appEntry.info.packageName)) { - enabled = false; - } - - // If the uninstall intent is already queued, disable the uninstall button - if (mDpm.isUninstallInQueue(mPackageName)) { - enabled = false; - } - - // Home apps need special handling. Bundled ones we don't risk downgrading - // because that can interfere with home-key resolution. Furthermore, we - // can't allow uninstallation of the only home app, and we don't want to - // allow uninstallation of an explicitly preferred one -- the user can go - // to Home settings and pick a different one, after which we'll permit - // uninstallation of the now-not-default one. - if (enabled && mHomePackages.contains(packageInfo.packageName)) { - if (isBundled) { - enabled = false; - } else { - ArrayList homeActivities = new ArrayList(); - ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities); - if (currentDefaultHome == null) { - // No preferred default, so permit uninstall only when - // there is more than one candidate - enabled = (mHomePackages.size() > 1); - } else { - // There is an explicit default home app -- forbid uninstall of - // that one, but permit it for installed-but-inactive ones. - enabled = !packageInfo.packageName.equals(currentDefaultHome.getPackageName()); - } - } - } - - if (RestrictedLockUtils.hasBaseUserRestriction( - mContext, UserManager.DISALLOW_APPS_CONTROL, mUserId)) { - enabled = false; - } - - try { - final IWebViewUpdateService webviewUpdateService = - IWebViewUpdateService.Stub.asInterface( - ServiceManager.getService("webviewupdate")); - if (webviewUpdateService.isFallbackPackage(appEntry.info.packageName)) { - enabled = false; - } - } catch (RemoteException e) { - throw new RuntimeException(e); - } - - mActionButtons.setButton1Enabled(enabled); - if (enabled) { - // Register listener - mActionButtons.setButton1OnClickListener(v -> mParent.handleUninstallButtonClick()); - } - } - - @VisibleForTesting - boolean initUninstallButtonForUserApp() { - boolean enabled = true; - final PackageInfo packageInfo = mParent.getPackageInfo(); - if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0 - && mUserManager.getUsers().size() >= 2) { - // When we have multiple users, there is a separate menu - // to uninstall for all users. - enabled = false; - } else if (AppUtils.isInstant(packageInfo.applicationInfo)) { - enabled = false; - mActionButtons.setButton1Visible(false); - } - mActionButtons.setButton1Text(R.string.uninstall_text).setButton1Positive(false); - return enabled; - } - - @VisibleForTesting - boolean handleDisableable(AppEntry appEntry, PackageInfo packageInfo) { - boolean disableable = false; - // Try to prevent the user from bricking their phone - // by not allowing disabling of apps signed with the - // system cert and any launcher app in the system. - if (mHomePackages.contains(appEntry.info.packageName) - || Utils.isSystemPackage(mContext.getResources(), mPm, packageInfo)) { - // Disable button for core system applications. - mActionButtons - .setButton1Text(R.string.disable_text) - .setButton1Positive(false); - } else if (appEntry.info.enabled && appEntry.info.enabledSetting - != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { - mActionButtons - .setButton1Text(R.string.disable_text) - .setButton1Positive(false); - disableable = !mApplicationFeatureProvider.getKeepEnabledPackages() - .contains(appEntry.info.packageName); - } else { - mActionButtons - .setButton1Text(R.string.enable_text) - .setButton1Positive(true); - disableable = true; - } - - return disableable; - } - - private void updateForceStopButton(boolean enabled) { - final boolean disallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction( - mContext, UserManager.DISALLOW_APPS_CONTROL, mUserId); - mActionButtons - .setButton2Enabled(disallowedBySystem ? false : enabled) - .setButton2OnClickListener( - disallowedBySystem ? null : v -> mParent.handleForceStopButtonClick()); - } - - void checkForceStop(AppEntry appEntry, PackageInfo packageInfo) { - if (mDpm.packageHasActiveAdmins(packageInfo.packageName)) { - // User can't force stop device admin. - Log.w(TAG, "User can't force stop device admin"); - updateForceStopButton(false); - } else if (mPm.isPackageStateProtected(packageInfo.packageName, - UserHandle.getUserId(appEntry.info.uid))) { - Log.w(TAG, "User can't force stop protected packages"); - updateForceStopButton(false); - } else if (AppUtils.isInstant(packageInfo.applicationInfo)) { - updateForceStopButton(false); - mActionButtons.setButton2Visible(false); - } else if ((appEntry.info.flags & ApplicationInfo.FLAG_STOPPED) == 0) { - // If the app isn't explicitly stopped, then always show the - // force stop button. - Log.w(TAG, "App is not explicitly stopped"); - updateForceStopButton(true); - } else { - final Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, - Uri.fromParts("package", appEntry.info.packageName, null)); - intent.putExtra(Intent.EXTRA_PACKAGES, new String[] {appEntry.info.packageName}); - intent.putExtra(Intent.EXTRA_UID, appEntry.info.uid); - intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(appEntry.info.uid)); - Log.d(TAG, "Sending broadcast to query restart status for " - + appEntry.info.packageName); - mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, - mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null); - } - } - - private boolean signaturesMatch(String pkg1, String pkg2) { - if (pkg1 != null && pkg2 != null) { - try { - return mPm.checkSignatures(pkg1, pkg2) >= PackageManager.SIGNATURE_MATCH; - } catch (Exception e) { - // e.g. named alternate package not found during lookup; - // this is an expected case sometimes - } - } - return false; - } - -} diff --git a/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java similarity index 97% rename from src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java rename to src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java index a2ba9a96181..dfbe064b832 100644 --- a/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.fuelgauge; +package com.android.settings.applications.appinfo; import android.app.Activity; import android.app.ActivityManager; @@ -49,13 +49,13 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.applications.ApplicationFeatureProvider; +import com.android.settings.core.BasePreferenceController; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.ActionButtonPreference; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; @@ -74,8 +74,7 @@ import java.util.List; * An easy way to handle them is to delegate them to {@link #handleDialogClick(int)} and * {@link #handleActivityResult(int, int, Intent)} in this controller. */ -//TODO(80312809): Merge this class into {@link AppActionButtonPreferenceController} -public class AppButtonsPreferenceController extends AbstractPreferenceController implements +public class AppButtonsPreferenceController extends BasePreferenceController implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnDestroy, ApplicationsState.Callbacks { public static final String APP_CHG = "chg"; @@ -120,9 +119,8 @@ public class AppButtonsPreferenceController extends AbstractPreferenceController public AppButtonsPreferenceController(SettingsActivity activity, Fragment fragment, Lifecycle lifecycle, String packageName, ApplicationsState state, - DevicePolicyManager dpm, UserManager userManager, - PackageManager packageManager, int requestUninstall, int requestRemoveDeviceAdmin) { - super(activity); + int requestUninstall, int requestRemoveDeviceAdmin) { + super(activity, KEY_ACTION_BUTTONS); if (!(fragment instanceof ButtonActionDialogFragment.AppButtonsDialogListener)) { throw new IllegalArgumentException( @@ -133,9 +131,9 @@ public class AppButtonsPreferenceController extends AbstractPreferenceController mMetricsFeatureProvider = factory.getMetricsFeatureProvider(); mApplicationFeatureProvider = factory.getApplicationFeatureProvider(activity); mState = state; - mDpm = dpm; - mUserManager = userManager; - mPm = packageManager; + mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); + mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE); + mPm = activity.getPackageManager(); mPackageName = packageName; mActivity = activity; mFragment = fragment; @@ -153,9 +151,10 @@ public class AppButtonsPreferenceController extends AbstractPreferenceController } @Override - public boolean isAvailable() { + public int getAvailabilityStatus() { // TODO(b/37313605): Re-enable once this controller supports instant apps - return mAppEntry != null && !AppUtils.isInstant(mAppEntry.info); + return mAppEntry != null && !AppUtils.isInstant(mAppEntry.info) + ? AVAILABLE : DISABLED_FOR_USER ; } @Override diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 1f8a3a07585..7107ff754aa 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -19,14 +19,12 @@ package com.android.settings.applications.appinfo; import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import android.app.Activity; -import android.app.ActivityManager; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; @@ -35,7 +33,6 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; @@ -47,7 +44,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.DeviceAdminAdd; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragment; @@ -62,7 +58,6 @@ import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -77,7 +72,8 @@ import java.util.List; * uninstall the application. */ public class AppInfoDashboardFragment extends DashboardFragment - implements ApplicationsState.Callbacks { + implements ApplicationsState.Callbacks, + ButtonActionDialogFragment.AppButtonsDialogListener { private static final String TAG = "AppInfoDashboard"; @@ -101,10 +97,7 @@ public class AppInfoDashboardFragment extends DashboardFragment // Dialog identifiers used in showDialog private static final int DLG_BASE = 0; - private static final int DLG_FORCE_STOP = DLG_BASE + 1; - private static final int DLG_DISABLE = DLG_BASE + 2; - private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3; - static final int DLG_CLEAR_INSTANT_APP = DLG_BASE + 4; + static final int DLG_CLEAR_INSTANT_APP = DLG_BASE + 1; public static final String ARG_PACKAGE_NAME = "package"; public static final String ARG_PACKAGE_UID = "uid"; @@ -132,12 +125,11 @@ public class AppInfoDashboardFragment extends DashboardFragment private boolean mInitialized; private boolean mShowUninstalled; private boolean mUpdatedSysApp = false; - private boolean mDisableAfterUninstall; private List mCallbacks = new ArrayList<>(); private InstantAppButtonsPreferenceController mInstantAppButtonPreferenceController; - private AppActionButtonPreferenceController mAppActionButtonPreferenceController; + private AppButtonsPreferenceController mAppButtonsPreferenceController; /** * Callback to invoke when app info has been changed. @@ -146,11 +138,6 @@ public class AppInfoDashboardFragment extends DashboardFragment void refreshUi(); } - private boolean isDisabledUntilUsed() { - return mAppEntry.info.enabledSetting - == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; - } - @Override public void onAttach(Context context) { super.onAttach(context); @@ -262,9 +249,6 @@ public class AppInfoDashboardFragment extends DashboardFragment // when app state changes. controllers.add( new AppHeaderViewPreferenceController(context, this, packageName, lifecycle)); - mAppActionButtonPreferenceController = - new AppActionButtonPreferenceController(context, this, packageName); - controllers.add(mAppActionButtonPreferenceController); for (AbstractPreferenceController controller : controllers) { mCallbacks.add((Callback) controller); @@ -275,6 +259,10 @@ public class AppInfoDashboardFragment extends DashboardFragment mInstantAppButtonPreferenceController = new InstantAppButtonsPreferenceController(context, this, packageName, lifecycle); controllers.add(mInstantAppButtonPreferenceController); + mAppButtonsPreferenceController = new AppButtonsPreferenceController( + (SettingsActivity) getActivity(), this, lifecycle, packageName, mState, + REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN); + controllers.add(mAppButtonsPreferenceController); controllers.add(new AppBatteryPreferenceController(context, this, packageName, lifecycle)); controllers.add(new AppMemoryPreferenceController(context, this, lifecycle)); controllers.add(new DefaultHomeShortcutPreferenceController(context, packageName)); @@ -374,30 +362,19 @@ public class AppInfoDashboardFragment extends DashboardFragment @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - switch (requestCode) { - case REQUEST_UNINSTALL: - // Refresh option menu - getActivity().invalidateOptionsMenu(); + if (requestCode == REQUEST_UNINSTALL) { + // Refresh option menu + getActivity().invalidateOptionsMenu(); + } + if (mAppButtonsPreferenceController != null) { + mAppButtonsPreferenceController.handleActivityResult(requestCode, resultCode, data); + } + } - if (mDisableAfterUninstall) { - mDisableAfterUninstall = false; - new DisableChanger(this, mAppEntry.info, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) - .execute((Object) null); - } - if (!refreshUi()) { - onPackageRemoved(); - } else { - startListeningToPackageRemove(); - } - break; - case REQUEST_REMOVE_DEVICE_ADMIN: - if (!refreshUi()) { - setIntentAndFinish(true, true); - } else { - startListeningToPackageRemove(); - } - break; + @Override + public void handleDialogClick(int id) { + if (mAppButtonsPreferenceController != null) { + mAppButtonsPreferenceController.handleDialogClick(id); } } @@ -442,6 +419,7 @@ public class AppInfoDashboardFragment extends DashboardFragment for (Callback callback : mCallbacks) { callback.refreshUi(); } + mAppButtonsPreferenceController.refreshUi(); if (!mInitialized) { // First time init: are we displaying an uninstalled app? @@ -471,53 +449,6 @@ public class AppInfoDashboardFragment extends DashboardFragment @VisibleForTesting AlertDialog createDialog(int id, int errorCode) { - switch (id) { - case DLG_DISABLE: - return new AlertDialog.Builder(getActivity()) - .setMessage(getActivity().getText(R.string.app_disable_dlg_text)) - .setPositiveButton(R.string.app_disable_dlg_positive, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - // Disable the app - mMetricsFeatureProvider.action(getContext(), - MetricsEvent.ACTION_SETTINGS_DISABLE_APP); - new DisableChanger(AppInfoDashboardFragment.this, - mAppEntry.info, - PackageManager - .COMPONENT_ENABLED_STATE_DISABLED_USER) - .execute((Object) null); - } - }) - .setNegativeButton(R.string.dlg_cancel, null) - .create(); - case DLG_SPECIAL_DISABLE: - return new AlertDialog.Builder(getActivity()) - .setMessage(getActivity().getText(R.string.app_disable_dlg_text)) - .setPositiveButton(R.string.app_disable_dlg_positive, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - // Disable the app and ask for uninstall - mMetricsFeatureProvider.action(getContext(), - MetricsEvent.ACTION_SETTINGS_DISABLE_APP); - uninstallPkg(mAppEntry.info.packageName, - false, true); - } - }) - .setNegativeButton(R.string.dlg_cancel, null) - .create(); - case DLG_FORCE_STOP: - return new AlertDialog.Builder(getActivity()) - .setTitle(getActivity().getText(R.string.force_stop_dlg_title)) - .setMessage(getActivity().getText(R.string.force_stop_dlg_text)) - .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - // Force stop - forceStopPackage(mAppEntry.info.packageName); - } - }) - .setNegativeButton(R.string.dlg_cancel, null) - .create(); - } return mInstantAppButtonPreferenceController.createDialog(id); } @@ -530,22 +461,6 @@ public class AppInfoDashboardFragment extends DashboardFragment mMetricsFeatureProvider.action( getContext(), MetricsEvent.ACTION_SETTINGS_UNINSTALL_APP); startActivityForResult(uninstallIntent, REQUEST_UNINSTALL); - mDisableAfterUninstall = andDisable; - } - - private void forceStopPackage(String pkgName) { - mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_APP_FORCE_STOP, pkgName); - final ActivityManager am = (ActivityManager) getActivity().getSystemService( - Context.ACTIVITY_SERVICE); - Log.d(TAG, "Stopping package " + pkgName); - am.forceStopPackage(pkgName); - final int userId = UserHandle.getUserId(mAppEntry.info.uid); - mState.invalidatePackage(pkgName, userId); - final AppEntry newEnt = mState.getEntry(pkgName, userId); - if (newEnt != null) { - mAppEntry = newEnt; - } - mAppActionButtonPreferenceController.checkForceStop(mAppEntry, mPackageInfo); } public static void startAppInfoFragment(Class fragment, int title, Bundle args, @@ -565,74 +480,6 @@ public class AppInfoDashboardFragment extends DashboardFragment .launch(); } - void handleUninstallButtonClick() { - if (mAppEntry == null) { - setIntentAndFinish(true, true); - return; - } - final String packageName = mAppEntry.info.packageName; - if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) { - stopListeningToPackageRemove(); - final Activity activity = getActivity(); - final Intent uninstallDAIntent = new Intent(activity, DeviceAdminAdd.class); - uninstallDAIntent.putExtra(DeviceAdminAdd.EXTRA_DEVICE_ADMIN_PACKAGE_NAME, - mPackageName); - mMetricsFeatureProvider.action( - activity, MetricsEvent.ACTION_SETTINGS_UNINSTALL_DEVICE_ADMIN); - activity.startActivityForResult(uninstallDAIntent, REQUEST_REMOVE_DEVICE_ADMIN); - return; - } - final EnforcedAdmin admin = RestrictedLockUtils.checkIfUninstallBlocked(getActivity(), - packageName, mUserId); - final boolean uninstallBlockedBySystem = mAppsControlDisallowedBySystem || - RestrictedLockUtils.hasBaseUserRestriction(getActivity(), packageName, mUserId); - if (admin != null && !uninstallBlockedBySystem) { - RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), admin); - } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - if (mAppEntry.info.enabled && !isDisabledUntilUsed()) { - // If the system app has an update and this is the only user on the device, - // then offer to downgrade the app, otherwise only offer to disable the - // app for this user. - if (mUpdatedSysApp && isSingleUser()) { - showDialogInner(DLG_SPECIAL_DISABLE, 0); - } else { - showDialogInner(DLG_DISABLE, 0); - } - } else { - mMetricsFeatureProvider.action( - getActivity(), - MetricsEvent.ACTION_SETTINGS_ENABLE_APP); - new DisableChanger(this, mAppEntry.info, - PackageManager.COMPONENT_ENABLED_STATE_ENABLED) - .execute((Object) null); - } - } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { - uninstallPkg(packageName, true, false); - } else { - uninstallPkg(packageName, false, false); - } - } - - void handleForceStopButtonClick() { - if (mAppEntry == null) { - setIntentAndFinish(true, true); - return; - } - if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) { - RestrictedLockUtils.sendShowAdminSupportDetailsIntent( - getActivity(), mAppsControlDisallowedAdmin); - } else { - showDialogInner(DLG_FORCE_STOP, 0); - //forceStopPackage(mAppInfo.packageName); - } - } - - /** Returns whether there is only one user on this device, not including the system-only user */ - private boolean isSingleUser() { - final int userCount = mUserManager.getUserCount(); - return userCount == 1 || (mUserManager.isSplitSystemUser() && userCount == 2); - } - private void onPackageRemoved() { getActivity().finishActivity(SUB_INFO_FRAGMENT); getActivity().finishAndRemoveTask(); @@ -659,26 +506,6 @@ public class AppInfoDashboardFragment extends DashboardFragment return count; } - private static class DisableChanger extends AsyncTask { - final PackageManager mPm; - final WeakReference mActivity; - final ApplicationInfo mInfo; - final int mState; - - DisableChanger(AppInfoDashboardFragment activity, ApplicationInfo info, int state) { - mPm = activity.mPm; - mActivity = new WeakReference(activity); - mInfo = info; - mState = state; - } - - @Override - protected Object doInBackground(Object... params) { - mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0); - return null; - } - } - private String getPackageName() { if (mPackageName != null) { return mPackageName; diff --git a/src/com/android/settings/fuelgauge/ButtonActionDialogFragment.java b/src/com/android/settings/applications/appinfo/ButtonActionDialogFragment.java similarity index 96% rename from src/com/android/settings/fuelgauge/ButtonActionDialogFragment.java rename to src/com/android/settings/applications/appinfo/ButtonActionDialogFragment.java index f4784a97824..a3f1bab78c5 100644 --- a/src/com/android/settings/fuelgauge/ButtonActionDialogFragment.java +++ b/src/com/android/settings/applications/appinfo/ButtonActionDialogFragment.java @@ -1,6 +1,5 @@ -package com.android.settings.fuelgauge; +package com.android.settings.applications.appinfo; -import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; @@ -26,7 +25,7 @@ public class ButtonActionDialogFragment extends InstrumentedDialogFragment imple /** * Interface to handle the dialog click */ - interface AppButtonsDialogListener { + public interface AppButtonsDialogListener { void handleDialogClick(int type); } diff --git a/src/com/android/settings/applications/defaultapps/DefaultBrowserPicker.java b/src/com/android/settings/applications/defaultapps/DefaultBrowserPicker.java index c243970bad0..1cb7985c4c1 100644 --- a/src/com/android/settings/applications/defaultapps/DefaultBrowserPicker.java +++ b/src/com/android/settings/applications/defaultapps/DefaultBrowserPicker.java @@ -17,11 +17,9 @@ package com.android.settings.applications.defaultapps; import android.content.Context; -import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.util.ArraySet; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; @@ -29,7 +27,6 @@ import com.android.settingslib.applications.DefaultAppInfo; import java.util.ArrayList; import java.util.List; -import java.util.Set; /** * Fragment for choosing default browser. @@ -61,24 +58,13 @@ public class DefaultBrowserPicker extends DefaultAppPickerFragment { final List candidates = new ArrayList<>(); final Context context = getContext(); // Resolve that intent and check that the handleAllWebDataURI boolean is set - final List list = mPm.queryIntentActivitiesAsUser( - DefaultBrowserPreferenceController.BROWSE_PROBE, PackageManager.MATCH_ALL, mUserId); + final List list = + DefaultBrowserPreferenceController.getCandidates(mPm, mUserId); - final int count = list.size(); - final Set addedPackages = new ArraySet<>(); - for (int i = 0; i < count; i++) { - ResolveInfo info = list.get(i); - if (info.activityInfo == null || !info.handleAllWebDataURI) { - continue; - } - final String packageName = info.activityInfo.packageName; - if (addedPackages.contains(packageName)) { - continue; - } + for (ResolveInfo info : list) { try { candidates.add(new DefaultAppInfo(context, mPm, - mPm.getApplicationInfoAsUser(packageName, 0, mUserId))); - addedPackages.add(packageName); + mPm.getApplicationInfoAsUser(info.activityInfo.packageName, 0, mUserId))); } catch (PackageManager.NameNotFoundException e) { // Skip unknown packages. } diff --git a/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceController.java index 5395be9919c..d4e86ff16fe 100644 --- a/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceController.java +++ b/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceController.java @@ -26,12 +26,15 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import androidx.preference.Preference; import android.text.TextUtils; +import android.util.ArraySet; import android.util.IconDrawableFactory; import android.util.Log; import com.android.settingslib.applications.DefaultAppInfo; +import java.util.ArrayList; import java.util.List; +import java.util.Set; public class DefaultBrowserPreferenceController extends DefaultAppPreferenceController { @@ -48,7 +51,7 @@ public class DefaultBrowserPreferenceController extends DefaultAppPreferenceCont @Override public boolean isAvailable() { - final List candidates = getCandidates(); + final List candidates = getCandidates(mPackageManager, mUserId); return candidates != null && !candidates.isEmpty(); } @@ -103,14 +106,31 @@ public class DefaultBrowserPreferenceController extends DefaultAppPreferenceCont return getOnlyAppIcon(); } - private List getCandidates() { - return mPackageManager.queryIntentActivitiesAsUser(BROWSE_PROBE, PackageManager.MATCH_ALL, - mUserId); + static List getCandidates(PackageManager packageManager, int userId) { + final List candidates = new ArrayList<>(); + // Resolve that intent and check that the handleAllWebDataURI boolean is set + final List list = packageManager.queryIntentActivitiesAsUser( + BROWSE_PROBE, PackageManager.MATCH_ALL, userId); + if (list != null) { + final Set addedPackages = new ArraySet<>(); + for (ResolveInfo info : list) { + if (info.activityInfo == null || !info.handleAllWebDataURI) { + continue; + } + final String packageName = info.activityInfo.packageName; + if (addedPackages.contains(packageName)) { + continue; + } + candidates.add(info); + addedPackages.add(packageName); + } + } + return candidates; } private String getOnlyAppLabel() { // Resolve that intent and check that the handleAllWebDataURI boolean is set - final List list = getCandidates(); + final List list = getCandidates(mPackageManager, mUserId); if (list != null && list.size() == 1) { final ResolveInfo info = list.get(0); final String label = info.loadLabel(mPackageManager).toString(); @@ -123,7 +143,7 @@ public class DefaultBrowserPreferenceController extends DefaultAppPreferenceCont } private Drawable getOnlyAppIcon() { - final List list = getCandidates(); + final List list = getCandidates(mPackageManager, mUserId); if (list != null && list.size() == 1) { final ResolveInfo info = list.get(0); final ComponentInfo cn = info.getComponentInfo(); diff --git a/src/com/android/settings/applications/DataSaverController.java b/src/com/android/settings/applications/specialaccess/DataSaverController.java similarity index 80% rename from src/com/android/settings/applications/DataSaverController.java rename to src/com/android/settings/applications/specialaccess/DataSaverController.java index afe7cd64cd3..56687d7aa4f 100644 --- a/src/com/android/settings/applications/DataSaverController.java +++ b/src/com/android/settings/applications/specialaccess/DataSaverController.java @@ -15,20 +15,17 @@ */ -package com.android.settings.applications; +package com.android.settings.applications.specialaccess; import android.content.Context; -import androidx.annotation.VisibleForTesting; -import com.android.settings.core.BasePreferenceController; import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; public class DataSaverController extends BasePreferenceController { - @VisibleForTesting static final String KEY_DATA_SAVER = "data_saver"; - - public DataSaverController(Context context) { - super(context, KEY_DATA_SAVER); + public DataSaverController(Context context, String key) { + super(context, key); } @AvailabilityStatus diff --git a/src/com/android/settings/applications/DeviceAdministratorsController.java b/src/com/android/settings/applications/specialaccess/DeviceAdministratorsController.java similarity index 79% rename from src/com/android/settings/applications/DeviceAdministratorsController.java rename to src/com/android/settings/applications/specialaccess/DeviceAdministratorsController.java index ec1d556a611..bdb99ef113a 100644 --- a/src/com/android/settings/applications/DeviceAdministratorsController.java +++ b/src/com/android/settings/applications/specialaccess/DeviceAdministratorsController.java @@ -14,20 +14,17 @@ * limitations under the License. */ -package com.android.settings.applications; +package com.android.settings.applications.specialaccess; import android.content.Context; -import androidx.annotation.VisibleForTesting; -import com.android.settings.core.BasePreferenceController; import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; public class DeviceAdministratorsController extends BasePreferenceController { - @VisibleForTesting static final String KEY_DEVICE_ADMIN = "device_administrators"; - - public DeviceAdministratorsController(Context context) { - super(context, KEY_DEVICE_ADMIN); + public DeviceAdministratorsController(Context context, String key) { + super(context, key); } @AvailabilityStatus diff --git a/src/com/android/settings/applications/EnabledVrListenersController.java b/src/com/android/settings/applications/specialaccess/EnabledVrListenersController.java similarity index 78% rename from src/com/android/settings/applications/EnabledVrListenersController.java rename to src/com/android/settings/applications/specialaccess/EnabledVrListenersController.java index 7b33529d7eb..5967b0d4507 100644 --- a/src/com/android/settings/applications/EnabledVrListenersController.java +++ b/src/com/android/settings/applications/specialaccess/EnabledVrListenersController.java @@ -14,25 +14,24 @@ * limitations under the License. */ -package com.android.settings.applications; +package com.android.settings.applications.specialaccess; +import android.app.ActivityManager; import android.content.Context; -import androidx.annotation.VisibleForTesting; -import com.android.settings.core.BasePreferenceController; import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; public class EnabledVrListenersController extends BasePreferenceController { - @VisibleForTesting static final String KEY_ENABLED_VR_LISTENERS = "enabled_vr_listeners"; - - public EnabledVrListenersController(Context context) { - super(context, KEY_ENABLED_VR_LISTENERS); + public EnabledVrListenersController(Context context, String key) { + super(context, key); } @AvailabilityStatus public int getAvailabilityStatus() { return mContext.getResources().getBoolean(R.bool.config_show_enabled_vr_listeners) + && !ActivityManager.isLowRamDeviceStatic() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/applications/HighPowerAppsController.java b/src/com/android/settings/applications/specialaccess/HighPowerAppsController.java similarity index 79% rename from src/com/android/settings/applications/HighPowerAppsController.java rename to src/com/android/settings/applications/specialaccess/HighPowerAppsController.java index 39b84516315..b893b887607 100644 --- a/src/com/android/settings/applications/HighPowerAppsController.java +++ b/src/com/android/settings/applications/specialaccess/HighPowerAppsController.java @@ -14,20 +14,17 @@ * limitations under the License. */ -package com.android.settings.applications; +package com.android.settings.applications.specialaccess; import android.content.Context; -import androidx.annotation.VisibleForTesting; -import com.android.settings.core.BasePreferenceController; import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; public class HighPowerAppsController extends BasePreferenceController { - @VisibleForTesting static final String KEY_HIGH_POWER_APPS = "high_power_apps"; - - public HighPowerAppsController(Context context) { - super(context, KEY_HIGH_POWER_APPS); + public HighPowerAppsController(Context context, String key) { + super(context, key); } @AvailabilityStatus diff --git a/src/com/android/settings/applications/specialaccess/NotificationAccessController.java b/src/com/android/settings/applications/specialaccess/NotificationAccessController.java new file mode 100644 index 00000000000..773cd7df576 --- /dev/null +++ b/src/com/android/settings/applications/specialaccess/NotificationAccessController.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 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.specialaccess; + +import android.app.ActivityManager; +import android.content.Context; + +import com.android.settings.core.BasePreferenceController; + +public class NotificationAccessController extends BasePreferenceController { + + public NotificationAccessController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return !ActivityManager.isLowRamDeviceStatic() + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; + } +} diff --git a/src/com/android/settings/applications/specialaccess/PictureInPictureController.java b/src/com/android/settings/applications/specialaccess/PictureInPictureController.java new file mode 100644 index 00000000000..6666605c1cc --- /dev/null +++ b/src/com/android/settings/applications/specialaccess/PictureInPictureController.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 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.specialaccess; + +import android.app.ActivityManager; +import android.content.Context; + +import com.android.settings.core.BasePreferenceController; + +public class PictureInPictureController extends BasePreferenceController { + + public PictureInPictureController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return !ActivityManager.isLowRamDeviceStatic() + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; + } +} diff --git a/src/com/android/settings/applications/PremiumSmsController.java b/src/com/android/settings/applications/specialaccess/PremiumSmsController.java similarity index 80% rename from src/com/android/settings/applications/PremiumSmsController.java rename to src/com/android/settings/applications/specialaccess/PremiumSmsController.java index eeb5d86fd90..0e8c198f3b2 100644 --- a/src/com/android/settings/applications/PremiumSmsController.java +++ b/src/com/android/settings/applications/specialaccess/PremiumSmsController.java @@ -14,20 +14,17 @@ * limitations under the License. */ -package com.android.settings.applications; +package com.android.settings.applications.specialaccess; import android.content.Context; -import androidx.annotation.VisibleForTesting; -import com.android.settings.core.BasePreferenceController; import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; public class PremiumSmsController extends BasePreferenceController { - @VisibleForTesting static final String KEY_PREMIUM_SMS = "premium_sms"; - - public PremiumSmsController(Context context) { - super(context, KEY_PREMIUM_SMS); + public PremiumSmsController(Context context, String key) { + super(context, key); } @AvailabilityStatus diff --git a/src/com/android/settings/applications/specialaccess/SpecialAccessSettings.java b/src/com/android/settings/applications/specialaccess/SpecialAccessSettings.java new file mode 100644 index 00000000000..80cadcc4396 --- /dev/null +++ b/src/com/android/settings/applications/specialaccess/SpecialAccessSettings.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.applications.specialaccess; + +import android.content.Context; +import android.provider.SearchIndexableResource; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settingslib.search.SearchIndexable; + +import java.util.ArrayList; +import java.util.List; + +@SearchIndexable +public class SpecialAccessSettings extends DashboardFragment { + + private static final String TAG = "SpecialAccessSettings"; + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.special_access; + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.SPECIAL_ACCESS; + } + + public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final ArrayList result = new ArrayList<>(); + + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.special_access; + result.add(sir); + return result; + } + }; +} diff --git a/src/com/android/settings/applications/specialaccess/ZenAccessController.java b/src/com/android/settings/applications/specialaccess/ZenAccessController.java new file mode 100644 index 00000000000..41344a3ebad --- /dev/null +++ b/src/com/android/settings/applications/specialaccess/ZenAccessController.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 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.specialaccess; + +import android.app.ActivityManager; +import android.content.Context; + +import com.android.settings.core.BasePreferenceController; + +public class ZenAccessController extends BasePreferenceController { + + public ZenAccessController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return !ActivityManager.isLowRamDeviceStatic() + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; + } +} diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java index 9a287f1786b..ea520ea88bf 100644 --- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java @@ -97,6 +97,11 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater if (DBG) { Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile); } + // If device is Hearing Aid, it is compatible with HFP and A2DP. + // It would show in Available Devices group. + if (cachedDevice.isConnectedHearingAidDevice()) { + return true; + } // According to the current audio profile type, // this page will show the bluetooth device that have corresponding profile. // For example: diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java index 0ac3e6d850b..bb543bad496 100644 --- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java @@ -101,6 +101,11 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater { if (DBG) { Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile); } + // If device is Hearing Aid, it is compatible with HFP and A2DP. + // It would not show in Connected Devices group. + if (cachedDevice.isConnectedHearingAidDevice()) { + return false; + } // According to the current audio profile type, // this page will show the bluetooth device that doesn't have corresponding profile. // For example: diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java index aa0b6cd54fd..654ea722335 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java @@ -76,9 +76,11 @@ public class ConnectedDeviceGroupController extends BasePreferenceController mPreferenceGroup = (PreferenceGroup) screen.findPreference(KEY); mPreferenceGroup.setVisible(false); - mBluetoothDeviceUpdater.setPrefContext(screen.getContext()); + final Context context = screen.getContext(); + mBluetoothDeviceUpdater.setPrefContext(context); mBluetoothDeviceUpdater.forceUpdate(); - mConnectedUsbDeviceUpdater.initUsbPreference(screen.getContext()); + mConnectedUsbDeviceUpdater.initUsbPreference(context); + mConnectedDockUpdater.setPreferenceContext(context); mConnectedDockUpdater.forceUpdate(); } } diff --git a/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java b/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java index 4bc9cdd637f..6f9b7ac2c04 100644 --- a/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java +++ b/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java @@ -75,8 +75,11 @@ public class SavedDeviceGroupController extends BasePreferenceController if (isAvailable()) { mPreferenceGroup = (PreferenceGroup) screen.findPreference(KEY); mPreferenceGroup.setVisible(false); - mBluetoothDeviceUpdater.setPrefContext(screen.getContext()); + + final Context context = screen.getContext(); + mBluetoothDeviceUpdater.setPrefContext(context); mBluetoothDeviceUpdater.forceUpdate(); + mSavedDockUpdater.setPreferenceContext(context); mSavedDockUpdater.forceUpdate(); } } diff --git a/src/com/android/settings/connecteddevice/dock/DockUpdater.java b/src/com/android/settings/connecteddevice/dock/DockUpdater.java index 19ee7324179..99ac12475bc 100644 --- a/src/com/android/settings/connecteddevice/dock/DockUpdater.java +++ b/src/com/android/settings/connecteddevice/dock/DockUpdater.java @@ -15,6 +15,7 @@ */ package com.android.settings.connecteddevice.dock; +import android.annotation.NonNull; import android.content.Context; /** @@ -40,4 +41,10 @@ public interface DockUpdater { */ default void forceUpdate() { } + + /** + * Set the context to generate the {@link Preference}, so it could get the correct theme. + */ + default void setPreferenceContext(@NonNull Context preferenceContext) { + } } diff --git a/src/com/android/settings/datetime/timezone/BaseTimeZoneAdapter.java b/src/com/android/settings/datetime/timezone/BaseTimeZoneAdapter.java index 1a868b8f296..253bd2f1512 100644 --- a/src/com/android/settings/datetime/timezone/BaseTimeZoneAdapter.java +++ b/src/com/android/settings/datetime/timezone/BaseTimeZoneAdapter.java @@ -78,7 +78,7 @@ public class BaseTimeZoneAdapter LayoutInflater inflater = LayoutInflater.from(parent.getContext()); switch(viewType) { case TYPE_HEADER: { - final View view = inflater.inflate(R.layout.preference_category_material_settings, + final View view = inflater.inflate(R.layout.preference_category_material, parent, false); return new HeaderViewHolder(view); } diff --git a/src/com/android/settings/development/qstile/DevelopmentTiles.java b/src/com/android/settings/development/qstile/DevelopmentTiles.java index 5482b028d35..ec017c510be 100644 --- a/src/com/android/settings/development/qstile/DevelopmentTiles.java +++ b/src/com/android/settings/development/qstile/DevelopmentTiles.java @@ -16,7 +16,9 @@ package com.android.settings.development.qstile; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; @@ -25,7 +27,6 @@ import android.os.SystemProperties; import android.provider.Settings; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; -import androidx.annotation.VisibleForTesting; import android.util.Log; import android.view.IWindowManager; import android.view.ThreadedRenderer; @@ -34,9 +35,12 @@ import android.view.WindowManagerGlobal; import android.widget.Toast; import com.android.internal.app.LocalePicker; +import com.android.internal.statusbar.IStatusBarService; import com.android.settingslib.development.DevelopmentSettingsEnabler; import com.android.settingslib.development.SystemPropPoker; +import androidx.annotation.VisibleForTesting; + public abstract class DevelopmentTiles extends TileService { private static final String TAG = "DevelopmentTiles"; @@ -58,6 +62,20 @@ public abstract class DevelopmentTiles extends TileService { setIsEnabled(false); SystemPropPoker.getInstance().poke(); } + final ComponentName cn = new ComponentName(getPackageName(), getClass().getName()); + try { + getPackageManager().setComponentEnabledSetting( + cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + final IStatusBarService statusBarService = IStatusBarService.Stub.asInterface( + ServiceManager.checkService(Context.STATUS_BAR_SERVICE)); + if (statusBarService != null) { + statusBarService.remTile(cn); + } + } catch (RemoteException e) { + Log.e(TAG, "Failed to modify QS tile for component " + + cn.toString(), e); + } state = Tile.STATE_UNAVAILABLE; } else { state = isEnabled() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index 9604f74fe3e..0272b5c6dfa 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -402,10 +402,14 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle try { final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1); + // b/33117269: Note that launchIntent may launch activity in different task which set + // different launchMode (e.g. Files), using startActivityForesult to set task as + // source task, and set requestCode as 0 means don't care about returnCode currently. if (userId == -1) { - mFragment.startActivity(intent); + mFragment.startActivityForResult(intent, 0 /* requestCode not used */); } else { - mFragment.getActivity().startActivityAsUser(intent, new UserHandle(userId)); + mFragment.getActivity().startActivityForResultAsUser(intent, + 0 /* requestCode not used */, new UserHandle(userId)); } } catch (ActivityNotFoundException e) { Log.w(TAG, "No activity found for " + intent); diff --git a/src/com/android/settings/display/AppGridView.java b/src/com/android/settings/display/AppGridView.java index 00275375280..d48eb09e22f 100644 --- a/src/com/android/settings/display/AppGridView.java +++ b/src/com/android/settings/display/AppGridView.java @@ -22,7 +22,6 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.UserHandle; -import androidx.annotation.VisibleForTesting; import android.util.AttributeSet; import android.util.IconDrawableFactory; import android.view.View; @@ -37,28 +36,32 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import androidx.annotation.VisibleForTesting; + public class AppGridView extends GridView { public AppGridView(Context context) { - this(context, null); + super(context); + init(context); } public AppGridView(Context context, AttributeSet attrs) { - this(context, attrs, 0); + super(context, attrs); + init(context); } public AppGridView(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); + super(context, attrs, defStyleAttr); + init(context); } public AppGridView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleResId) { super(context, attrs, defStyleAttr, defStyleResId); - setNumColumns(AUTO_FIT); + init(context); - final int columnWidth = getResources().getDimensionPixelSize( - R.dimen.screen_zoom_preview_app_icon_width); - setColumnWidth(columnWidth); + } + private void init(Context context) { setAdapter(new AppsAdapter(context, R.layout.screen_zoom_preview_app_icon, android.R.id.text1, android.R.id.icon1)); } @@ -105,6 +108,7 @@ public class AppGridView extends GridView { } private void loadAllApps() { + final int needAppCount = 6; final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); @@ -117,6 +121,9 @@ public class AppGridView extends GridView { if (label != null) { results.add(new ActivityEntry(info, label.toString(), iconFactory)); } + if (results.size() >= needAppCount) { + break; + } } Collections.sort(results); diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java index c25463a1f86..af1de4856f0 100644 --- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java +++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java @@ -20,7 +20,6 @@ import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; import android.app.LoaderManager; -import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.Loader; @@ -28,7 +27,6 @@ import android.content.pm.PackageManager; import android.os.BatteryStats; import android.os.Bundle; import android.os.UserHandle; -import android.os.UserManager; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import android.text.TextUtils; @@ -43,6 +41,8 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.applications.LayoutPreference; +import com.android.settings.applications.appinfo.AppButtonsPreferenceController; +import com.android.settings.applications.appinfo.ButtonActionDialogFragment; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; @@ -112,9 +112,6 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements private AppButtonsPreferenceController mAppButtonsPreferenceController; private BackgroundActivityPreferenceController mBackgroundActivityPreferenceController; - private DevicePolicyManager mDpm; - private UserManager mUserManager; - private PackageManager mPackageManager; private List mAnomalies; private String mPackageName; @@ -203,9 +200,6 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements super.onAttach(activity); mState = ApplicationsState.getInstance(getActivity().getApplication()); - mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); - mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE); - mPackageManager = activity.getPackageManager(); mBatteryUtils = BatteryUtils.getInstance(getContext()); } @@ -332,8 +326,8 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements controllers.add(new BatteryOptimizationPreferenceController( (SettingsActivity) getActivity(), this, packageName)); mAppButtonsPreferenceController = new AppButtonsPreferenceController( - (SettingsActivity) getActivity(), this, getLifecycle(), packageName, mState, mDpm, - mUserManager, mPackageManager, REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN); + (SettingsActivity) getActivity(), this, getLifecycle(), packageName, mState, + REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN); controllers.add(mAppButtonsPreferenceController); return controllers; diff --git a/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java b/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java index b082eeb52f9..379b995aa4b 100644 --- a/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java +++ b/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java @@ -43,6 +43,7 @@ import com.android.settingslib.core.lifecycle.events.OnStop; public class AutoBatterySeekBarPreferenceController extends BasePreferenceController implements LifecycleObserver, OnStart, OnStop, SeekBarPreference.OnPreferenceChangeListener { private static final String TAG = "AutoBatterySeekBarPreferenceController"; + private static final int INTERVAL = 5; @VisibleForTesting static final String KEY_AUTO_BATTERY_SEEK_BAR = "battery_saver_seek_bar"; private SeekBarPreference mPreference; @@ -92,7 +93,7 @@ public class AutoBatterySeekBarPreferenceController extends BasePreferenceContro public boolean onPreferenceChange(Preference preference, Object newValue) { final int progress = (int) newValue; Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, progress); + Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, progress * INTERVAL); return true; } @@ -102,7 +103,7 @@ public class AutoBatterySeekBarPreferenceController extends BasePreferenceContro // Override the max value with LOW_POWER_MODE_TRIGGER_LEVEL_MAX, if set. final int maxLevel = Settings.Global.getInt(contentResolver, - Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX, 0); + Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX, 0) / INTERVAL; if (maxLevel > 0) { if (!(preference instanceof SeekBarPreference)) { Log.e(TAG, "Unexpected preference class: " + preference.getClass()); @@ -127,7 +128,7 @@ public class AutoBatterySeekBarPreferenceController extends BasePreferenceContro preference.setTitle(mContext.getString(R.string.battery_saver_seekbar_title, Utils.formatPercentage(level))); SeekBarPreference seekBarPreference = (SeekBarPreference) preference; - seekBarPreference.setProgress(level); + seekBarPreference.setProgress(level / INTERVAL); seekBarPreference.setSeekBarContentDescription( mContext.getString(R.string.battery_saver_turn_on_automatically_title)); } diff --git a/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java b/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java index f7793aa8e61..2dc35f17a74 100644 --- a/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java +++ b/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java @@ -157,7 +157,7 @@ public class AnomalyDetectionJobService extends JobService { metricsFeatureProvider.action(context, MetricsProto.MetricsEvent.ACTION_ANOMALY_IGNORED, packageName, - Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, + Pair.create(MetricsProto.MetricsEvent.FIELD_ANOMALY_TYPE, anomalyInfo.anomalyType), Pair.create(MetricsProto.MetricsEvent.FIELD_APP_VERSION_CODE, versionCode)); diff --git a/src/com/android/settings/network/ApnSettings.java b/src/com/android/settings/network/ApnSettings.java index e41d1b8ea56..f80acd4b3e3 100755 --- a/src/com/android/settings/network/ApnSettings.java +++ b/src/com/android/settings/network/ApnSettings.java @@ -43,6 +43,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; import android.text.TextUtils; import android.util.Log; import android.view.Menu; @@ -54,7 +55,7 @@ import android.widget.Toast; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.dataconnection.ApnSetting; +import com.android.internal.telephony.dataconnection.ApnSettingUtils; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.UiccController; import com.android.settings.R; @@ -336,7 +337,8 @@ public class ApnSettings extends RestrictedSettingsFragment implements ArrayList mvnoList, IccRecords r, String mvnoType, String mvnoMatchData) { if (r != null && !TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData)) { - if (ApnSetting.mvnoMatches(r, mvnoType, mvnoMatchData)) { + if (ApnSettingUtils.mvnoMatches(r, ApnSetting.getMvnoTypeIntFromString(mvnoType), + mvnoMatchData)) { mvnoList.add(pref); // Since adding to mvno list, save mvno info mMvnoType = mvnoType; diff --git a/src/com/android/settings/nfc/AndroidBeamPreferenceController.java b/src/com/android/settings/nfc/AndroidBeamPreferenceController.java index 12ab1b756dc..f99c47c188a 100644 --- a/src/com/android/settings/nfc/AndroidBeamPreferenceController.java +++ b/src/com/android/settings/nfc/AndroidBeamPreferenceController.java @@ -17,7 +17,6 @@ package com.android.settings.nfc; import android.content.Context; import android.nfc.NfcAdapter; -import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.core.BasePreferenceController; @@ -26,15 +25,12 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnResume; -import java.util.List; - public class AndroidBeamPreferenceController extends BasePreferenceController implements LifecycleObserver, OnResume, OnPause { public static final String KEY_ANDROID_BEAM_SETTINGS = "android_beam_settings"; private final NfcAdapter mNfcAdapter; private AndroidBeamEnabler mAndroidBeamEnabler; - private NfcAirplaneModeObserver mAirplaneModeObserver; public AndroidBeamPreferenceController(Context context, String key) { super(context, key); @@ -52,12 +48,6 @@ public class AndroidBeamPreferenceController extends BasePreferenceController final RestrictedPreference restrictedPreference = (RestrictedPreference) screen.findPreference(getPreferenceKey()); mAndroidBeamEnabler = new AndroidBeamEnabler(mContext, restrictedPreference); - - // Manually set dependencies for NFC when not toggleable. - if (!NfcPreferenceController.isToggleableInAirplaneMode(mContext)) { - mAirplaneModeObserver = new NfcAirplaneModeObserver(mContext, mNfcAdapter, - (Preference) restrictedPreference); - } } @Override @@ -70,9 +60,6 @@ public class AndroidBeamPreferenceController extends BasePreferenceController @Override public void onResume() { - if (mAirplaneModeObserver != null) { - mAirplaneModeObserver.register(); - } if (mAndroidBeamEnabler != null) { mAndroidBeamEnabler.resume(); } @@ -80,9 +67,6 @@ public class AndroidBeamPreferenceController extends BasePreferenceController @Override public void onPause() { - if (mAirplaneModeObserver != null) { - mAirplaneModeObserver.unregister(); - } if (mAndroidBeamEnabler != null) { mAndroidBeamEnabler.pause(); } diff --git a/src/com/android/settings/nfc/BaseNfcEnabler.java b/src/com/android/settings/nfc/BaseNfcEnabler.java index 88bafb98fb9..64c6d15c7ad 100644 --- a/src/com/android/settings/nfc/BaseNfcEnabler.java +++ b/src/com/android/settings/nfc/BaseNfcEnabler.java @@ -28,7 +28,7 @@ import androidx.preference.Preference; * preference. It will receive intent and update state to ensure preference show correct state. */ public abstract class BaseNfcEnabler { - private final Context mContext; + protected final Context mContext; protected final NfcAdapter mNfcAdapter; private final IntentFilter mIntentFilter; diff --git a/src/com/android/settings/nfc/NfcAirplaneModeObserver.java b/src/com/android/settings/nfc/NfcAirplaneModeObserver.java index d0ce045296f..65ac655bd8e 100644 --- a/src/com/android/settings/nfc/NfcAirplaneModeObserver.java +++ b/src/com/android/settings/nfc/NfcAirplaneModeObserver.java @@ -70,12 +70,13 @@ public class NfcAirplaneModeObserver extends ContentObserver { } mAirplaneMode = airplaneMode; - boolean toggleable = mAirplaneMode != 1; - if (toggleable) { - mNfcAdapter.enable(); - } else { + if (mAirplaneMode == 1) { + // airplane mode is on, need to turn off NFC, and check if user can toggle it mNfcAdapter.disable(); + mPreference.setEnabled(NfcPreferenceController.isToggleableInAirplaneMode(mContext)); + } else { + // airplane mode is off, no restriction + mPreference.setEnabled(true); } - mPreference.setEnabled(toggleable); } } diff --git a/src/com/android/settings/nfc/NfcEnabler.java b/src/com/android/settings/nfc/NfcEnabler.java index 507a0532378..777e7d114bd 100644 --- a/src/com/android/settings/nfc/NfcEnabler.java +++ b/src/com/android/settings/nfc/NfcEnabler.java @@ -18,8 +18,10 @@ package com.android.settings.nfc; import android.content.Context; import android.nfc.NfcAdapter; -import androidx.preference.SwitchPreference; +import android.provider.Settings; +import androidx.annotation.VisibleForTesting; +import androidx.preference.SwitchPreference; /** * NfcEnabler is a helper to manage the Nfc on/off checkbox preference. It turns on/off Nfc @@ -38,7 +40,7 @@ public class NfcEnabler extends BaseNfcEnabler { switch (newState) { case NfcAdapter.STATE_OFF: mPreference.setChecked(false); - mPreference.setEnabled(true); + mPreference.setEnabled(isToggleable()); break; case NfcAdapter.STATE_ON: mPreference.setChecked(true); @@ -54,4 +56,15 @@ public class NfcEnabler extends BaseNfcEnabler { break; } } + + @VisibleForTesting + boolean isToggleable() { + if (NfcPreferenceController.isToggleableInAirplaneMode(mContext) + || !NfcPreferenceController.shouldTurnOffNFCInAirplaneMode(mContext)) { + return true; + } + final int airplaneMode = Settings.Global.getInt( + mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); + return airplaneMode != 1; + } } diff --git a/src/com/android/settings/nfc/NfcPreferenceController.java b/src/com/android/settings/nfc/NfcPreferenceController.java index e1fa1b3e6ce..0f68a9ce47c 100644 --- a/src/com/android/settings/nfc/NfcPreferenceController.java +++ b/src/com/android/settings/nfc/NfcPreferenceController.java @@ -20,7 +20,7 @@ import android.content.IntentFilter; import android.nfc.NfcAdapter; import android.provider.Settings; -import androidx.preference.Preference; +import androidx.annotation.VisibleForTesting; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; @@ -37,7 +37,8 @@ public class NfcPreferenceController extends TogglePreferenceController public static final String KEY_TOGGLE_NFC = "toggle_nfc"; private final NfcAdapter mNfcAdapter; private NfcEnabler mNfcEnabler; - private NfcAirplaneModeObserver mAirplaneModeObserver; + @VisibleForTesting + NfcAirplaneModeObserver mAirplaneModeObserver; public NfcPreferenceController(Context context, String key) { super(context, key); @@ -57,10 +58,10 @@ public class NfcPreferenceController extends TogglePreferenceController mNfcEnabler = new NfcEnabler(mContext, switchPreference); - // Manually set dependencies for NFC when not toggleable. - if (!isToggleableInAirplaneMode(mContext)) { - mAirplaneModeObserver = new NfcAirplaneModeObserver(mContext, - mNfcAdapter, (Preference) switchPreference); + // Listen to airplane mode updates if NFC should be turned off when airplane mode is on + if (shouldTurnOffNFCInAirplaneMode(mContext) || isToggleableInAirplaneMode(mContext)) { + mAirplaneModeObserver = + new NfcAirplaneModeObserver(mContext, mNfcAdapter, switchPreference); } } @@ -125,6 +126,12 @@ public class NfcPreferenceController extends TogglePreferenceController } } + public static boolean shouldTurnOffNFCInAirplaneMode(Context context) { + final String airplaneModeRadios = Settings.Global.getString(context.getContentResolver(), + Settings.Global.AIRPLANE_MODE_RADIOS); + return airplaneModeRadios != null && airplaneModeRadios.contains(Settings.Global.RADIO_NFC); + } + public static boolean isToggleableInAirplaneMode(Context context) { final String toggleable = Settings.Global.getString(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index a2d4a3ab3ed..39380ea2111 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -39,6 +39,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import androidx.annotation.StringRes; +import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import android.text.TextUtils; @@ -124,7 +125,8 @@ public class ChooseLockGeneric extends SettingsActivity { */ public static final String EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS = "choose_lock_generic_extras"; - private static final int CONFIRM_EXISTING_REQUEST = 100; + @VisibleForTesting + static final int CONFIRM_EXISTING_REQUEST = 100; private static final int ENABLE_ENCRYPTION_REQUEST = 101; private static final int CHOOSE_LOCK_REQUEST = 102; private static final int CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST = 103; @@ -329,7 +331,9 @@ public class ChooseLockGeneric extends SettingsActivity { mWaitingForConfirmation = false; if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) { mPasswordConfirmed = true; - mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); + mUserPassword = data != null + ? data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD) + : null; updatePreferencesOrFinish(false /* isRecreatingActivity */); if (mForChangeCredRequiredForBoot) { if (!TextUtils.isEmpty(mUserPassword)) { @@ -394,7 +398,8 @@ public class ChooseLockGeneric extends SettingsActivity { } } - private void updatePreferencesOrFinish(boolean isRecreatingActivity) { + @VisibleForTesting + void updatePreferencesOrFinish(boolean isRecreatingActivity) { Intent intent = getActivity().getIntent(); int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1); if (quality == -1) { diff --git a/src/com/android/settings/vpn2/VpnUtils.java b/src/com/android/settings/vpn2/VpnUtils.java index 4528180b0ee..38c56c527d2 100644 --- a/src/com/android/settings/vpn2/VpnUtils.java +++ b/src/com/android/settings/vpn2/VpnUtils.java @@ -38,7 +38,8 @@ public class VpnUtils { private static final String TAG = "VpnUtils"; public static String getLockdownVpn() { - final byte[] value = KeyStore.getInstance().get(Credentials.LOCKDOWN_VPN); + final byte[] value = KeyStore.getInstance().get( + Credentials.LOCKDOWN_VPN, true /* suppressKeyNotFoundWarning */); return value == null ? null : new String(value); } diff --git a/src/com/android/settings/widget/UsageGraph.java b/src/com/android/settings/widget/UsageGraph.java index da61607278f..7238e5de128 100644 --- a/src/com/android/settings/widget/UsageGraph.java +++ b/src/com/android/settings/widget/UsageGraph.java @@ -255,9 +255,15 @@ public class UsageGraph extends View { return; } + canvas.save(); + if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { + // Flip the canvas along the y-axis of the center of itself before drawing paths. + canvas.scale(-1, 1, canvas.getWidth() * 0.5f, 0); + } drawLinePath(canvas, mLocalProjectedPaths, mDottedPaint); drawFilledPath(canvas, mLocalPaths, mFillPaint); drawLinePath(canvas, mLocalPaths, mLinePaint); + canvas.restore(); BatteryUtils.logRuntime(LOG_TAG, "onDraw", startTime); } diff --git a/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor b/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor index c2b3da98a1f..a2be681ce5c 100644 --- a/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor +++ b/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor @@ -1,4 +1,4 @@ -com.android.settings.applications.appinfo.AppActionButtonPreferenceController +com.android.settings.applications.appinfo.AppButtonsPreferenceController com.android.settings.applications.appinfo.AppBatteryPreferenceController com.android.settings.applications.appinfo.AppHeaderViewPreferenceController com.android.settings.applications.appinfo.AppMemoryPreferenceController diff --git a/tests/robotests/src/com/android/settings/applications/SpecialAccessSettingsTest.java b/tests/robotests/src/com/android/settings/applications/SpecialAccessSettingsTest.java deleted file mode 100644 index fd71af7ac1b..00000000000 --- a/tests/robotests/src/com/android/settings/applications/SpecialAccessSettingsTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2017 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 com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.spy; - -import android.content.Context; -import android.provider.SearchIndexableResource; - -import com.android.settings.R; -import com.android.settings.testutils.SettingsRobolectricTestRunner; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.List; - -@RunWith(SettingsRobolectricTestRunner.class) -public class SpecialAccessSettingsTest { - - private Context mContext; - private SpecialAccessSettings mFragment; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); - mFragment = new SpecialAccessSettings() { - @Override - public Context getContext() { - return mContext; - } - }; - } - - @Test - public void testSearchIndexProvider_shouldIndexResource() { - final List indexRes = - SpecialAccessSettings.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(mContext, - true /* enabled */); - final List niks = - SpecialAccessSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); - - assertThat(indexRes).isNotNull(); - assertThat(indexRes.get(0).xmlResId).isEqualTo(R.xml.special_access); - assertThat(niks).isEmpty(); - } - - @Test - @Config(qualifiers = "mcc999") - public void testSearchIndexProvider_ifElementsAreNotShown_shouldNotBeIndexed() { - final List niks = - SpecialAccessSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); - - assertThat(niks).contains(HighPowerAppsController.KEY_HIGH_POWER_APPS); - assertThat(niks).contains(DeviceAdministratorsController.KEY_DEVICE_ADMIN); - assertThat(niks).contains(PremiumSmsController.KEY_PREMIUM_SMS); - assertThat(niks).contains(DataSaverController.KEY_DATA_SAVER); - assertThat(niks).contains(EnabledVrListenersController.KEY_ENABLED_VR_LISTENERS); - } -} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceControllerTest.java deleted file mode 100644 index cf423f7a635..00000000000 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceControllerTest.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (C) 2017 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 com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.admin.DevicePolicyManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.UserInfo; -import android.content.res.Resources; -import android.os.Bundle; -import android.os.Handler; -import android.os.UserHandle; -import android.os.UserManager; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.testutils.FakeFeatureFactory; -import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settings.widget.ActionButtonPreference; -import com.android.settings.widget.ActionButtonPreferenceTest; -import com.android.settingslib.Utils; -import com.android.settingslib.applications.AppUtils; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.applications.instantapps.InstantAppDataProvider; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.util.ReflectionHelpers; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -@RunWith(SettingsRobolectricTestRunner.class) -public class AppActionButtonPreferenceControllerTest { - - @Mock - private UserManager mUserManager; - @Mock - private DevicePolicyManager mDevicePolicyManager; - @Mock - private AppInfoDashboardFragment mFragment; - @Mock - private ApplicationInfo mAppInfo; - @Mock - private PackageManager mPackageManager; - - private Context mContext; - private AppActionButtonPreferenceController mController; - private FakeFeatureFactory mFeatureFactory; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mFeatureFactory = FakeFeatureFactory.setupForTest(); - mContext = spy(RuntimeEnvironment.application); - mController = spy(new AppActionButtonPreferenceController(mContext, mFragment, "Package1")); - mController.mActionButtons = ActionButtonPreferenceTest.createMock(); - ReflectionHelpers.setField(mController, "mUserManager", mUserManager); - ReflectionHelpers.setField(mController, "mDpm", mDevicePolicyManager); - ReflectionHelpers.setField(mController, "mApplicationFeatureProvider", - mFeatureFactory.applicationFeatureProvider); - ReflectionHelpers.setField(mController, "mPm", mPackageManager); - when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); - when(mContext.getPackageManager()).thenReturn(mPackageManager); - final PackageInfo packageInfo = mock(PackageInfo.class); - packageInfo.applicationInfo = mAppInfo; - when(mFragment.getPackageInfo()).thenReturn(packageInfo); - } - - @Test - public void getAvailabilityStatus_notInstantApp_shouldReturnAvailable() { - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> false)); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.AVAILABLE); - } - - @Test - public void getAvailabilityStatus_isInstantApp_shouldReturnDisabled() { - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> true)); - - assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.DISABLED_FOR_USER); - } - - @Test - public void displayPreference_shouldInitializeForceStopButton() { - final PreferenceScreen screen = mock(PreferenceScreen.class); - final ActionButtonPreference preference = spy(new ActionButtonPreference(mContext)); - when(screen.findPreference(mController.getPreferenceKey())).thenReturn(preference); - - mController.displayPreference(screen); - - verify(preference).setButton2Positive(false); - verify(preference).setButton2Text(R.string.force_stop); - verify(preference).setButton2Enabled(false); - } - - @Test - public void refreshUi_shouldRefreshButton() { - final PackageInfo packageInfo = mock(PackageInfo.class); - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - final ApplicationInfo info = new ApplicationInfo(); - appEntry.info = info; - doNothing().when(mController).checkForceStop(appEntry, packageInfo); - doNothing().when(mController).initUninstallButtons(appEntry, packageInfo); - when(mFragment.getAppEntry()).thenReturn(appEntry); - when(mFragment.getPackageInfo()).thenReturn(packageInfo); - - mController.refreshUi(); - - verify(mController).checkForceStop(appEntry, packageInfo); - verify(mController).initUninstallButtons(appEntry, packageInfo); - } - - @Test - public void initUninstallButtonForUserApp_shouldSetNegativeButton() { - final ApplicationInfo info = new ApplicationInfo(); - info.flags = ApplicationInfo.FLAG_INSTALLED; - info.enabled = true; - final PackageInfo packageInfo = mock(PackageInfo.class); - packageInfo.applicationInfo = info; - when(mFragment.getPackageInfo()).thenReturn(packageInfo); - - assertThat(mController.initUninstallButtonForUserApp()).isTrue(); - verify(mController.mActionButtons).setButton1Positive(false); - } - - // Tests that we don't show the uninstall button for instant apps" - @Test - public void initUninstallButtonForUserApp_instantApps_noUninstallButton() { - // Make this app appear to be instant. - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> true)); - final ApplicationInfo info = new ApplicationInfo(); - info.flags = ApplicationInfo.FLAG_INSTALLED; - info.enabled = true; - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - appEntry.info = info; - final PackageInfo packageInfo = mock(PackageInfo.class); - packageInfo.applicationInfo = info; - when(mFragment.getPackageInfo()).thenReturn(packageInfo); - - assertThat(mController.initUninstallButtonForUserApp()).isFalse(); - verify(mController.mActionButtons).setButton1Visible(false); - } - - @Test - public void initUninstallButtonForUserApp_notInstalledForCurrentUser_shouldDisableButton() { - final ApplicationInfo info = new ApplicationInfo(); - info.enabled = true; - final PackageInfo packageInfo = mock(PackageInfo.class); - packageInfo.applicationInfo = info; - when(mFragment.getPackageInfo()).thenReturn(packageInfo); - final int userID1 = 1; - final int userID2 = 2; - final List userInfos = new ArrayList<>(); - userInfos.add(new UserInfo(userID1, "User1", UserInfo.FLAG_PRIMARY)); - userInfos.add(new UserInfo(userID2, "User2", UserInfo.FLAG_GUEST)); - when(mUserManager.getUsers(true)).thenReturn(userInfos); - - assertThat(mController.initUninstallButtonForUserApp()).isFalse(); - } - - // Tests that we don't show the force stop button for instant apps (they aren't allowed to run - // when they aren't in the foreground). - @Test - public void checkForceStop_instantApps_shouldNotShowForceStop() { - // Make this app appear to be instant. - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> true)); - final PackageInfo packageInfo = mock(PackageInfo.class); - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - final ApplicationInfo info = new ApplicationInfo(); - appEntry.info = info; - - mController.checkForceStop(appEntry, packageInfo); - - verify(mController.mActionButtons).setButton2Visible(false); - } - - @Test - public void checkForceStop_isStateProtected_shouldDisableForceStop() { - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> false)); - final String packageName = "Package1"; - final PackageInfo packageInfo = new PackageInfo(); - packageInfo.packageName = packageName; - final ApplicationInfo appInfo = new ApplicationInfo(); - appInfo.uid = 42; - appInfo.sourceDir = "source"; - final ApplicationsState.AppEntry appEntry = new ApplicationsState.AppEntry( - mContext, appInfo, 0); - when(mPackageManager.isPackageStateProtected(packageName, 0)).thenReturn(true); - - mController.checkForceStop(appEntry, packageInfo); - - verify(mController.mActionButtons).setButton2Enabled(false); - } - - @Test - public void checkForceStop_hasActiveAdmin_shouldDisableForceStop() { - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> false)); - final String packageName = "Package1"; - final PackageInfo packageInfo = new PackageInfo(); - packageInfo.packageName = packageName; - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - when(mDevicePolicyManager.packageHasActiveAdmins(packageName)).thenReturn(true); - - mController.checkForceStop(appEntry, packageInfo); - - verify(mController.mActionButtons).setButton2Enabled(false); - } - - @Test - public void checkForceStop_appRunning_shouldEnableForceStop() { - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> false)); - final PackageInfo packageInfo = mock(PackageInfo.class); - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - final ApplicationInfo info = new ApplicationInfo(); - appEntry.info = info; - - mController.checkForceStop(appEntry, packageInfo); - - verify(mController.mActionButtons).setButton2Enabled(true); - } - - @Test - public void checkForceStop_appStopped_shouldQueryPackageRestart() { - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> false)); - final PackageInfo packageInfo = mock(PackageInfo.class); - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - final ApplicationInfo info = new ApplicationInfo(); - appEntry.info = info; - info.flags = ApplicationInfo.FLAG_STOPPED; - info.packageName = "com.android.setting"; - - mController.checkForceStop(appEntry, packageInfo); - - verify(mContext).sendOrderedBroadcastAsUser(argThat(intent -> intent != null - && intent.getAction().equals(Intent.ACTION_QUERY_PACKAGE_RESTART)), - any(UserHandle.class), nullable(String.class), any(BroadcastReceiver.class), - nullable(Handler.class), anyInt(), nullable(String.class), nullable(Bundle.class)); - } - - @Test - public void handleDisableable_appIsHomeApp_buttonShouldNotWork() { - final ApplicationInfo info = new ApplicationInfo(); - info.packageName = "pkg"; - info.enabled = true; - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - appEntry.info = info; - final HashSet homePackages = new HashSet<>(); - homePackages.add(info.packageName); - ReflectionHelpers.setField(mController, "mHomePackages", homePackages); - - assertThat(mController.handleDisableable(appEntry, mock(PackageInfo.class))).isFalse(); - verify(mController.mActionButtons).setButton1Text(R.string.disable_text); - } - - @Test - @Config(shadows = ShadowUtils.class) - public void handleDisableable_appIsEnabled_buttonShouldWork() { - final ApplicationInfo info = new ApplicationInfo(); - info.packageName = "pkg"; - info.enabled = true; - info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED; - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - appEntry.info = info; - when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()) - .thenReturn(new HashSet<>()); - - assertThat(mController.handleDisableable(appEntry, mock(PackageInfo.class))).isTrue(); - verify(mController.mActionButtons).setButton1Text(R.string.disable_text); - } - - @Test - @Config(shadows = ShadowUtils.class) - public void handleDisableable_appIsDisabled_buttonShouldShowEnable() { - final ApplicationInfo info = new ApplicationInfo(); - info.packageName = "pkg"; - info.enabled = false; - info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED; - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - appEntry.info = info; - when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()) - .thenReturn(new HashSet<>()); - - assertThat(mController.handleDisableable(appEntry, mock(PackageInfo.class))).isTrue(); - verify(mController.mActionButtons).setButton1Text(R.string.enable_text); - verify(mController.mActionButtons).setButton1Positive(true); - } - - @Test - @Config(shadows = ShadowUtils.class) - public void handleDisableable_appIsEnabledAndInKeepEnabledWhitelist_buttonShouldNotWork() { - final ApplicationInfo info = new ApplicationInfo(); - info.packageName = "pkg"; - info.enabled = true; - info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED; - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - appEntry.info = info; - final HashSet packages = new HashSet<>(); - packages.add(info.packageName); - when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()) - .thenReturn(packages); - - assertThat(mController.handleDisableable(appEntry, mock(PackageInfo.class))).isFalse(); - verify(mController.mActionButtons).setButton1Text(R.string.disable_text); - } - - @Implements(Utils.class) - public static class ShadowUtils { - @Implementation - public static boolean isSystemPackage(Resources resources, PackageManager pm, - PackageInfo pkg) { - return false; - } - } -} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AppButtonsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java similarity index 93% rename from tests/robotests/src/com/android/settings/fuelgauge/AppButtonsPreferenceControllerTest.java rename to tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java index 551cb3e0bb0..24579ef961f 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/AppButtonsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.fuelgauge; +package com.android.settings.applications.appinfo; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; @@ -44,6 +44,8 @@ import android.os.UserManager; import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.applications.appinfo.AppButtonsPreferenceController; +import com.android.settings.applications.appinfo.ButtonActionDialogFragment; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.widget.ActionButtonPreference; import com.android.settings.widget.ActionButtonPreferenceTest; @@ -107,6 +109,7 @@ public class AppButtonsPreferenceControllerTest { MockitoAnnotations.initMocks(this); FakeFeatureFactory.setupForTest(); + doReturn(mDpm).when(mSettingsActivity).getSystemService(Context.DEVICE_POLICY_SERVICE); doReturn(mUserManager).when(mSettingsActivity).getSystemService(Context.USER_SERVICE); doReturn(mPackageManger).when(mSettingsActivity).getPackageManager(); doReturn(mAm).when(mSettingsActivity).getSystemService(Context.ACTIVITY_SERVICE); @@ -115,8 +118,7 @@ public class AppButtonsPreferenceControllerTest { when(mSettingsActivity.getResources().getString(anyInt())).thenReturn(RESOURCE_STRING); mController = spy(new AppButtonsPreferenceController(mSettingsActivity, mFragment, - mLifecycle, PACKAGE_NAME, mState, mDpm, mUserManager, mPackageManger, - REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN)); + mLifecycle, PACKAGE_NAME, mState, REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN)); doReturn(false).when(mController).isFallbackPackage(anyString()); mAppEntry.info = mAppInfo; @@ -334,6 +336,15 @@ public class AppButtonsPreferenceControllerTest { assertThat(controllable).isTrue(); } + @Test + public void handleActivityResult_packageUninstalled_shouldFinishPrefernecePanel() { + doReturn(false).when(mController).refreshUi(); + + mController.handleActivityResult(REQUEST_UNINSTALL, 0, mock(Intent.class)); + + verify(mSettingsActivity).finishPreferencePanel(anyInt(), any(Intent.class)); + } + @Test public void refreshUi_packageNull_shouldNotCrash() { mController.mPackageName = null; @@ -344,7 +355,7 @@ public class AppButtonsPreferenceControllerTest { @Test public void onPackageListChanged_available_shouldRefreshUi() { - doReturn(true).when(mController).isAvailable(); + doReturn(mController.AVAILABLE).when(mController).getAvailabilityStatus(); doReturn(true).when(mController).refreshUi(); mController.onPackageListChanged(); @@ -354,7 +365,7 @@ public class AppButtonsPreferenceControllerTest { @Test public void onPackageListChanged_notAvailable_shouldNotRefreshUiAndNoCrash() { - doReturn(false).when(mController).isAvailable(); + doReturn(mController.DISABLED_FOR_USER).when(mController).getAvailabilityStatus(); mController.onPackageListChanged(); diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java index 3128f30f656..8314cb70f5d 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java @@ -232,15 +232,6 @@ public final class AppInfoDashboardFragmentTest { verify(mActivity).invalidateOptionsMenu(); } - @Test - public void onActivityResult_packageUninstalled_shouldFinishAndRemoveTask() { - doReturn(false).when(mFragment).refreshUi(); - - mFragment.onActivityResult(mFragment.REQUEST_UNINSTALL, 0, mock(Intent.class)); - - verify(mActivity).finishAndRemoveTask(); - } - @Test public void getPreferenceControllers_noPackageInfo_shouldReturnNull() { doNothing().when(mFragment).retrieveAppEntry(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ButtonActionDialogFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/ButtonActionDialogFragmentTest.java similarity index 97% rename from tests/robotests/src/com/android/settings/fuelgauge/ButtonActionDialogFragmentTest.java rename to tests/robotests/src/com/android/settings/applications/appinfo/ButtonActionDialogFragmentTest.java index 83d8f7a81f6..ae6ba1d8146 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/ButtonActionDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/ButtonActionDialogFragmentTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.settings.fuelgauge; +package com.android.settings.applications.appinfo; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.anyInt; @@ -128,7 +128,7 @@ public class ButtonActionDialogFragmentTest { /** * Test fragment that used as the target fragment, it must implement the - * {@link com.android.settings.fuelgauge.ButtonActionDialogFragment.AppButtonsDialogListener} + * {@link ButtonActionDialogFragment.AppButtonsDialogListener} */ public static class TestFragment extends Fragment implements ButtonActionDialogFragment.AppButtonsDialogListener { diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPickerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPickerTest.java index bdf249d1f5e..3aa83a8ca1e 100644 --- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPickerTest.java +++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPickerTest.java @@ -16,8 +16,6 @@ package com.android.settings.applications.defaultapps; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; @@ -25,20 +23,11 @@ import static org.mockito.Mockito.when; import android.app.Activity; import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ResolveInfo; import android.os.UserManager; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settingslib.applications.DefaultAppInfo; - -import java.util.ArrayList; -import java.util.List; import org.junit.Before; import org.junit.Test; @@ -85,39 +74,4 @@ public class DefaultBrowserPickerTest { mPicker.getDefaultKey(); verify(mPackageManager).getDefaultBrowserPackageNameAsUser(anyInt()); } - - @Test - public void getCandidates_shouldNotIncludeDuplicatePackageName() throws NameNotFoundException { - final List resolveInfos = new ArrayList<>(); - final String PACKAGE_ONE = "com.first.package"; - final String PACKAGE_TWO = "com.second.package"; - resolveInfos.add(createResolveInfo(PACKAGE_ONE)); - resolveInfos.add(createResolveInfo(PACKAGE_TWO)); - resolveInfos.add(createResolveInfo(PACKAGE_ONE)); - resolveInfos.add(createResolveInfo(PACKAGE_TWO)); - when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) - .thenReturn(resolveInfos); - when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_ONE), anyInt(), anyInt())) - .thenReturn(createApplicationInfo(PACKAGE_ONE)); - when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_TWO), anyInt(), anyInt())) - .thenReturn(createApplicationInfo(PACKAGE_TWO)); - - final List defaultBrowserInfo = mPicker.getCandidates(); - - assertThat(defaultBrowserInfo.size()).isEqualTo(2); - } - - private ResolveInfo createResolveInfo(String packageName) { - final ResolveInfo info = new ResolveInfo(); - info.handleAllWebDataURI = true; - info.activityInfo = new ActivityInfo(); - info.activityInfo.packageName = packageName; - return info; - } - - private ApplicationInfo createApplicationInfo(String packageName) { - final ApplicationInfo info = new ApplicationInfo(); - info.packageName = packageName; - return info; - } } diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceControllerTest.java index 6bf6ac4189e..d4c4115b6a4 100644 --- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceControllerTest.java @@ -17,15 +17,21 @@ package com.android.settings.applications.defaultapps; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.os.UserManager; import androidx.preference.Preference; @@ -33,6 +39,8 @@ import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import java.util.ArrayList; +import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -73,8 +81,11 @@ public class DefaultBrowserPreferenceControllerTest { @Test public void isAvailable_hasBrowser_shouldReturnTrue() { + final ResolveInfo info = new ResolveInfo(); + info.activityInfo = new ActivityInfo(); + info.handleAllWebDataURI = true; when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) - .thenReturn(Collections.singletonList(new ResolveInfo())); + .thenReturn(Collections.singletonList(info)); assertThat(mController.isAvailable()).isTrue(); } @@ -88,6 +99,28 @@ public class DefaultBrowserPreferenceControllerTest { verify(pref).setSummary(R.string.app_list_preference_none); } + @Test + public void getDefaultAppLabel_hasAppWithMultipleResolvedInfo_shouldReturnLabel() + throws NameNotFoundException { + DefaultBrowserPreferenceController spyController = spy(mController); + doReturn(null).when(spyController).getDefaultAppIcon(); + final List resolveInfos = new ArrayList<>(); + final CharSequence PACKAGE_NAME = "com.test.package"; + final ResolveInfo info1 = spy(createResolveInfo(PACKAGE_NAME.toString())); + when(info1.loadLabel(mPackageManager)).thenReturn(PACKAGE_NAME); + resolveInfos.add(info1); + resolveInfos.add(createResolveInfo(PACKAGE_NAME.toString())); + when(mPackageManager.getDefaultBrowserPackageNameAsUser(anyInt())).thenReturn(null); + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) + .thenReturn(resolveInfos); + when(mPackageManager.getApplicationInfoAsUser( + eq(PACKAGE_NAME.toString()), anyInt(), anyInt())) + .thenReturn(createApplicationInfo(PACKAGE_NAME.toString())); + final Preference pref = mock(Preference.class); + + assertThat(spyController.getDefaultAppLabel()).isEqualTo(PACKAGE_NAME); + } + @Test public void getDefaultApp_shouldGetDefaultBrowserPackage() { mController.getDefaultAppInfo(); @@ -103,4 +136,40 @@ public class DefaultBrowserPreferenceControllerTest { assertThat(mController.isBrowserDefault("pkg", 0)).isTrue(); } + + @Test + public void getCandidates_shouldNotIncludeDuplicatePackageName() throws NameNotFoundException { + final List resolveInfos = new ArrayList<>(); + final String PACKAGE_ONE = "com.first.package"; + final String PACKAGE_TWO = "com.second.package"; + resolveInfos.add(createResolveInfo(PACKAGE_ONE)); + resolveInfos.add(createResolveInfo(PACKAGE_TWO)); + resolveInfos.add(createResolveInfo(PACKAGE_ONE)); + resolveInfos.add(createResolveInfo(PACKAGE_TWO)); + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) + .thenReturn(resolveInfos); + when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_ONE), anyInt(), anyInt())) + .thenReturn(createApplicationInfo(PACKAGE_ONE)); + when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_TWO), anyInt(), anyInt())) + .thenReturn(createApplicationInfo(PACKAGE_TWO)); + + final List defaultBrowserInfo = + mController.getCandidates(mPackageManager, 0 /* userId */); + + assertThat(defaultBrowserInfo.size()).isEqualTo(2); + } + + private ResolveInfo createResolveInfo(String packageName) { + final ResolveInfo info = new ResolveInfo(); + info.handleAllWebDataURI = true; + info.activityInfo = new ActivityInfo(); + info.activityInfo.packageName = packageName; + return info; + } + + private ApplicationInfo createApplicationInfo(String packageName) { + final ApplicationInfo info = new ApplicationInfo(); + info.packageName = packageName; + return info; + } } diff --git a/tests/robotests/src/com/android/settings/applications/DataSaverControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/DataSaverControllerTest.java similarity index 93% rename from tests/robotests/src/com/android/settings/applications/DataSaverControllerTest.java rename to tests/robotests/src/com/android/settings/applications/specialaccess/DataSaverControllerTest.java index 22140bb5c4d..c632d08bec0 100644 --- a/tests/robotests/src/com/android/settings/applications/DataSaverControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/DataSaverControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.applications; +package com.android.settings.applications.specialaccess; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; @@ -40,7 +40,7 @@ public class DataSaverControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application.getApplicationContext()); - mController = new DataSaverController(mContext); + mController = new DataSaverController(mContext, "key"); } @Test diff --git a/tests/robotests/src/com/android/settings/applications/DeviceAdministratorsControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/DeviceAdministratorsControllerTest.java similarity index 96% rename from tests/robotests/src/com/android/settings/applications/DeviceAdministratorsControllerTest.java rename to tests/robotests/src/com/android/settings/applications/specialaccess/DeviceAdministratorsControllerTest.java index ad7e615ce78..efa784683f3 100644 --- a/tests/robotests/src/com/android/settings/applications/DeviceAdministratorsControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/DeviceAdministratorsControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.applications; +package com.android.settings.applications.specialaccess; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; @@ -40,7 +40,7 @@ public class DeviceAdministratorsControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application.getApplicationContext()); - mController = new DeviceAdministratorsController(mContext); + mController = new DeviceAdministratorsController(mContext, "key"); } @Test diff --git a/tests/robotests/src/com/android/settings/applications/EnabledVrListenersControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/EnabledVrListenersControllerTest.java similarity index 66% rename from tests/robotests/src/com/android/settings/applications/EnabledVrListenersControllerTest.java rename to tests/robotests/src/com/android/settings/applications/specialaccess/EnabledVrListenersControllerTest.java index b36472031f7..7963fd4a20a 100644 --- a/tests/robotests/src/com/android/settings/applications/EnabledVrListenersControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/EnabledVrListenersControllerTest.java @@ -14,10 +14,9 @@ * limitations under the License. */ -package com.android.settings.applications; +package com.android.settings.applications.specialaccess; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.spy; import android.content.Context; @@ -26,31 +25,39 @@ import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowActivityManager; @RunWith(SettingsRobolectricTestRunner.class) public class EnabledVrListenersControllerTest { private Context mContext; private EnabledVrListenersController mController; + private ShadowActivityManager mActivityManager; @Before public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application.getApplicationContext()); - mController = new EnabledVrListenersController(mContext); + mContext = RuntimeEnvironment.application; + mController = new EnabledVrListenersController(mContext, "key"); + mActivityManager = Shadow.extract(mContext.getSystemService(Context.ACTIVITY_SERVICE)); } @Test - public void testEnabledVrListeners_byDefault_shouldBeShown() { + public void isAvailable_byDefault_true() { + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_lowMemory_false() { + mActivityManager.setIsLowRamDevice(true); assertThat(mController.isAvailable()).isTrue(); } @Test @Config(qualifiers = "mcc999") - public void testEnabledVrListeners_ifDisabled_shouldNotBeShown() { + public void isAvailable_disabled_false() { assertThat(mController.isAvailable()).isFalse(); } } diff --git a/tests/robotests/src/com/android/settings/applications/HighPowerAppsControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/HighPowerAppsControllerTest.java similarity index 93% rename from tests/robotests/src/com/android/settings/applications/HighPowerAppsControllerTest.java rename to tests/robotests/src/com/android/settings/applications/specialaccess/HighPowerAppsControllerTest.java index 6dfaa7c59eb..4713be22512 100644 --- a/tests/robotests/src/com/android/settings/applications/HighPowerAppsControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/HighPowerAppsControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.applications; +package com.android.settings.applications.specialaccess; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; @@ -40,7 +40,7 @@ public class HighPowerAppsControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application.getApplicationContext()); - mController = new HighPowerAppsController(mContext); + mController = new HighPowerAppsController(mContext, "key"); } @Test diff --git a/tests/robotests/src/com/android/settings/applications/PremiumSmsControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/PremiumSmsControllerTest.java similarity index 93% rename from tests/robotests/src/com/android/settings/applications/PremiumSmsControllerTest.java rename to tests/robotests/src/com/android/settings/applications/specialaccess/PremiumSmsControllerTest.java index cad4100adea..8f16da7022e 100644 --- a/tests/robotests/src/com/android/settings/applications/PremiumSmsControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/PremiumSmsControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.applications; +package com.android.settings.applications.specialaccess; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; @@ -40,7 +40,7 @@ public class PremiumSmsControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application.getApplicationContext()); - mController = new PremiumSmsController(mContext); + mController = new PremiumSmsController(mContext, "key"); } @Test diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/ZenAccessControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/ZenAccessControllerTest.java new file mode 100644 index 00000000000..205de10f1c8 --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/ZenAccessControllerTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 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.specialaccess; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowActivityManager; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ZenAccessControllerTest { + + private Context mContext; + private ZenAccessController mController; + private ShadowActivityManager mActivityManager; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mController = new ZenAccessController(mContext, "key"); + mActivityManager = Shadow.extract(mContext.getSystemService(Context.ACTIVITY_SERVICE)); + } + + @Test + public void isAvailable_byDefault_true() { + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_lowMemory_false() { + mActivityManager.setIsLowRamDevice(true); + assertThat(mController.isAvailable()).isTrue(); + } +} diff --git a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java index ced8fc4a2e4..0b1311d9364 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java @@ -203,6 +203,33 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } + @Test + public void onProfileConnectionStateChanged_hearingAidDeviceConnected_notInCall_addPreference() + { + mShadowAudioManager.setMode(AudioManager.MODE_NORMAL); + when(mBluetoothDeviceUpdater. + isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); + when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID); + + verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); + } + + @Test + public void onProfileConnectionStateChanged_hearingAidDeviceConnected_inCall_addPreference() { + mShadowAudioManager.setMode(AudioManager.MODE_IN_CALL); + when(mBluetoothDeviceUpdater. + isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); + when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID); + + verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); + } + @Test public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() { mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, diff --git a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java index 483df01a6b8..8120d91d28f 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java @@ -204,6 +204,34 @@ public class ConnectedBluetoothDeviceUpdaterTest { verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } + @Test + public void onProfileConnectionStateChanged_hearingAidDeviceConnected_inCall_removePreference() + { + mShadowAudioManager.setMode(AudioManager.MODE_IN_CALL); + when(mBluetoothDeviceUpdater. + isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); + when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID); + + verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); + } + + @Test + public void onProfileConnectionStateChanged_hearingAidDeviceConnected_notInCall_removePreference + () { + mShadowAudioManager.setMode(AudioManager.MODE_NORMAL); + when(mBluetoothDeviceUpdater. + isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); + when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID); + + verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); + } + @Test public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() { mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, diff --git a/tests/robotests/src/com/android/settings/core/BasePreferenceControllerSignatureInspector.java b/tests/robotests/src/com/android/settings/core/BasePreferenceControllerSignatureInspector.java index a9b4f5dc550..ce438b06bb0 100644 --- a/tests/robotests/src/com/android/settings/core/BasePreferenceControllerSignatureInspector.java +++ b/tests/robotests/src/com/android/settings/core/BasePreferenceControllerSignatureInspector.java @@ -67,7 +67,7 @@ public class BasePreferenceControllerSignatureInspector extends CodeInspector { } assertWithMessage("All BasePreferenceController (and subclasses) constructor must either" - + "only take Context, or (Context, String). No other types are allowed") + + " only take Context, or (Context, String). No other types are allowed") .that(badClasses.toString()) .isEmpty(); diff --git a/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java b/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java index 85c1cb522d2..8367fd3980e 100644 --- a/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java +++ b/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java @@ -19,7 +19,10 @@ package com.android.settings.development.qstile; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import android.content.ComponentName; +import android.content.pm.PackageManager; import android.service.quicksettings.Tile; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -37,6 +40,9 @@ public class DevelopmentTilesTest { @Mock private Tile mTile; + @Mock + private PackageManager mPackageManager; + private DevelopmentTiles mService; @Before @@ -48,11 +54,18 @@ public class DevelopmentTilesTest { @Test public void refresh_devOptionIsDisabled_shouldResetTileValue() { + final ComponentName cn = new ComponentName( + mService.getPackageName(), mService.getClass().getName()); + doReturn(mPackageManager).when(mService).getPackageManager(); + DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(mService, false); mService.setIsEnabled(true); mService.refresh(); + verify(mPackageManager).setComponentEnabledSetting(cn, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); assertThat(mService.isEnabled()).isFalse(); } } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java index a4107f5b186..c8ed42e342c 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java @@ -19,6 +19,7 @@ import static com.android.settings.applications.manageapplications.ManageApplica import static com.android.settings.applications.manageapplications.ManageApplications.EXTRA_WORK_ONLY; import static com.android.settings.utils.FileSizeFormatter.MEGABYTE_IN_BYTES; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -123,7 +124,8 @@ public class StorageItemPreferenceControllerTest { mController.handlePreferenceTreeClick(mPreference); final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(mActivity).startActivityAsUser(argumentCaptor.capture(), nullable(UserHandle.class)); + verify(mActivity).startActivityForResultAsUser(argumentCaptor.capture(), anyInt(), + nullable(UserHandle.class)); final Intent intent = argumentCaptor.getValue(); assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN); @@ -140,8 +142,8 @@ public class StorageItemPreferenceControllerTest { mController.handlePreferenceTreeClick(mPreference); final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(mFragment.getActivity()) - .startActivityAsUser(argumentCaptor.capture(), nullable(UserHandle.class)); + verify(mFragment.getActivity()).startActivityForResultAsUser(argumentCaptor.capture(), + anyInt(), nullable(UserHandle.class)); final Intent intent = argumentCaptor.getValue(); assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN); @@ -167,8 +169,8 @@ public class StorageItemPreferenceControllerTest { mController.handlePreferenceTreeClick(mPreference); final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(mFragment.getActivity()).startActivityAsUser(argumentCaptor.capture(), - nullable(UserHandle.class)); + verify(mFragment.getActivity()).startActivityForResultAsUser(argumentCaptor.capture(), + anyInt(), nullable(UserHandle.class)); final Intent intent = argumentCaptor.getValue(); assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN); @@ -186,8 +188,8 @@ public class StorageItemPreferenceControllerTest { mController.handlePreferenceTreeClick(mPreference); final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(mFragment.getActivity()) - .startActivityAsUser(argumentCaptor.capture(), nullable(UserHandle.class)); + verify(mFragment.getActivity()).startActivityForResultAsUser(argumentCaptor.capture(), + anyInt(), nullable(UserHandle.class)); Intent intent = argumentCaptor.getValue(); assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN); @@ -223,8 +225,8 @@ public class StorageItemPreferenceControllerTest { .isTrue(); final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(mFragment.getActivity()).startActivityAsUser(argumentCaptor.capture(), - nullable(UserHandle.class)); + verify(mFragment.getActivity()).startActivityForResultAsUser(argumentCaptor.capture(), + anyInt(), nullable(UserHandle.class)); Intent intent = argumentCaptor.getValue(); Intent browseIntent = mVolume.buildBrowseIntent(); @@ -240,8 +242,8 @@ public class StorageItemPreferenceControllerTest { mController.handlePreferenceTreeClick(mPreference); final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(mFragment.getActivity()).startActivityAsUser(argumentCaptor.capture(), - nullable(UserHandle.class)); + verify(mFragment.getActivity()).startActivityForResultAsUser(argumentCaptor.capture(), + anyInt(), nullable(UserHandle.class)); Intent intent = argumentCaptor.getValue(); assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN); @@ -258,8 +260,8 @@ public class StorageItemPreferenceControllerTest { mController.handlePreferenceTreeClick(mPreference); final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(mFragment.getActivity()).startActivityAsUser(argumentCaptor.capture(), - nullable(UserHandle.class)); + verify(mFragment.getActivity()).startActivityForResultAsUser(argumentCaptor.capture(), + anyInt(), nullable(UserHandle.class)); Intent intent = argumentCaptor.getValue(); assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java index 9457f091dbe..e1cf196a9d9 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java @@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.batterysaver; import static com.google.common.truth.Truth.assertThat; import androidx.lifecycle.LifecycleOwner; + import android.content.Context; import android.provider.Settings; @@ -39,6 +40,7 @@ public class AutoBatterySeekBarPreferenceControllerTest { private static final int TRIGGER_LEVEL = 20; private static final int DEFAULT_LEVEL = 15; + private static final int INTERVAL = 5; private AutoBatterySeekBarPreferenceController mController; private Context mContext; @@ -85,15 +87,16 @@ public class AutoBatterySeekBarPreferenceControllerTest { assertThat(mPreference.isVisible()).isTrue(); assertThat(mPreference.getTitle()).isEqualTo("At 20%"); - assertThat(mPreference.getProgress()).isEqualTo(TRIGGER_LEVEL); + assertThat(mPreference.getProgress()).isEqualTo(TRIGGER_LEVEL / INTERVAL); } + @Test public void testOnPreferenceChange_updateValue() { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0); - mController.onPreferenceChange(mPreference, TRIGGER_LEVEL); + mController.onPreferenceChange(mPreference, TRIGGER_LEVEL / INTERVAL); assertThat(Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0)).isEqualTo(TRIGGER_LEVEL); @@ -106,7 +109,7 @@ public class AutoBatterySeekBarPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.getMax()).isEqualTo(50); + assertThat(mPreference.getMax()).isEqualTo(50 / INTERVAL); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java index b55bf6b956c..adee4333169 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java @@ -178,7 +178,7 @@ public class AnomalyDetectionJobServiceTest { verify(mFeatureFactory.metricsFeatureProvider).action(mContext, MetricsProto.MetricsEvent.ACTION_ANOMALY_IGNORED, SYSTEM_PACKAGE, - Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, ANOMALY_TYPE), + Pair.create(MetricsProto.MetricsEvent.FIELD_ANOMALY_TYPE, ANOMALY_TYPE), Pair.create(MetricsProto.MetricsEvent.FIELD_APP_VERSION_CODE, VERSION_CODE)); } diff --git a/tests/robotests/src/com/android/settings/nfc/NfcAirplaneModeObserverTest.java b/tests/robotests/src/com/android/settings/nfc/NfcAirplaneModeObserverTest.java index 5efa94aaa98..c5e38a6fe44 100644 --- a/tests/robotests/src/com/android/settings/nfc/NfcAirplaneModeObserverTest.java +++ b/tests/robotests/src/com/android/settings/nfc/NfcAirplaneModeObserverTest.java @@ -18,11 +18,12 @@ package com.android.settings.nfc; import static com.google.common.truth.Truth.assertThat; +import android.content.ContentResolver; import android.content.Context; import android.nfc.NfcAdapter; import android.provider.Settings; -import androidx.preference.Preference; +import android.provider.Settings.Global; import androidx.preference.SwitchPreference; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -52,8 +53,8 @@ public class NfcAirplaneModeObserverTest { mNfcPreference = new SwitchPreference(RuntimeEnvironment.application); - mNfcAirplaneModeObserver = new NfcAirplaneModeObserver(mContext, mNfcAdapter, - (Preference) mNfcPreference); + mNfcAirplaneModeObserver = + new NfcAirplaneModeObserver(mContext, mNfcAdapter, mNfcPreference); } @Test @@ -67,20 +68,51 @@ public class NfcAirplaneModeObserverTest { NfcAirplaneModeObserver.AIRPLANE_MODE_URI); assertThat(mNfcAdapter.isEnabled()).isFalse(); + } + + @Test + public void NfcAirplaneModeObserver_airplaneModeOnNfcToggleable_shouldEnablePreference() { + ReflectionHelpers.setField(mNfcAirplaneModeObserver, "mAirplaneMode", 0); + final ContentResolver contentResolver = mContext.getContentResolver(); + Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 1); + Settings.Global.putString(contentResolver, + Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Settings.Global.RADIO_NFC); + + mNfcAirplaneModeObserver.onChange(false, NfcAirplaneModeObserver.AIRPLANE_MODE_URI); + + assertThat(mNfcPreference.isEnabled()).isTrue(); + } + + @Test + public void NfcAirplaneModeObserver_airplaneModeOnNfcNotToggleable_shouldDisablePreference() { + ReflectionHelpers.setField(mNfcAirplaneModeObserver, "mAirplaneMode", 0); + final ContentResolver contentResolver = mContext.getContentResolver(); + Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 1); + Settings.Global.putString(contentResolver, + Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Global.RADIO_WIFI); + + mNfcAirplaneModeObserver.onChange(false, NfcAirplaneModeObserver.AIRPLANE_MODE_URI); + assertThat(mNfcPreference.isEnabled()).isFalse(); } @Test - public void NfcAirplaneModeObserver_airplaneOff_shouldEnableNfc() { - ReflectionHelpers.setField(mNfcAirplaneModeObserver, - "mAirplaneMode", 1); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 0); + public void NfcAirplaneModeObserver_airplaneModeOff_shouldEnablePreference() { + ReflectionHelpers.setField(mNfcAirplaneModeObserver, "mAirplaneMode", 1); + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); - mNfcAirplaneModeObserver.onChange(false, - NfcAirplaneModeObserver.AIRPLANE_MODE_URI); + mNfcAirplaneModeObserver.onChange(false, NfcAirplaneModeObserver.AIRPLANE_MODE_URI); - assertThat(mNfcAdapter.isEnabled()).isTrue(); assertThat(mNfcPreference.isEnabled()).isTrue(); } + + @Test + public void NfcAirplaneModeObserver_airplaneModeOff_shouldNotEnableNfcAutomatically() { + ReflectionHelpers.setField(mNfcAirplaneModeObserver, "mAirplaneMode", 1); + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); + + mNfcAirplaneModeObserver.onChange(false, NfcAirplaneModeObserver.AIRPLANE_MODE_URI); + + assertThat(mNfcAdapter.isEnabled()).isFalse(); + } } diff --git a/tests/robotests/src/com/android/settings/nfc/NfcEnablerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcEnablerTest.java new file mode 100644 index 00000000000..a10c27a874b --- /dev/null +++ b/tests/robotests/src/com/android/settings/nfc/NfcEnablerTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018 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.nfc; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.ContentResolver; +import android.content.Context; +import android.nfc.NfcAdapter; +import android.provider.Settings; +import androidx.preference.SwitchPreference; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class NfcEnablerTest { + + @Mock + private SwitchPreference mNfcPreference; + + private Context mContext; + private NfcEnabler mNfcEnabler; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mNfcEnabler = spy(new NfcEnabler(mContext, mNfcPreference)); + } + + @Test + public void isToggleable_AirplaneModeOff_shouldReturnTrue() { + final ContentResolver contentResolver = mContext.getContentResolver(); + Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0); + Settings.Global.putString(contentResolver, + Settings.Global.AIRPLANE_MODE_RADIOS, Settings.Global.RADIO_NFC); + Settings.Global.putString(contentResolver, + Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Settings.Global.RADIO_NFC); + + assertThat(mNfcEnabler.isToggleable()).isTrue(); + } + + @Test + public void isToggleable_AirplaneModeOnNfcNotInAirplaneModeRadio_shouldReturnTrue() { + final ContentResolver contentResolver = mContext.getContentResolver(); + Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 1); + Settings.Global.putString(contentResolver, Settings.Global.AIRPLANE_MODE_RADIOS, ""); + + assertThat(mNfcEnabler.isToggleable()).isTrue(); + } + + @Test + public void isToggleable_AirplaneModeOnNfcToggleable_shouldReturnTrue() { + final ContentResolver contentResolver = mContext.getContentResolver(); + Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 1); + Settings.Global.putString(contentResolver, + Settings.Global.AIRPLANE_MODE_RADIOS, Settings.Global.RADIO_NFC); + Settings.Global.putString(contentResolver, + Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Settings.Global.RADIO_NFC); + + assertThat(mNfcEnabler.isToggleable()).isTrue(); + } + + @Test + public void isToggleable_AirplaneModeOnNfcNotToggleable_shouldReturnFalse() { + final ContentResolver contentResolver = mContext.getContentResolver(); + Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 1); + Settings.Global.putString(contentResolver, + Settings.Global.AIRPLANE_MODE_RADIOS, Settings.Global.RADIO_NFC); + Settings.Global.putString(contentResolver, + Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, ""); + + assertThat(mNfcEnabler.isToggleable()).isFalse(); + } + + @Test + public void handleNfcStateChanged_stateOff_shouldCheckIfPreferenceEnableState() { + mNfcEnabler.handleNfcStateChanged(NfcAdapter.STATE_OFF); + + verify(mNfcEnabler).isToggleable(); + } +} diff --git a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java index eaf6425f43f..758f72c0998 100644 --- a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java @@ -75,15 +75,6 @@ public class NfcPreferenceControllerTest { mNfcPreference = new SwitchPreference(RuntimeEnvironment.application); when(mScreen.findPreference(mNfcController.getPreferenceKey())).thenReturn(mNfcPreference); - - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, - Settings.Global.RADIO_NFC); - - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, - 0); - mNfcController.displayPreference(mScreen); } @Test @@ -102,6 +93,7 @@ public class NfcPreferenceControllerTest { @Test public void isNfcEnable_nfcStateNotTurning_shouldReturnTrue() { + mNfcController.displayPreference(mScreen); when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_ON); mNfcController.onResume(); assertThat(mNfcPreference.isEnabled()).isTrue(); @@ -113,6 +105,7 @@ public class NfcPreferenceControllerTest { @Test public void isNfcEnable_nfcStateTurning_shouldReturnFalse() { + mNfcController.displayPreference(mScreen); when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_TURNING_ON); mNfcController.onResume(); assertThat(mNfcPreference.isEnabled()).isFalse(); @@ -124,6 +117,7 @@ public class NfcPreferenceControllerTest { @Test public void isNfcChecked_nfcStateOn_shouldReturnTrue() { + mNfcController.displayPreference(mScreen); when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_ON); mNfcController.onResume(); assertThat(mNfcPreference.isChecked()).isTrue(); @@ -205,4 +199,52 @@ public class NfcPreferenceControllerTest { assertThat(NfcPreferenceController.isToggleableInAirplaneMode(mContext)).isFalse(); } + + @Test + public void shouldTurnOffNFCInAirplaneMode_airplaneModeRadiosContainsNfc_shouldReturnTrue() { + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_RADIOS, Settings.Global.RADIO_NFC); + + assertThat(NfcPreferenceController.shouldTurnOffNFCInAirplaneMode(mContext)).isTrue(); + } + + @Test + public void shouldTurnOffNFCInAirplaneMode_airplaneModeRadiosWithoutNfc_shouldReturnFalse() { + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_RADIOS, ""); + + assertThat(NfcPreferenceController.shouldTurnOffNFCInAirplaneMode(mContext)).isFalse(); + } + + @Test + public void displayPreference_airplaneModeRadiosContainsNfc_shouldCreateAirplaneModeObserver() { + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_RADIOS, Settings.Global.RADIO_NFC); + + mNfcController.displayPreference(mScreen); + + assertThat(mNfcController.mAirplaneModeObserver).isNotNull(); + } + + @Test + public void displayPreference_nfcToggleableInAirplaneMode_shouldCreateAirplaneModeObserver() { + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Settings.Global.RADIO_NFC); + + mNfcController.displayPreference(mScreen); + + assertThat(mNfcController.mAirplaneModeObserver).isNotNull(); + } + + @Test + public void displayPreference_nfcNotAffectByAirplaneMode_shouldNotCreateAirplaneModeObserver() { + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, ""); + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_RADIOS, ""); + + mNfcController.displayPreference(mScreen); + + assertThat(mNfcController.mAirplaneModeObserver).isNull(); + } } diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java new file mode 100644 index 00000000000..c66373b669b --- /dev/null +++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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.password; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; + +import android.app.Activity; +import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ChooseLockGenericTest { + + @Test + public void onActivityResult_nullIntentData_shouldNotCrash() { + ChooseLockGenericFragment fragment = spy(new ChooseLockGenericFragment()); + doNothing().when(fragment).updatePreferencesOrFinish(anyBoolean()); + + fragment.onActivityResult( + fragment.CONFIRM_EXISTING_REQUEST, Activity.RESULT_OK, null /* data */); + // no crash + } + +}