Consolidate the 2 app button prefernece controllers.

- move the fuelgauge app button controller and the button dialog
fragment into app info package and change app detail fragment to use
that controller instead.
- remove the original appinfo/AppActionButtonPreferenceController

Change-Id: I94ca072a8dfe6051853eb23efa1f96ac3e13d79d
Fixes: 80312809
Test: make RunSettingsRoboTests
This commit is contained in:
Doris Ling
2018-06-11 15:11:44 -07:00
parent f817b1e3a5
commit 2511d108ed
11 changed files with 58 additions and 918 deletions

View File

@@ -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<String> 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<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
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<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
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;
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.settings.fuelgauge; package com.android.settings.applications.appinfo;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
@@ -49,13 +49,13 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.applications.ApplicationFeatureProvider; import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.ActionButtonPreference; import com.android.settings.widget.ActionButtonPreference;
import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.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 * An easy way to handle them is to delegate them to {@link #handleDialogClick(int)} and
* {@link #handleActivityResult(int, int, Intent)} in this controller. * {@link #handleActivityResult(int, int, Intent)} in this controller.
*/ */
//TODO(80312809): Merge this class into {@link AppActionButtonPreferenceController} public class AppButtonsPreferenceController extends BasePreferenceController implements
public class AppButtonsPreferenceController extends AbstractPreferenceController implements
PreferenceControllerMixin, LifecycleObserver, OnResume, OnDestroy, PreferenceControllerMixin, LifecycleObserver, OnResume, OnDestroy,
ApplicationsState.Callbacks { ApplicationsState.Callbacks {
public static final String APP_CHG = "chg"; public static final String APP_CHG = "chg";
@@ -120,9 +119,8 @@ public class AppButtonsPreferenceController extends AbstractPreferenceController
public AppButtonsPreferenceController(SettingsActivity activity, Fragment fragment, public AppButtonsPreferenceController(SettingsActivity activity, Fragment fragment,
Lifecycle lifecycle, String packageName, ApplicationsState state, Lifecycle lifecycle, String packageName, ApplicationsState state,
DevicePolicyManager dpm, UserManager userManager, int requestUninstall, int requestRemoveDeviceAdmin) {
PackageManager packageManager, int requestUninstall, int requestRemoveDeviceAdmin) { super(activity, KEY_ACTION_BUTTONS);
super(activity);
if (!(fragment instanceof ButtonActionDialogFragment.AppButtonsDialogListener)) { if (!(fragment instanceof ButtonActionDialogFragment.AppButtonsDialogListener)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
@@ -133,9 +131,9 @@ public class AppButtonsPreferenceController extends AbstractPreferenceController
mMetricsFeatureProvider = factory.getMetricsFeatureProvider(); mMetricsFeatureProvider = factory.getMetricsFeatureProvider();
mApplicationFeatureProvider = factory.getApplicationFeatureProvider(activity); mApplicationFeatureProvider = factory.getApplicationFeatureProvider(activity);
mState = state; mState = state;
mDpm = dpm; mDpm = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
mUserManager = userManager; mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE);
mPm = packageManager; mPm = activity.getPackageManager();
mPackageName = packageName; mPackageName = packageName;
mActivity = activity; mActivity = activity;
mFragment = fragment; mFragment = fragment;
@@ -153,9 +151,10 @@ public class AppButtonsPreferenceController extends AbstractPreferenceController
} }
@Override @Override
public boolean isAvailable() { public int getAvailabilityStatus() {
// TODO(b/37313605): Re-enable once this controller supports instant apps // 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 @Override

View File

@@ -19,14 +19,12 @@ package com.android.settings.applications.appinfo;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.app.DialogFragment; import android.app.DialogFragment;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
@@ -35,7 +33,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
@@ -47,7 +44,6 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.DeviceAdminAdd;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment; 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.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -77,7 +72,8 @@ import java.util.List;
* uninstall the application. * uninstall the application.
*/ */
public class AppInfoDashboardFragment extends DashboardFragment public class AppInfoDashboardFragment extends DashboardFragment
implements ApplicationsState.Callbacks { implements ApplicationsState.Callbacks,
ButtonActionDialogFragment.AppButtonsDialogListener {
private static final String TAG = "AppInfoDashboard"; private static final String TAG = "AppInfoDashboard";
@@ -101,10 +97,7 @@ public class AppInfoDashboardFragment extends DashboardFragment
// Dialog identifiers used in showDialog // Dialog identifiers used in showDialog
private static final int DLG_BASE = 0; private static final int DLG_BASE = 0;
private static final int DLG_FORCE_STOP = DLG_BASE + 1; static final int DLG_CLEAR_INSTANT_APP = 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;
public static final String ARG_PACKAGE_NAME = "package"; public static final String ARG_PACKAGE_NAME = "package";
public static final String ARG_PACKAGE_UID = "uid"; public static final String ARG_PACKAGE_UID = "uid";
@@ -132,12 +125,11 @@ public class AppInfoDashboardFragment extends DashboardFragment
private boolean mInitialized; private boolean mInitialized;
private boolean mShowUninstalled; private boolean mShowUninstalled;
private boolean mUpdatedSysApp = false; private boolean mUpdatedSysApp = false;
private boolean mDisableAfterUninstall;
private List<Callback> mCallbacks = new ArrayList<>(); private List<Callback> mCallbacks = new ArrayList<>();
private InstantAppButtonsPreferenceController mInstantAppButtonPreferenceController; private InstantAppButtonsPreferenceController mInstantAppButtonPreferenceController;
private AppActionButtonPreferenceController mAppActionButtonPreferenceController; private AppButtonsPreferenceController mAppButtonsPreferenceController;
/** /**
* Callback to invoke when app info has been changed. * Callback to invoke when app info has been changed.
@@ -146,11 +138,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
void refreshUi(); void refreshUi();
} }
private boolean isDisabledUntilUsed() {
return mAppEntry.info.enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
}
@Override @Override
public void onAttach(Context context) { public void onAttach(Context context) {
super.onAttach(context); super.onAttach(context);
@@ -262,9 +249,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
// when app state changes. // when app state changes.
controllers.add( controllers.add(
new AppHeaderViewPreferenceController(context, this, packageName, lifecycle)); new AppHeaderViewPreferenceController(context, this, packageName, lifecycle));
mAppActionButtonPreferenceController =
new AppActionButtonPreferenceController(context, this, packageName);
controllers.add(mAppActionButtonPreferenceController);
for (AbstractPreferenceController controller : controllers) { for (AbstractPreferenceController controller : controllers) {
mCallbacks.add((Callback) controller); mCallbacks.add((Callback) controller);
@@ -275,6 +259,10 @@ public class AppInfoDashboardFragment extends DashboardFragment
mInstantAppButtonPreferenceController = mInstantAppButtonPreferenceController =
new InstantAppButtonsPreferenceController(context, this, packageName, lifecycle); new InstantAppButtonsPreferenceController(context, this, packageName, lifecycle);
controllers.add(mInstantAppButtonPreferenceController); 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 AppBatteryPreferenceController(context, this, packageName, lifecycle));
controllers.add(new AppMemoryPreferenceController(context, this, lifecycle)); controllers.add(new AppMemoryPreferenceController(context, this, lifecycle));
controllers.add(new DefaultHomeShortcutPreferenceController(context, packageName)); controllers.add(new DefaultHomeShortcutPreferenceController(context, packageName));
@@ -374,30 +362,19 @@ public class AppInfoDashboardFragment extends DashboardFragment
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) { if (requestCode == REQUEST_UNINSTALL) {
case REQUEST_UNINSTALL: // Refresh option menu
// Refresh option menu getActivity().invalidateOptionsMenu();
getActivity().invalidateOptionsMenu(); }
if (mAppButtonsPreferenceController != null) {
mAppButtonsPreferenceController.handleActivityResult(requestCode, resultCode, data);
}
}
if (mDisableAfterUninstall) { @Override
mDisableAfterUninstall = false; public void handleDialogClick(int id) {
new DisableChanger(this, mAppEntry.info, if (mAppButtonsPreferenceController != null) {
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) mAppButtonsPreferenceController.handleDialogClick(id);
.execute((Object) null);
}
if (!refreshUi()) {
onPackageRemoved();
} else {
startListeningToPackageRemove();
}
break;
case REQUEST_REMOVE_DEVICE_ADMIN:
if (!refreshUi()) {
setIntentAndFinish(true, true);
} else {
startListeningToPackageRemove();
}
break;
} }
} }
@@ -442,6 +419,7 @@ public class AppInfoDashboardFragment extends DashboardFragment
for (Callback callback : mCallbacks) { for (Callback callback : mCallbacks) {
callback.refreshUi(); callback.refreshUi();
} }
mAppButtonsPreferenceController.refreshUi();
if (!mInitialized) { if (!mInitialized) {
// First time init: are we displaying an uninstalled app? // First time init: are we displaying an uninstalled app?
@@ -471,53 +449,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
@VisibleForTesting @VisibleForTesting
AlertDialog createDialog(int id, int errorCode) { 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); return mInstantAppButtonPreferenceController.createDialog(id);
} }
@@ -530,22 +461,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
mMetricsFeatureProvider.action( mMetricsFeatureProvider.action(
getContext(), MetricsEvent.ACTION_SETTINGS_UNINSTALL_APP); getContext(), MetricsEvent.ACTION_SETTINGS_UNINSTALL_APP);
startActivityForResult(uninstallIntent, REQUEST_UNINSTALL); 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, public static void startAppInfoFragment(Class<?> fragment, int title, Bundle args,
@@ -565,74 +480,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
.launch(); .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() { private void onPackageRemoved() {
getActivity().finishActivity(SUB_INFO_FRAGMENT); getActivity().finishActivity(SUB_INFO_FRAGMENT);
getActivity().finishAndRemoveTask(); getActivity().finishAndRemoveTask();
@@ -659,26 +506,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
return count; return count;
} }
private static class DisableChanger extends AsyncTask<Object, Object, Object> {
final PackageManager mPm;
final WeakReference<AppInfoDashboardFragment> mActivity;
final ApplicationInfo mInfo;
final int mState;
DisableChanger(AppInfoDashboardFragment activity, ApplicationInfo info, int state) {
mPm = activity.mPm;
mActivity = new WeakReference<AppInfoDashboardFragment>(activity);
mInfo = info;
mState = state;
}
@Override
protected Object doInBackground(Object... params) {
mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
return null;
}
}
private String getPackageName() { private String getPackageName() {
if (mPackageName != null) { if (mPackageName != null) {
return mPackageName; return mPackageName;

View File

@@ -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.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
@@ -26,7 +25,7 @@ public class ButtonActionDialogFragment extends InstrumentedDialogFragment imple
/** /**
* Interface to handle the dialog click * Interface to handle the dialog click
*/ */
interface AppButtonsDialogListener { public interface AppButtonsDialogListener {
void handleDialogClick(int type); void handleDialogClick(int type);
} }

View File

@@ -20,7 +20,6 @@ import android.annotation.UserIdInt;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.LoaderManager; import android.app.LoaderManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.Loader; import android.content.Loader;
@@ -28,7 +27,6 @@ import android.content.pm.PackageManager;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference; import androidx.preference.Preference;
import android.text.TextUtils; import android.text.TextUtils;
@@ -43,6 +41,8 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.applications.LayoutPreference; 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.InstrumentedPreferenceFragment;
import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
@@ -112,9 +112,6 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
private AppButtonsPreferenceController mAppButtonsPreferenceController; private AppButtonsPreferenceController mAppButtonsPreferenceController;
private BackgroundActivityPreferenceController mBackgroundActivityPreferenceController; private BackgroundActivityPreferenceController mBackgroundActivityPreferenceController;
private DevicePolicyManager mDpm;
private UserManager mUserManager;
private PackageManager mPackageManager;
private List<Anomaly> mAnomalies; private List<Anomaly> mAnomalies;
private String mPackageName; private String mPackageName;
@@ -203,9 +200,6 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
super.onAttach(activity); super.onAttach(activity);
mState = ApplicationsState.getInstance(getActivity().getApplication()); 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()); mBatteryUtils = BatteryUtils.getInstance(getContext());
} }
@@ -332,8 +326,8 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
controllers.add(new BatteryOptimizationPreferenceController( controllers.add(new BatteryOptimizationPreferenceController(
(SettingsActivity) getActivity(), this, packageName)); (SettingsActivity) getActivity(), this, packageName));
mAppButtonsPreferenceController = new AppButtonsPreferenceController( mAppButtonsPreferenceController = new AppButtonsPreferenceController(
(SettingsActivity) getActivity(), this, getLifecycle(), packageName, mState, mDpm, (SettingsActivity) getActivity(), this, getLifecycle(), packageName, mState,
mUserManager, mPackageManager, REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN); REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN);
controllers.add(mAppButtonsPreferenceController); controllers.add(mAppButtonsPreferenceController);
return controllers; return controllers;

View File

@@ -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.AppBatteryPreferenceController
com.android.settings.applications.appinfo.AppHeaderViewPreferenceController com.android.settings.applications.appinfo.AppHeaderViewPreferenceController
com.android.settings.applications.appinfo.AppMemoryPreferenceController com.android.settings.applications.appinfo.AppMemoryPreferenceController

View File

@@ -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<UserInfo> 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<String> 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<String> 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;
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License. * 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 com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
@@ -44,6 +44,8 @@ import android.os.UserManager;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; 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.testutils.FakeFeatureFactory;
import com.android.settings.widget.ActionButtonPreference; import com.android.settings.widget.ActionButtonPreference;
import com.android.settings.widget.ActionButtonPreferenceTest; import com.android.settings.widget.ActionButtonPreferenceTest;
@@ -107,6 +109,7 @@ public class AppButtonsPreferenceControllerTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest(); FakeFeatureFactory.setupForTest();
doReturn(mDpm).when(mSettingsActivity).getSystemService(Context.DEVICE_POLICY_SERVICE);
doReturn(mUserManager).when(mSettingsActivity).getSystemService(Context.USER_SERVICE); doReturn(mUserManager).when(mSettingsActivity).getSystemService(Context.USER_SERVICE);
doReturn(mPackageManger).when(mSettingsActivity).getPackageManager(); doReturn(mPackageManger).when(mSettingsActivity).getPackageManager();
doReturn(mAm).when(mSettingsActivity).getSystemService(Context.ACTIVITY_SERVICE); doReturn(mAm).when(mSettingsActivity).getSystemService(Context.ACTIVITY_SERVICE);
@@ -115,8 +118,7 @@ public class AppButtonsPreferenceControllerTest {
when(mSettingsActivity.getResources().getString(anyInt())).thenReturn(RESOURCE_STRING); when(mSettingsActivity.getResources().getString(anyInt())).thenReturn(RESOURCE_STRING);
mController = spy(new AppButtonsPreferenceController(mSettingsActivity, mFragment, mController = spy(new AppButtonsPreferenceController(mSettingsActivity, mFragment,
mLifecycle, PACKAGE_NAME, mState, mDpm, mUserManager, mPackageManger, mLifecycle, PACKAGE_NAME, mState, REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN));
REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN));
doReturn(false).when(mController).isFallbackPackage(anyString()); doReturn(false).when(mController).isFallbackPackage(anyString());
mAppEntry.info = mAppInfo; mAppEntry.info = mAppInfo;
@@ -334,6 +336,15 @@ public class AppButtonsPreferenceControllerTest {
assertThat(controllable).isTrue(); 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 @Test
public void refreshUi_packageNull_shouldNotCrash() { public void refreshUi_packageNull_shouldNotCrash() {
mController.mPackageName = null; mController.mPackageName = null;
@@ -344,7 +355,7 @@ public class AppButtonsPreferenceControllerTest {
@Test @Test
public void onPackageListChanged_available_shouldRefreshUi() { public void onPackageListChanged_available_shouldRefreshUi() {
doReturn(true).when(mController).isAvailable(); doReturn(mController.AVAILABLE).when(mController).getAvailabilityStatus();
doReturn(true).when(mController).refreshUi(); doReturn(true).when(mController).refreshUi();
mController.onPackageListChanged(); mController.onPackageListChanged();
@@ -354,7 +365,7 @@ public class AppButtonsPreferenceControllerTest {
@Test @Test
public void onPackageListChanged_notAvailable_shouldNotRefreshUiAndNoCrash() { public void onPackageListChanged_notAvailable_shouldNotRefreshUiAndNoCrash() {
doReturn(false).when(mController).isAvailable(); doReturn(mController.DISABLED_FOR_USER).when(mController).getAvailabilityStatus();
mController.onPackageListChanged(); mController.onPackageListChanged();

View File

@@ -232,15 +232,6 @@ public final class AppInfoDashboardFragmentTest {
verify(mActivity).invalidateOptionsMenu(); 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 @Test
public void getPreferenceControllers_noPackageInfo_shouldReturnNull() { public void getPreferenceControllers_noPackageInfo_shouldReturnNull() {
doNothing().when(mFragment).retrieveAppEntry(); doNothing().when(mFragment).retrieveAppEntry();

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * 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 com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyInt; 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 * 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 public static class TestFragment extends Fragment implements
ButtonActionDialogFragment.AppButtonsDialogListener { ButtonActionDialogFragment.AppButtonsDialogListener {

View File

@@ -67,7 +67,7 @@ public class BasePreferenceControllerSignatureInspector extends CodeInspector {
} }
assertWithMessage("All BasePreferenceController (and subclasses) constructor must either" 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()) .that(badClasses.toString())
.isEmpty(); .isEmpty();