diff --git a/AndroidManifest.xml b/AndroidManifest.xml index ea4f6ffb2ee..4546a54cbbc 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -273,10 +273,6 @@ - - - - diff --git a/res/values/strings.xml b/res/values/strings.xml index 03e23190649..f193a3180f9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13404,8 +13404,10 @@ W+ network SIM - + DOWNLOADED SIM + + DOWNLOADED SIMS Active diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java index aeb5e9f2fcc..44990ffa3ef 100644 --- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java +++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java @@ -16,21 +16,33 @@ package com.android.settings.fuelgauge; +import android.app.AppGlobals; +import android.app.AppOpsManager; import android.app.backup.BackupDataInputStream; import android.app.backup.BackupDataOutput; import android.app.backup.BackupHelper; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; +import android.content.pm.UserInfo; import android.os.IDeviceIdleController; import android.os.RemoteException; import android.os.ParcelFileDescriptor; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.util.Log; import androidx.annotation.VisibleForTesting; +import com.android.settings.fuelgauge.BatteryOptimizeUtils.AppUsageState; + import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; /** An implementation to backup and restore battery configurations. */ public final class BatteryBackupHelper implements BackupHelper { @@ -39,13 +51,24 @@ public final class BatteryBackupHelper implements BackupHelper { private static final String DEVICE_IDLE_SERVICE = "deviceidle"; private static final boolean DEBUG = false; - @VisibleForTesting - static final CharSequence DELIMITER = ":"; - @VisibleForTesting + // Only the owner can see all apps. + private static final int RETRIEVE_FLAG_ADMIN = + PackageManager.MATCH_ANY_USER | + PackageManager.MATCH_DISABLED_COMPONENTS | + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; + private static final int RETRIEVE_FLAG = + PackageManager.MATCH_DISABLED_COMPONENTS | + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; + + static final CharSequence DELIMITER = ","; + static final CharSequence DELIMITER_MODE = "|"; static final String KEY_FULL_POWER_LIST = "full_power_list"; + static final String KEY_OPTIMIZATION_LIST = "optimization_mode_list"; @VisibleForTesting IDeviceIdleController mIDeviceIdleController; + @VisibleForTesting + IPackageManager mIPackageManager; private final Context mContext; @@ -57,10 +80,13 @@ public final class BatteryBackupHelper implements BackupHelper { public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) { if (!isOwner()) { - Log.w(TAG, "ignore the backup process for non-owner"); + Log.w(TAG, "ignore performBackup() for non-owner"); return; } - backupFullPowerList(getIDeviceIdleController(), data); + final List allowlistedApps = backupFullPowerList(data); + if (allowlistedApps != null) { + backupOptimizationMode(data, allowlistedApps); + } } @Override @@ -72,33 +98,57 @@ public final class BatteryBackupHelper implements BackupHelper { public void writeNewStateDescription(ParcelFileDescriptor newState) { } - private void backupFullPowerList( - IDeviceIdleController deviceIdleService, BackupDataOutput data) { + private List backupFullPowerList(BackupDataOutput data) { final long timestamp = System.currentTimeMillis(); String[] allowlistedApps; try { - allowlistedApps = deviceIdleService.getFullPowerWhitelist(); + allowlistedApps = getIDeviceIdleController().getFullPowerWhitelist(); } catch (RemoteException e) { Log.e(TAG, "backupFullPowerList() failed", e); - return; + return null; } // Ignores unexpected emptty result case. if (allowlistedApps == null || allowlistedApps.length == 0) { Log.w(TAG, "no data found in the getFullPowerList()"); - return; + return new ArrayList<>(); } + debugLog("allowlistedApps:" + Arrays.toString(allowlistedApps)); final String allowedApps = String.join(DELIMITER, allowlistedApps); - final byte[] allowedAppsBytes = allowedApps.getBytes(); - try { - data.writeEntityHeader(KEY_FULL_POWER_LIST, allowedAppsBytes.length); - data.writeEntityData(allowedAppsBytes, allowedAppsBytes.length); - } catch (IOException e) { - Log.e(TAG, "backup getFullPowerList() failed", e); - return; - } + writeBackupData(data, KEY_FULL_POWER_LIST, allowedApps); Log.d(TAG, String.format("backup getFullPowerList() size=%d in %d/ms", allowlistedApps.length, (System.currentTimeMillis() - timestamp))); + return Arrays.asList(allowlistedApps); + } + + @VisibleForTesting + void backupOptimizationMode(BackupDataOutput data, List allowlistedApps) { + final long timestamp = System.currentTimeMillis(); + final List applications = getInstalledApplications(); + if (applications == null || applications.isEmpty()) { + Log.w(TAG, "no data found in the getInstalledApplications()"); + return; + } + final StringBuilder builder = new StringBuilder(); + final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); + // Converts application into the AppUsageState. + for (ApplicationInfo info : applications) { + final int mode = appOps.checkOpNoThrow( + AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, info.uid, info.packageName); + final AppUsageState state = BatteryOptimizeUtils.getAppUsageState( + mode, allowlistedApps.contains(info.packageName)); + // Ignores default optimized or unknown state. + if (state == AppUsageState.OPTIMIZED || state == AppUsageState.UNKNOWN) { + continue; + } + final String packageOptimizeMode = info.packageName + DELIMITER_MODE + state; + builder.append(packageOptimizeMode + DELIMITER); + debugLog(packageOptimizeMode); + } + + writeBackupData(data, KEY_OPTIMIZATION_LIST, builder.toString()); + Log.d(TAG, String.format("backup getInstalledApplications() size=%d in %d/ms", + applications.size(), (System.currentTimeMillis() - timestamp))); } // Provides an opportunity to inject mock IDeviceIdleController for testing. @@ -111,10 +161,58 @@ public final class BatteryBackupHelper implements BackupHelper { return mIDeviceIdleController; } + private IPackageManager getIPackageManager() { + if (mIPackageManager != null) { + return mIPackageManager; + } + mIPackageManager = AppGlobals.getPackageManager(); + return mIPackageManager; + } + + private List getInstalledApplications() { + final List applications = new ArrayList<>(); + final UserManager um = mContext.getSystemService(UserManager.class); + for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) { + try { + @SuppressWarnings("unchecked") + final ParceledListSlice infoList = + getIPackageManager().getInstalledApplications( + userInfo.isAdmin() ? RETRIEVE_FLAG_ADMIN : RETRIEVE_FLAG, + userInfo.id); + if (infoList != null) { + applications.addAll(infoList.getList()); + } + } catch (Exception e) { + Log.e(TAG, "getInstalledApplications() is failed", e); + return null; + } + } + // Removes the application which is disabled by the system. + for (int index = applications.size() - 1; index >= 0; index--) { + final ApplicationInfo info = applications.get(index); + if (info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER + && !info.enabled) { + applications.remove(index); + } + } + return applications; + } + private void debugLog(String debugContent) { if (DEBUG) Log.d(TAG, debugContent); } + private static void writeBackupData( + BackupDataOutput data, String dataKey, String dataContent) { + final byte[] dataContentBytes = dataContent.getBytes(); + try { + data.writeEntityHeader(dataKey, dataContentBytes.length); + data.writeEntityData(dataContentBytes, dataContentBytes.length); + } catch (IOException e) { + Log.e(TAG, "writeBackupData() is failed for " + dataKey, e); + } + } + private static boolean isOwner() { return UserHandle.myUserId() == UserHandle.USER_OWNER; } diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java index 4a560402667..0be90600ba7 100644 --- a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java @@ -59,20 +59,25 @@ public class BatteryOptimizeUtils { mAllowListed = mPowerAllowListBackend.isAllowlisted(mPackageName); } - public AppUsageState getAppUsageState() { - refreshState(); - if (!mAllowListed && mMode == AppOpsManager.MODE_IGNORED) { + /** Gets the {@link AppUsageState} based on mode and allowed list. */ + public static AppUsageState getAppUsageState(int mode, boolean isAllowListed) { + if (!isAllowListed && mode == AppOpsManager.MODE_IGNORED) { return AppUsageState.RESTRICTED; - } else if (mAllowListed && mMode == AppOpsManager.MODE_ALLOWED) { + } else if (isAllowListed && mode == AppOpsManager.MODE_ALLOWED) { return AppUsageState.UNRESTRICTED; - } else if (!mAllowListed && mMode == AppOpsManager.MODE_ALLOWED) { + } else if (!isAllowListed && mode == AppOpsManager.MODE_ALLOWED) { return AppUsageState.OPTIMIZED; } else { - Log.d(TAG, "get unknown app usage state."); return AppUsageState.UNKNOWN; } } + /** Gets the current {@link AppUsageState}. */ + public AppUsageState getAppUsageState() { + refreshState(); + return getAppUsageState(mMode, mAllowListed); + } + public void setAppUsageState(AppUsageState state) { switch (state) { case RESTRICTED: diff --git a/src/com/android/settings/network/NetworkProviderCallsSmsController.java b/src/com/android/settings/network/NetworkProviderCallsSmsController.java index f83418ba551..c8b1c49b7bf 100644 --- a/src/com/android/settings/network/NetworkProviderCallsSmsController.java +++ b/src/com/android/settings/network/NetworkProviderCallsSmsController.java @@ -24,6 +24,7 @@ import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.view.View; import androidx.annotation.VisibleForTesting; import androidx.lifecycle.LifecycleObserver; @@ -44,12 +45,14 @@ public class NetworkProviderCallsSmsController extends AbstractPreferenceControl private static final String TAG = "NetworkProviderCallsSmsController"; private static final String KEY = "calls_and_sms"; + private static final String RTL_MARK = "\u200F"; private UserManager mUserManager; private SubscriptionManager mSubscriptionManager; private SubscriptionsChangeListener mSubscriptionsChangeListener; private TelephonyManager mTelephonyManager; private RestrictedPreference mPreference; + private boolean mIsRtlMode; /** * The summary text and click behavior of the "Calls & SMS" item on the @@ -61,6 +64,8 @@ public class NetworkProviderCallsSmsController extends AbstractPreferenceControl mUserManager = context.getSystemService(UserManager.class); mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + mIsRtlMode = context.getResources().getConfiguration().getLayoutDirection() + == View.LAYOUT_DIRECTION_RTL; if (lifecycle != null) { mSubscriptionsChangeListener = new SubscriptionsChangeListener(context, this); lifecycle.addObserver(this); @@ -121,6 +126,10 @@ public class NetworkProviderCallsSmsController extends AbstractPreferenceControl if (subInfo != subs.get(subs.size() - 1)) { summary.append(", "); } + + if (mIsRtlMode) { + summary.insert(0, RTL_MARK).insert(summary.length(), RTL_MARK); + } } return summary; } @@ -152,12 +161,12 @@ public class NetworkProviderCallsSmsController extends AbstractPreferenceControl } @VisibleForTesting - protected int getDefaultVoiceSubscriptionId(){ + protected int getDefaultVoiceSubscriptionId() { return SubscriptionManager.getDefaultVoiceSubscriptionId(); } @VisibleForTesting - protected int getDefaultSmsSubscriptionId(){ + protected int getDefaultSmsSubscriptionId() { return SubscriptionManager.getDefaultSmsSubscriptionId(); } diff --git a/src/com/android/settings/network/NetworkProviderDownloadedSimsCategoryController.java b/src/com/android/settings/network/NetworkProviderDownloadedSimsCategoryController.java index 199740fd202..f7c70f25a90 100644 --- a/src/com/android/settings/network/NetworkProviderDownloadedSimsCategoryController.java +++ b/src/com/android/settings/network/NetworkProviderDownloadedSimsCategoryController.java @@ -3,9 +3,11 @@ package com.android.settings.network; import android.content.Context; import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; +import com.android.settings.R; import com.android.settings.widget.PreferenceCategoryController; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; @@ -15,6 +17,7 @@ public class NetworkProviderDownloadedSimsCategoryController extends private static final String KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM = "provider_model_downloaded_sim_category"; + private PreferenceCategory mPreferenceCategory; private NetworkProviderDownloadedSimListController mNetworkProviderDownloadedSimListController; public NetworkProviderDownloadedSimsCategoryController(Context context, String key) { @@ -44,9 +47,19 @@ public class NetworkProviderDownloadedSimsCategoryController extends @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); - PreferenceCategory preferenceCategory = screen.findPreference( + mPreferenceCategory = screen.findPreference( KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM); - preferenceCategory.setVisible(isAvailable()); + mPreferenceCategory.setVisible(isAvailable()); mNetworkProviderDownloadedSimListController.displayPreference(screen); } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + int count = mPreferenceCategory.getPreferenceCount(); + String title = mContext.getString(count > 1 + ? R.string.downloaded_sims_category_title + : R.string.downloaded_sim_category_title); + mPreferenceCategory.setTitle(title); + } } diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java index 35a34d471a8..fefae9ee98f 100644 --- a/src/com/android/settings/network/NetworkProviderSettings.java +++ b/src/com/android/settings/network/NetworkProviderSettings.java @@ -710,6 +710,11 @@ public class NetworkProviderSettings extends RestrictedSettingsFragment Log.i(TAG, "onWifiStateChanged called with wifi state: " + wifiState); } + if (isFinishingOrDestroyed()) { + Log.w(TAG, "onWifiStateChanged shouldn't run when fragment is finishing or destroyed"); + return; + } + switch (wifiState) { case WifiManager.WIFI_STATE_ENABLED: updateWifiEntryPreferences(); @@ -981,6 +986,11 @@ public class NetworkProviderSettings extends RestrictedSettingsFragment private String getSavedNetworkSettingsSummaryText( int numSavedNetworks, int numSavedSubscriptions) { + if (getResources() == null) { + Log.w(TAG, "getSavedNetworkSettingsSummaryText shouldn't run if resource is not ready"); + return null; + } + if (numSavedSubscriptions == 0) { return getResources().getQuantityString(R.plurals.wifi_saved_access_points_summary, numSavedNetworks, numSavedNetworks); diff --git a/src/com/android/settings/network/telephony/CallsDefaultSubscriptionController.java b/src/com/android/settings/network/telephony/CallsDefaultSubscriptionController.java index 36b19ba1e60..16ac8f7ab4e 100644 --- a/src/com/android/settings/network/telephony/CallsDefaultSubscriptionController.java +++ b/src/com/android/settings/network/telephony/CallsDefaultSubscriptionController.java @@ -46,7 +46,7 @@ public class CallsDefaultSubscriptionController extends DefaultSubscriptionContr @Override public CharSequence getSummary() { if (Utils.isProviderModelEnabled(mContext)) { - return MobileNetworkUtils.getPreferredStatus(mContext, mManager, true); + return MobileNetworkUtils.getPreferredStatus(isRtlMode(), mContext, mManager, true); } else { return super.getSummary(); } diff --git a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java index 4fb6cff75d0..d21d584a71c 100644 --- a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java +++ b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java @@ -26,6 +26,7 @@ import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.view.View; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; @@ -62,11 +63,14 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere private static final ComponentName PSTN_CONNECTION_SERVICE_COMPONENT = new ComponentName("com.android.phone", "com.android.services.telephony.TelephonyConnectionService"); + private boolean mIsRtlMode; public DefaultSubscriptionController(Context context, String preferenceKey) { super(context, preferenceKey); mManager = context.getSystemService(SubscriptionManager.class); mChangeListener = new SubscriptionsChangeListener(context, this); + mIsRtlMode = context.getResources().getConfiguration().getLayoutDirection() + == View.LAYOUT_DIRECTION_RTL; } public void init(Lifecycle lifecycle) { @@ -285,4 +289,8 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere refreshSummary(mPreference); } } + + boolean isRtlMode() { + return mIsRtlMode; + } } diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java index 18984848b2f..6e5d4b7b8eb 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java +++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java @@ -99,6 +99,7 @@ public class MobileNetworkUtils { "esim.enable_esim_system_ui_by_default"; private static final String LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE"; + private static final String RTL_MARK = "\u200F"; // The following constants are used to draw signal icon. public static final int NO_CELL_DATA_TYPE_ICON = 0; @@ -922,7 +923,7 @@ public class MobileNetworkUtils { /** * Returns preferred status of Calls & SMS separately when Provider Model is enabled. */ - public static CharSequence getPreferredStatus(Context context, + public static CharSequence getPreferredStatus(boolean isRtlMode, Context context, SubscriptionManager subscriptionManager, boolean isPreferredCallStatus) { final List subs = SubscriptionUtil.getActiveSubscriptions( subscriptionManager); @@ -956,6 +957,10 @@ public class MobileNetworkUtils { if (subInfo != subs.get(subs.size() - 1)) { summary.append(", "); } + + if (isRtlMode) { + summary.insert(0, RTL_MARK).insert(summary.length(), RTL_MARK); + } } return summary; } else { diff --git a/src/com/android/settings/network/telephony/SmsDefaultSubscriptionController.java b/src/com/android/settings/network/telephony/SmsDefaultSubscriptionController.java index ca8c0f6c5d3..a73c62116a9 100644 --- a/src/com/android/settings/network/telephony/SmsDefaultSubscriptionController.java +++ b/src/com/android/settings/network/telephony/SmsDefaultSubscriptionController.java @@ -62,7 +62,7 @@ public class SmsDefaultSubscriptionController extends DefaultSubscriptionControl @Override public CharSequence getSummary() { if (Utils.isProviderModelEnabled(mContext)) { - return MobileNetworkUtils.getPreferredStatus(mContext, mManager, false); + return MobileNetworkUtils.getPreferredStatus(isRtlMode(), mContext, mManager, false); } else { return super.getSummary(); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java index 87aa8122caf..47fa59e6271 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java @@ -27,11 +27,21 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.AppOpsManager; import android.app.backup.BackupDataOutput; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; +import android.content.pm.UserInfo; import android.os.IDeviceIdleController; import android.os.RemoteException; import android.os.UserHandle; +import android.os.UserManager; + +import java.util.Arrays; +import java.util.List; import org.junit.After; import org.junit.Before; @@ -57,13 +67,23 @@ public final class BatteryBackupHelperTest { private BackupDataOutput mBackupDataOutput; @Mock private IDeviceIdleController mDeviceController; + @Mock + private IPackageManager mIPackageManager; + @Mock + private AppOpsManager mAppOpsManager; + @Mock + private UserManager mUserManager; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); + doReturn(mContext).when(mContext).getApplicationContext(); + doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class); + doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); mBatteryBackupHelper = new BatteryBackupHelper(mContext); mBatteryBackupHelper.mIDeviceIdleController = mDeviceController; + mBatteryBackupHelper.mIPackageManager = mIPackageManager; } @After @@ -135,6 +155,78 @@ public final class BatteryBackupHelperTest { verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt()); } + @Test + public void backupOptimizationMode_nullInstalledApps_ignoreBackupOptimization() + throws Exception { + final UserInfo userInfo = + new UserInfo(/*userId=*/ 0, /*userName=*/ "google", /*flag=*/ 0); + doReturn(Arrays.asList(userInfo)).when(mUserManager).getProfiles(anyInt()); + doThrow(new RuntimeException()) + .when(mIPackageManager) + .getInstalledApplications(anyInt(), anyInt()); + + mBatteryBackupHelper.backupOptimizationMode(mBackupDataOutput, null); + + verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt()); + } + + @Test + public void backupOptimizationMode_backupOptimizationMode() throws Exception { + final String packageName1 = "com.android.testing.1"; + final String packageName2 = "com.android.testing.2"; + final String packageName3 = "com.android.testing.3"; + final List allowlistedApps = Arrays.asList(packageName1); + createTestingData(packageName1, packageName2, packageName3); + + mBatteryBackupHelper.backupOptimizationMode(mBackupDataOutput, allowlistedApps); + + final String expectedResult = + packageName1 + "|UNRESTRICTED," + packageName2 + "|RESTRICTED,"; + final byte[] expectedBytes = expectedResult.getBytes(); + verify(mBackupDataOutput).writeEntityHeader( + BatteryBackupHelper.KEY_OPTIMIZATION_LIST, expectedBytes.length); + verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length); + } + + private void createTestingData( + String packageName1, String packageName2, String packageName3) throws Exception { + // Sets the getInstalledApplications() method for testing. + final UserInfo userInfo = + new UserInfo(/*userId=*/ 0, /*userName=*/ "google", /*flag=*/ 0); + doReturn(Arrays.asList(userInfo)).when(mUserManager).getProfiles(anyInt()); + final ApplicationInfo applicationInfo1 = new ApplicationInfo(); + applicationInfo1.enabled = true; + applicationInfo1.uid = 1; + applicationInfo1.packageName = packageName1; + final ApplicationInfo applicationInfo2 = new ApplicationInfo(); + applicationInfo2.enabled = false; + applicationInfo2.uid = 2; + applicationInfo2.packageName = packageName2; + applicationInfo2.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; + final ApplicationInfo applicationInfo3 = new ApplicationInfo(); + applicationInfo3.enabled = false; + applicationInfo3.uid = 3; + applicationInfo3.packageName = packageName3; + applicationInfo3.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + doReturn(new ParceledListSlice( + Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3))) + .when(mIPackageManager) + .getInstalledApplications(anyInt(), anyInt()); + // Sets the AppOpsManager for checkOpNoThrow() method. + doReturn(AppOpsManager.MODE_ALLOWED) + .when(mAppOpsManager) + .checkOpNoThrow( + AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, + applicationInfo1.uid, + applicationInfo1.packageName); + doReturn(AppOpsManager.MODE_IGNORED) + .when(mAppOpsManager) + .checkOpNoThrow( + AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, + applicationInfo2.uid, + applicationInfo2.packageName); + } + @Implements(UserHandle.class) public static class ShadowUserHandle { // Sets the default as thte OWNER role.