Loading AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -2046,7 +2046,7 @@ android:name=".fuelgauge.RequestIgnoreBatteryOptimizations" android:label="@string/high_power_apps" android:exported="true" android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight"> android:theme="@style/Transparent"> <intent-filter android:priority="1"> <action android:name="android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> <category android:name="android.intent.category.DEFAULT" /> Loading src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java +78 −20 Original line number Diff line number Diff line Loading @@ -16,9 +16,13 @@ package com.android.settings.fuelgauge; import static android.content.DialogInterface.BUTTON_NEGATIVE; import static android.content.DialogInterface.BUTTON_POSITIVE; import static com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNRESTRICTED; import android.Manifest; import android.app.settings.SettingsEnums; import android.content.DialogInterface; import android.content.pm.ApplicationInfo; import android.content.pm.PackageItemInfo; Loading @@ -30,41 +34,60 @@ import android.text.TextUtils; import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.FragmentActivity; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; import com.android.settings.R; import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.widget.SettingsThemeHelper; public class RequestIgnoreBatteryOptimizations extends AlertActivity public class RequestIgnoreBatteryOptimizations extends FragmentActivity implements DialogInterface.OnClickListener { private static final String TAG = "RequestIgnoreBatteryOptimizations"; private static final boolean DEBUG = false; @VisibleForTesting static BatteryOptimizeUtils sTestBatteryOptimizeUtils = null; @VisibleForTesting ApplicationInfo mApplicationInfo; @VisibleForTesting MetricsFeatureProvider mMetricsFeatureProvider; /** Request status of ignore battery optimizations dialog. */ @VisibleForTesting static BatteryOptimizeUtils sTestBatteryOptimizeUtils = null; enum RequestStatus { UNKNOWN(0), ALREADY_PROMPTED(1), NO_PERMISSION(2), PACKAGE_NOT_EXIST(3); private ApplicationInfo mApplicationInfo; public final int value; RequestStatus(int value) { this.value = value; } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); getWindow() .addSystemFlags( android.view.WindowManager.LayoutParams .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); if (SettingsThemeHelper.isExpressiveTheme(this)) { setTheme(R.style.Transparent_Expressive); } Uri data = getIntent().getData(); if (data == null) { debugLog( "No data supplied for IGNORE_BATTERY_OPTIMIZATION_SETTINGS in: " + getIntent()); finish(); return; } final String packageName = data.getSchemeSpecificPart(); final String packageName = data == null ? null : data.getSchemeSpecificPart(); if (TextUtils.isEmpty(packageName)) { debugLog( "No data supplied for IGNORE_BATTERY_OPTIMIZATION_SETTINGS in: " + getIntent()); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.PACKAGE_NOT_EXIST.value); finish(); return; } Loading @@ -73,6 +96,9 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity PowerManager power = getSystemService(PowerManager.class); if (power.isIgnoringBatteryOptimizations(packageName)) { debugLog("Not should prompt, already ignoring optimizations: " + packageName); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.ALREADY_PROMPTED.value); finish(); return; } Loading @@ -87,6 +113,9 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity + packageName + " does not hold permission " + Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.NO_PERMISSION.value); finish(); return; } Loading @@ -95,24 +124,30 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity mApplicationInfo = getPackageManager().getApplicationInfo(packageName, 0); } catch (PackageManager.NameNotFoundException e) { debugLog("Requested package doesn't exist: " + packageName); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.PACKAGE_NOT_EXIST.value); finish(); return; } final AlertController.AlertParams p = mAlertParams; final CharSequence appLabel = mApplicationInfo.loadSafeLabel( getPackageManager(), PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); p.mTitle = getText(R.string.high_power_prompt_title); p.mMessage = getString(R.string.high_power_prompt_body, appLabel); p.mPositiveButtonText = getText(R.string.allow); p.mNegativeButtonText = getText(R.string.deny); p.mPositiveButtonListener = this; p.mNegativeButtonListener = this; setupAlert(); AlertDialog dialog = new AlertDialog.Builder(this) .setTitle(R.string.high_power_prompt_title) .setMessage(getString(R.string.high_power_prompt_body, appLabel)) .setPositiveButton(R.string.allow, this) .setNegativeButton(R.string.deny, this) .setOnDismissListener(this::onDismissDialog) .create(); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_SHOW, mApplicationInfo.uid); dialog.show(); } @Override Loading @@ -128,12 +163,35 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity mApplicationInfo.packageName); batteryOptimizeUtils.setAppUsageState( MODE_UNRESTRICTED, Action.APPLY, /* forceMode= */ true); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_ALLOW, mApplicationInfo.uid); dialog.dismiss(); break; case BUTTON_NEGATIVE: logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_DENY, mApplicationInfo.uid); dialog.dismiss(); break; } } private void onDismissDialog(DialogInterface dialog) { logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_DISMISS, mApplicationInfo.uid); finish(); } private void logDialogAction(int action, int value) { mMetricsFeatureProvider.action( /* attribution= */ SettingsEnums.DIALOG_REQUEST_IGNORE_BATTERY_OPTIMIZE, /* action= */ action, /* pageId= */ SettingsEnums.DIALOG_REQUEST_IGNORE_BATTERY_OPTIMIZE, /* key= */ TAG, /* value= */ value); } private static void debugLog(String debugContent) { if (DEBUG) Log.w(TAG, debugContent); } Loading tests/robotests/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizationsTest.java +53 −4 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import static org.mockito.Mockito.when; import android.Manifest; import android.app.AppOpsManager; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; Loading @@ -43,6 +44,8 @@ import android.net.Uri; import android.os.Bundle; import android.os.PowerManager; import com.android.settings.fuelgauge.RequestIgnoreBatteryOptimizations.RequestStatus; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settingslib.fuelgauge.PowerAllowlistBackend; Loading @@ -58,6 +61,7 @@ import org.mockito.junit.MockitoRule; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) Loading @@ -66,28 +70,38 @@ public class RequestIgnoreBatteryOptimizationsTest { private static final int UID = 12345; private static final String PACKAGE_NAME = "com.android.app"; private static final String UNKNOWN_PACKAGE_NAME = "com.android.unknown"; private static final String METRICS_KEY = "RequestIgnoreBatteryOptimizations"; private static final String PACKAGE_LABEL = "app"; @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); private Context mContext; private FakeFeatureFactory mFeatureFactory; private RequestIgnoreBatteryOptimizations mActivity; private BatteryOptimizeUtils mBatteryOptimizeUtils; private PowerAllowlistBackend mPowerAllowlistBackend; private ActivityController<RequestIgnoreBatteryOptimizations> mActivityController; @Mock private PowerManager mMockPowerManager; @Mock private PackageManager mMockPackageManager; @Mock private ApplicationInfo mMockApplicationInfo; @Mock private BatteryUtils mMockBatteryUtils; @Mock private DialogInterface mMockDialog; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); mActivity = spy(Robolectric.setupActivity(RequestIgnoreBatteryOptimizations.class)); mFeatureFactory = FakeFeatureFactory.setupForTest(); mActivityController = Robolectric.buildActivity(RequestIgnoreBatteryOptimizations.class); mActivity = spy(mActivityController.get()); mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(mContext, UID, PACKAGE_NAME)); mPowerAllowlistBackend = spy(PowerAllowlistBackend.getInstance(mContext)); mBatteryOptimizeUtils.mPowerAllowListBackend = mPowerAllowlistBackend; mBatteryOptimizeUtils.mBatteryUtils = mMockBatteryUtils; mActivity.mApplicationInfo = mMockApplicationInfo; mActivity.mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider; mMockApplicationInfo.uid = UID; doNothing().when(mMockDialog).dismiss(); RequestIgnoreBatteryOptimizations.sTestBatteryOptimizeUtils = mBatteryOptimizeUtils; when(mActivity.getApplicationContext()).thenReturn(mContext); Loading Loading @@ -126,6 +140,7 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity, never()).finish(); assertDialogMetrics(SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_SHOW, UID); } @Test Loading @@ -135,6 +150,9 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity).finish(); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.PACKAGE_NOT_EXIST.value); } @Test Loading @@ -144,6 +162,9 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity).finish(); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.PACKAGE_NOT_EXIST.value); } @Test Loading @@ -154,6 +175,9 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity).finish(); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.ALREADY_PROMPTED.value); } @Test Loading @@ -167,6 +191,9 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity).finish(); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.NO_PERMISSION.value); } @Test Loading @@ -176,20 +203,26 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity).finish(); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.PACKAGE_NOT_EXIST.value); } @Test public void onClick_clickNegativeButton_doNothing() { mActivity.onClick(null, DialogInterface.BUTTON_NEGATIVE); mActivity.onClick(mMockDialog, DialogInterface.BUTTON_NEGATIVE); verifyNoInteractions(mBatteryOptimizeUtils); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_DENY, UID); verify(mMockDialog).dismiss(); } @Test public void onClick_clickPositiveButtonWithUnrestrictedMode_addAllowlist() { when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(MODE_UNRESTRICTED); mActivity.onClick(null, DialogInterface.BUTTON_POSITIVE); mActivity.onClick(mMockDialog, DialogInterface.BUTTON_POSITIVE); verify(mBatteryOptimizeUtils) .setAppUsageState( Loading @@ -198,6 +231,9 @@ public class RequestIgnoreBatteryOptimizationsTest { /* forceMode= */ true); verify(mPowerAllowlistBackend).addApp(PACKAGE_NAME, UID); verify(mMockBatteryUtils).setForceAppStandby(UID, PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_ALLOW, UID); verify(mMockDialog).dismiss(); } @Test Loading @@ -205,7 +241,7 @@ public class RequestIgnoreBatteryOptimizationsTest { when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(MODE_RESTRICTED); doNothing().when(mMockBatteryUtils).setForceAppStandby(anyInt(), anyString(), anyInt()); mActivity.onClick(null, DialogInterface.BUTTON_POSITIVE); mActivity.onClick(mMockDialog, DialogInterface.BUTTON_POSITIVE); verify(mBatteryOptimizeUtils) .setAppUsageState( Loading @@ -214,6 +250,9 @@ public class RequestIgnoreBatteryOptimizationsTest { /* forceMode= */ true); verify(mPowerAllowlistBackend).addApp(PACKAGE_NAME, UID); verify(mMockBatteryUtils).setForceAppStandby(UID, PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_ALLOW, UID); verify(mMockDialog).dismiss(); } private Intent createIntent(String packageName) { Loading @@ -221,4 +260,14 @@ public class RequestIgnoreBatteryOptimizationsTest { intent.setData(new Uri.Builder().scheme("package").opaquePart(packageName).build()); return intent; } private void assertDialogMetrics(final int action, final int value) { verify(mFeatureFactory.metricsFeatureProvider) .action( SettingsEnums.DIALOG_REQUEST_IGNORE_BATTERY_OPTIMIZE, action, SettingsEnums.DIALOG_REQUEST_IGNORE_BATTERY_OPTIMIZE, METRICS_KEY, value); } } Loading
AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -2046,7 +2046,7 @@ android:name=".fuelgauge.RequestIgnoreBatteryOptimizations" android:label="@string/high_power_apps" android:exported="true" android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight"> android:theme="@style/Transparent"> <intent-filter android:priority="1"> <action android:name="android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> <category android:name="android.intent.category.DEFAULT" /> Loading
src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java +78 −20 Original line number Diff line number Diff line Loading @@ -16,9 +16,13 @@ package com.android.settings.fuelgauge; import static android.content.DialogInterface.BUTTON_NEGATIVE; import static android.content.DialogInterface.BUTTON_POSITIVE; import static com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNRESTRICTED; import android.Manifest; import android.app.settings.SettingsEnums; import android.content.DialogInterface; import android.content.pm.ApplicationInfo; import android.content.pm.PackageItemInfo; Loading @@ -30,41 +34,60 @@ import android.text.TextUtils; import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.FragmentActivity; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; import com.android.settings.R; import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.widget.SettingsThemeHelper; public class RequestIgnoreBatteryOptimizations extends AlertActivity public class RequestIgnoreBatteryOptimizations extends FragmentActivity implements DialogInterface.OnClickListener { private static final String TAG = "RequestIgnoreBatteryOptimizations"; private static final boolean DEBUG = false; @VisibleForTesting static BatteryOptimizeUtils sTestBatteryOptimizeUtils = null; @VisibleForTesting ApplicationInfo mApplicationInfo; @VisibleForTesting MetricsFeatureProvider mMetricsFeatureProvider; /** Request status of ignore battery optimizations dialog. */ @VisibleForTesting static BatteryOptimizeUtils sTestBatteryOptimizeUtils = null; enum RequestStatus { UNKNOWN(0), ALREADY_PROMPTED(1), NO_PERMISSION(2), PACKAGE_NOT_EXIST(3); private ApplicationInfo mApplicationInfo; public final int value; RequestStatus(int value) { this.value = value; } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); getWindow() .addSystemFlags( android.view.WindowManager.LayoutParams .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); if (SettingsThemeHelper.isExpressiveTheme(this)) { setTheme(R.style.Transparent_Expressive); } Uri data = getIntent().getData(); if (data == null) { debugLog( "No data supplied for IGNORE_BATTERY_OPTIMIZATION_SETTINGS in: " + getIntent()); finish(); return; } final String packageName = data.getSchemeSpecificPart(); final String packageName = data == null ? null : data.getSchemeSpecificPart(); if (TextUtils.isEmpty(packageName)) { debugLog( "No data supplied for IGNORE_BATTERY_OPTIMIZATION_SETTINGS in: " + getIntent()); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.PACKAGE_NOT_EXIST.value); finish(); return; } Loading @@ -73,6 +96,9 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity PowerManager power = getSystemService(PowerManager.class); if (power.isIgnoringBatteryOptimizations(packageName)) { debugLog("Not should prompt, already ignoring optimizations: " + packageName); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.ALREADY_PROMPTED.value); finish(); return; } Loading @@ -87,6 +113,9 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity + packageName + " does not hold permission " + Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.NO_PERMISSION.value); finish(); return; } Loading @@ -95,24 +124,30 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity mApplicationInfo = getPackageManager().getApplicationInfo(packageName, 0); } catch (PackageManager.NameNotFoundException e) { debugLog("Requested package doesn't exist: " + packageName); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.PACKAGE_NOT_EXIST.value); finish(); return; } final AlertController.AlertParams p = mAlertParams; final CharSequence appLabel = mApplicationInfo.loadSafeLabel( getPackageManager(), PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); p.mTitle = getText(R.string.high_power_prompt_title); p.mMessage = getString(R.string.high_power_prompt_body, appLabel); p.mPositiveButtonText = getText(R.string.allow); p.mNegativeButtonText = getText(R.string.deny); p.mPositiveButtonListener = this; p.mNegativeButtonListener = this; setupAlert(); AlertDialog dialog = new AlertDialog.Builder(this) .setTitle(R.string.high_power_prompt_title) .setMessage(getString(R.string.high_power_prompt_body, appLabel)) .setPositiveButton(R.string.allow, this) .setNegativeButton(R.string.deny, this) .setOnDismissListener(this::onDismissDialog) .create(); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_SHOW, mApplicationInfo.uid); dialog.show(); } @Override Loading @@ -128,12 +163,35 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity mApplicationInfo.packageName); batteryOptimizeUtils.setAppUsageState( MODE_UNRESTRICTED, Action.APPLY, /* forceMode= */ true); logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_ALLOW, mApplicationInfo.uid); dialog.dismiss(); break; case BUTTON_NEGATIVE: logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_DENY, mApplicationInfo.uid); dialog.dismiss(); break; } } private void onDismissDialog(DialogInterface dialog) { logDialogAction( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_DISMISS, mApplicationInfo.uid); finish(); } private void logDialogAction(int action, int value) { mMetricsFeatureProvider.action( /* attribution= */ SettingsEnums.DIALOG_REQUEST_IGNORE_BATTERY_OPTIMIZE, /* action= */ action, /* pageId= */ SettingsEnums.DIALOG_REQUEST_IGNORE_BATTERY_OPTIMIZE, /* key= */ TAG, /* value= */ value); } private static void debugLog(String debugContent) { if (DEBUG) Log.w(TAG, debugContent); } Loading
tests/robotests/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizationsTest.java +53 −4 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import static org.mockito.Mockito.when; import android.Manifest; import android.app.AppOpsManager; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; Loading @@ -43,6 +44,8 @@ import android.net.Uri; import android.os.Bundle; import android.os.PowerManager; import com.android.settings.fuelgauge.RequestIgnoreBatteryOptimizations.RequestStatus; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settingslib.fuelgauge.PowerAllowlistBackend; Loading @@ -58,6 +61,7 @@ import org.mockito.junit.MockitoRule; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) Loading @@ -66,28 +70,38 @@ public class RequestIgnoreBatteryOptimizationsTest { private static final int UID = 12345; private static final String PACKAGE_NAME = "com.android.app"; private static final String UNKNOWN_PACKAGE_NAME = "com.android.unknown"; private static final String METRICS_KEY = "RequestIgnoreBatteryOptimizations"; private static final String PACKAGE_LABEL = "app"; @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); private Context mContext; private FakeFeatureFactory mFeatureFactory; private RequestIgnoreBatteryOptimizations mActivity; private BatteryOptimizeUtils mBatteryOptimizeUtils; private PowerAllowlistBackend mPowerAllowlistBackend; private ActivityController<RequestIgnoreBatteryOptimizations> mActivityController; @Mock private PowerManager mMockPowerManager; @Mock private PackageManager mMockPackageManager; @Mock private ApplicationInfo mMockApplicationInfo; @Mock private BatteryUtils mMockBatteryUtils; @Mock private DialogInterface mMockDialog; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); mActivity = spy(Robolectric.setupActivity(RequestIgnoreBatteryOptimizations.class)); mFeatureFactory = FakeFeatureFactory.setupForTest(); mActivityController = Robolectric.buildActivity(RequestIgnoreBatteryOptimizations.class); mActivity = spy(mActivityController.get()); mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(mContext, UID, PACKAGE_NAME)); mPowerAllowlistBackend = spy(PowerAllowlistBackend.getInstance(mContext)); mBatteryOptimizeUtils.mPowerAllowListBackend = mPowerAllowlistBackend; mBatteryOptimizeUtils.mBatteryUtils = mMockBatteryUtils; mActivity.mApplicationInfo = mMockApplicationInfo; mActivity.mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider; mMockApplicationInfo.uid = UID; doNothing().when(mMockDialog).dismiss(); RequestIgnoreBatteryOptimizations.sTestBatteryOptimizeUtils = mBatteryOptimizeUtils; when(mActivity.getApplicationContext()).thenReturn(mContext); Loading Loading @@ -126,6 +140,7 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity, never()).finish(); assertDialogMetrics(SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_SHOW, UID); } @Test Loading @@ -135,6 +150,9 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity).finish(); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.PACKAGE_NOT_EXIST.value); } @Test Loading @@ -144,6 +162,9 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity).finish(); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.PACKAGE_NOT_EXIST.value); } @Test Loading @@ -154,6 +175,9 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity).finish(); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.ALREADY_PROMPTED.value); } @Test Loading @@ -167,6 +191,9 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity).finish(); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.NO_PERMISSION.value); } @Test Loading @@ -176,20 +203,26 @@ public class RequestIgnoreBatteryOptimizationsTest { mActivity.onCreate(new Bundle()); verify(mActivity).finish(); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_FAIL_SHOW, RequestStatus.PACKAGE_NOT_EXIST.value); } @Test public void onClick_clickNegativeButton_doNothing() { mActivity.onClick(null, DialogInterface.BUTTON_NEGATIVE); mActivity.onClick(mMockDialog, DialogInterface.BUTTON_NEGATIVE); verifyNoInteractions(mBatteryOptimizeUtils); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_DENY, UID); verify(mMockDialog).dismiss(); } @Test public void onClick_clickPositiveButtonWithUnrestrictedMode_addAllowlist() { when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(MODE_UNRESTRICTED); mActivity.onClick(null, DialogInterface.BUTTON_POSITIVE); mActivity.onClick(mMockDialog, DialogInterface.BUTTON_POSITIVE); verify(mBatteryOptimizeUtils) .setAppUsageState( Loading @@ -198,6 +231,9 @@ public class RequestIgnoreBatteryOptimizationsTest { /* forceMode= */ true); verify(mPowerAllowlistBackend).addApp(PACKAGE_NAME, UID); verify(mMockBatteryUtils).setForceAppStandby(UID, PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_ALLOW, UID); verify(mMockDialog).dismiss(); } @Test Loading @@ -205,7 +241,7 @@ public class RequestIgnoreBatteryOptimizationsTest { when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(MODE_RESTRICTED); doNothing().when(mMockBatteryUtils).setForceAppStandby(anyInt(), anyString(), anyInt()); mActivity.onClick(null, DialogInterface.BUTTON_POSITIVE); mActivity.onClick(mMockDialog, DialogInterface.BUTTON_POSITIVE); verify(mBatteryOptimizeUtils) .setAppUsageState( Loading @@ -214,6 +250,9 @@ public class RequestIgnoreBatteryOptimizationsTest { /* forceMode= */ true); verify(mPowerAllowlistBackend).addApp(PACKAGE_NAME, UID); verify(mMockBatteryUtils).setForceAppStandby(UID, PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); assertDialogMetrics( SettingsEnums.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZE_ALLOW, UID); verify(mMockDialog).dismiss(); } private Intent createIntent(String packageName) { Loading @@ -221,4 +260,14 @@ public class RequestIgnoreBatteryOptimizationsTest { intent.setData(new Uri.Builder().scheme("package").opaquePart(packageName).build()); return intent; } private void assertDialogMetrics(final int action, final int value) { verify(mFeatureFactory.metricsFeatureProvider) .action( SettingsEnums.DIALOG_REQUEST_IGNORE_BATTERY_OPTIMIZE, action, SettingsEnums.DIALOG_REQUEST_IGNORE_BATTERY_OPTIMIZE, METRICS_KEY, value); } }