diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9b2cf2412a2..ea4f6ffb2ee 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1694,11 +1694,6 @@
android:value="true" />
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/drawable-night/illustration_accessibility_gesture_two_finger.xml b/res/drawable-night/illustration_accessibility_gesture_two_finger.xml
new file mode 100644
index 00000000000..c95523b1655
--- /dev/null
+++ b/res/drawable-night/illustration_accessibility_gesture_two_finger.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/drawable/illustration_accessibility_gesture_three_finger.xml b/res/drawable/illustration_accessibility_gesture_three_finger.xml
new file mode 100644
index 00000000000..c14d7443110
--- /dev/null
+++ b/res/drawable/illustration_accessibility_gesture_three_finger.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/drawable/illustration_accessibility_gesture_two_finger.xml b/res/drawable/illustration_accessibility_gesture_two_finger.xml
new file mode 100644
index 00000000000..3ef4fd1db4b
--- /dev/null
+++ b/res/drawable/illustration_accessibility_gesture_two_finger.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/tutorial_dialog_launch_by_gesture_navigation_settings.xml b/res/layout/tutorial_dialog_launch_by_gesture_navigation_settings.xml
index 524f7c9b7e4..b494e9367b2 100644
--- a/res/layout/tutorial_dialog_launch_by_gesture_navigation_settings.xml
+++ b/res/layout/tutorial_dialog_launch_by_gesture_navigation_settings.xml
@@ -29,11 +29,15 @@
android:orientation="vertical"
android:paddingTop="24dp">
-
+
-
+
finish());
- }
-}
diff --git a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java
index 09f28d72c9b..0ca16cb99b0 100644
--- a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java
+++ b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java
@@ -32,7 +32,6 @@ import android.text.style.ImageSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -77,13 +76,13 @@ public final class AccessibilityGestureNavigationTutorial {
@Retention(RetentionPolicy.SOURCE)
@IntDef({
DialogType.LAUNCH_SERVICE_BY_ACCESSIBILITY_BUTTON,
- DialogType.LAUNCH_SERVICE_BY_GESTURE_NAVIGATION,
+ DialogType.LAUNCH_SERVICE_BY_ACCESSIBILITY_GESTURE,
DialogType.GESTURE_NAVIGATION_SETTINGS,
})
private @interface DialogType {
int LAUNCH_SERVICE_BY_ACCESSIBILITY_BUTTON = 0;
- int LAUNCH_SERVICE_BY_GESTURE_NAVIGATION = 1;
+ int LAUNCH_SERVICE_BY_ACCESSIBILITY_GESTURE = 1;
int GESTURE_NAVIGATION_SETTINGS = 2;
}
@@ -92,13 +91,17 @@ public final class AccessibilityGestureNavigationTutorial {
private static final DialogInterface.OnClickListener mOnClickListener =
(DialogInterface dialog, int which) -> dialog.dismiss();
- public static void showGestureNavigationSettingsTutorialDialog(Context context,
- DialogInterface.OnDismissListener dismissListener) {
+ /**
+ * Displays a dialog that guides users to use accessibility features with accessibility
+ * gestures under system gesture navigation mode.
+ */
+ public static void showGestureNavigationTutorialDialog(Context context,
+ DialogInterface.OnDismissListener onDismissListener) {
final AlertDialog alertDialog = new AlertDialog.Builder(context)
.setView(createTutorialDialogContentView(context,
DialogType.GESTURE_NAVIGATION_SETTINGS))
.setNegativeButton(R.string.accessibility_tutorial_dialog_button, mOnClickListener)
- .setOnDismissListener(dismissListener)
+ .setOnDismissListener(onDismissListener)
.create();
alertDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
@@ -117,8 +120,8 @@ public final class AccessibilityGestureNavigationTutorial {
return alertDialog;
}
- static AlertDialog showGestureNavigationTutorialDialog(Context context) {
- return createDialog(context, DialogType.LAUNCH_SERVICE_BY_GESTURE_NAVIGATION);
+ static AlertDialog showAccessibilityGestureTutorialDialog(Context context) {
+ return createDialog(context, DialogType.LAUNCH_SERVICE_BY_ACCESSIBILITY_GESTURE);
}
static AlertDialog createAccessibilityTutorialDialog(Context context, int shortcutTypes) {
@@ -129,7 +132,7 @@ public final class AccessibilityGestureNavigationTutorial {
}
/**
- * Get a content View for a dialog to confirm that they want to enable a service.
+ * Gets a content View for a dialog to confirm that they want to enable a service.
*
* @param context A valid context
* @param dialogType The type of tutorial dialog
@@ -146,42 +149,36 @@ public final class AccessibilityGestureNavigationTutorial {
content = inflater.inflate(
R.layout.tutorial_dialog_launch_service_by_accessibility_button, null);
break;
- case DialogType.LAUNCH_SERVICE_BY_GESTURE_NAVIGATION:
+ case DialogType.LAUNCH_SERVICE_BY_ACCESSIBILITY_GESTURE:
content = inflater.inflate(
R.layout.tutorial_dialog_launch_service_by_gesture_navigation, null);
- final TextureView gestureTutorialVideo = content.findViewById(
- R.id.gesture_tutorial_video);
- final TextView gestureTutorialMessage = content.findViewById(
- R.id.gesture_tutorial_message);
- VideoPlayer.create(context, AccessibilityUtil.isTouchExploreEnabled(context)
- ? R.raw.illustration_accessibility_gesture_three_finger
- : R.raw.illustration_accessibility_gesture_two_finger,
- gestureTutorialVideo);
- gestureTutorialMessage.setText(AccessibilityUtil.isTouchExploreEnabled(context)
- ? R.string.accessibility_tutorial_dialog_message_gesture_talkback
- : R.string.accessibility_tutorial_dialog_message_gesture);
+ setupGestureNavigationTextWithImage(context, content);
break;
case DialogType.GESTURE_NAVIGATION_SETTINGS:
content = inflater.inflate(
R.layout.tutorial_dialog_launch_by_gesture_navigation_settings, null);
- final TextureView gestureSettingsTutorialVideo = content.findViewById(
- R.id.gesture_tutorial_video);
- final TextView gestureSettingsTutorialMessage = content.findViewById(
- R.id.gesture_tutorial_message);
- VideoPlayer.create(context, AccessibilityUtil.isTouchExploreEnabled(context)
- ? R.raw.illustration_accessibility_gesture_three_finger
- : R.raw.illustration_accessibility_gesture_two_finger,
- gestureSettingsTutorialVideo);
- final int stringResId = AccessibilityUtil.isTouchExploreEnabled(context)
- ? R.string.accessibility_tutorial_dialog_message_gesture_settings_talkback
- : R.string.accessibility_tutorial_dialog_message_gesture_settings;
- gestureSettingsTutorialMessage.setText(stringResId);
+ setupGestureNavigationTextWithImage(context, content);
break;
}
return content;
}
+ private static void setupGestureNavigationTextWithImage(Context context, View view) {
+ final boolean isTouchExploreEnabled = AccessibilityUtil.isTouchExploreEnabled(context);
+
+ final ImageView imageView = view.findViewById(R.id.image);
+ final int gestureSettingsImageResId =
+ isTouchExploreEnabled ? R.drawable.illustration_accessibility_gesture_three_finger
+ : R.drawable.illustration_accessibility_gesture_two_finger;
+ imageView.setImageResource(gestureSettingsImageResId);
+
+ final TextView textView = view.findViewById(R.id.gesture_tutorial_message);
+ textView.setText(isTouchExploreEnabled
+ ? R.string.accessibility_tutorial_dialog_message_gesture_settings_talkback
+ : R.string.accessibility_tutorial_dialog_message_gesture_settings);
+ }
+
private static AlertDialog createDialog(Context context, int dialogType) {
final AlertDialog alertDialog = new AlertDialog.Builder(context)
.setView(createTutorialDialogContentView(context, dialogType))
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index 1c7ce39bab9..c15217490c6 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -141,7 +141,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends
switch (dialogId) {
case DialogEnums.GESTURE_NAVIGATION_TUTORIAL:
return AccessibilityGestureNavigationTutorial
- .showGestureNavigationTutorialDialog(getPrefContext());
+ .showAccessibilityGestureTutorialDialog(getPrefContext());
case DialogEnums.MAGNIFICATION_EDIT_SHORTCUT:
final CharSequence dialogTitle = getPrefContext().getString(
R.string.accessibility_shortcut_title, mPackageName);
diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
index 2b5576d6743..aeb5e9f2fcc 100644
--- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
+++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
@@ -20,24 +20,47 @@ import android.app.backup.BackupDataInputStream;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupHelper;
import android.content.Context;
+import android.os.IDeviceIdleController;
+import android.os.RemoteException;
import android.os.ParcelFileDescriptor;
+import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+
+import java.io.IOException;
+import java.util.Arrays;
+
/** An implementation to backup and restore battery configurations. */
public final class BatteryBackupHelper implements BackupHelper {
/** An inditifier for {@link BackupHelper}. */
public static final String TAG = "BatteryBackupHelper";
+ private static final String DEVICE_IDLE_SERVICE = "deviceidle";
+ private static final boolean DEBUG = false;
+
+ @VisibleForTesting
+ static final CharSequence DELIMITER = ":";
+ @VisibleForTesting
+ static final String KEY_FULL_POWER_LIST = "full_power_list";
+
+ @VisibleForTesting
+ IDeviceIdleController mIDeviceIdleController;
private final Context mContext;
public BatteryBackupHelper(Context context) {
- mContext = context;
+ mContext = context.getApplicationContext();
}
@Override
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
- Log.d(TAG, "performBackup()");
+ if (!isOwner()) {
+ Log.w(TAG, "ignore the backup process for non-owner");
+ return;
+ }
+ backupFullPowerList(getIDeviceIdleController(), data);
}
@Override
@@ -48,4 +71,51 @@ public final class BatteryBackupHelper implements BackupHelper {
@Override
public void writeNewStateDescription(ParcelFileDescriptor newState) {
}
+
+ private void backupFullPowerList(
+ IDeviceIdleController deviceIdleService, BackupDataOutput data) {
+ final long timestamp = System.currentTimeMillis();
+ String[] allowlistedApps;
+ try {
+ allowlistedApps = deviceIdleService.getFullPowerWhitelist();
+ } catch (RemoteException e) {
+ Log.e(TAG, "backupFullPowerList() failed", e);
+ return;
+ }
+ // Ignores unexpected emptty result case.
+ if (allowlistedApps == null || allowlistedApps.length == 0) {
+ Log.w(TAG, "no data found in the getFullPowerList()");
+ return;
+ }
+ 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;
+ }
+ Log.d(TAG, String.format("backup getFullPowerList() size=%d in %d/ms",
+ allowlistedApps.length, (System.currentTimeMillis() - timestamp)));
+ }
+
+ // Provides an opportunity to inject mock IDeviceIdleController for testing.
+ private IDeviceIdleController getIDeviceIdleController() {
+ if (mIDeviceIdleController != null) {
+ return mIDeviceIdleController;
+ }
+ mIDeviceIdleController = IDeviceIdleController.Stub.asInterface(
+ ServiceManager.getService(DEVICE_IDLE_SERVICE));
+ return mIDeviceIdleController;
+ }
+
+ private void debugLog(String debugContent) {
+ if (DEBUG) Log.d(TAG, debugContent);
+ }
+
+ private static boolean isOwner() {
+ return UserHandle.myUserId() == UserHandle.USER_OWNER;
+ }
}
diff --git a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
index 4b9cfa36f2f..1a116da91ab 100644
--- a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
+++ b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
@@ -28,17 +28,19 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityManager;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
-import com.android.settings.SettingsTutorialDialogWrapperActivity;
+import com.android.settings.accessibility.AccessibilityGestureNavigationTutorial;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
@@ -57,8 +59,6 @@ import java.util.List;
public class SystemNavigationGestureSettings extends RadioButtonPickerFragment implements
HelpResourceProvider {
- private static final String TAG = "SystemNavigationGesture";
-
@VisibleForTesting
static final String KEY_SYSTEM_NAV_3BUTTONS = "system_nav_3buttons";
@VisibleForTesting
@@ -69,10 +69,33 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i
public static final String PREF_KEY_SUGGESTION_COMPLETE =
"pref_system_navigation_suggestion_complete";
+ private static final String KEY_SHOW_A11Y_TUTORIAL_DIALOG = "show_a11y_tutorial_dialog_bool";
+
+ private boolean mA11yTutorialDialogShown = false;
+
private IOverlayManager mOverlayManager;
private IllustrationPreference mVideoPreference;
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ mA11yTutorialDialogShown =
+ savedInstanceState.getBoolean(KEY_SHOW_A11Y_TUTORIAL_DIALOG, false);
+ if (mA11yTutorialDialogShown) {
+ AccessibilityGestureNavigationTutorial.showGestureNavigationTutorialDialog(
+ getContext(), dialog -> mA11yTutorialDialogShown = false);
+ }
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ outState.putBoolean(KEY_SHOW_A11Y_TUTORIAL_DIALOG, mA11yTutorialDialogShown);
+ super.onSaveInstanceState(outState);
+ }
+
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -177,14 +200,7 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i
protected boolean setDefaultKey(String key) {
setCurrentSystemNavigationMode(mOverlayManager, key);
setIllustrationVideo(mVideoPreference, key);
- if (TextUtils.equals(KEY_SYSTEM_NAV_GESTURAL, key)
- && !isAccessibilityFloatingMenuEnabled()
- && (isAnyServiceSupportAccessibilityButton() || isNavBarMagnificationEnabled())) {
- final Intent intent = new Intent(getActivity(),
- SettingsTutorialDialogWrapperActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
- }
+ setGestureNavigationTutorialDialog(key);
return true;
}
@@ -257,6 +273,18 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i
}
}
+ private void setGestureNavigationTutorialDialog(String systemNavKey) {
+ if (TextUtils.equals(KEY_SYSTEM_NAV_GESTURAL, systemNavKey)
+ && !isAccessibilityFloatingMenuEnabled()
+ && (isAnyServiceSupportAccessibilityButton() || isNavBarMagnificationEnabled())) {
+ mA11yTutorialDialogShown = true;
+ AccessibilityGestureNavigationTutorial.showGestureNavigationTutorialDialog(getContext(),
+ dialog -> mA11yTutorialDialogShown = false);
+ } else {
+ mA11yTutorialDialogShown = false;
+ }
+ }
+
private boolean isAnyServiceSupportAccessibilityButton() {
final AccessibilityManager ams = getContext().getSystemService(AccessibilityManager.class);
final List targets = ams.getAccessibilityShortcutTargets(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
new file mode 100644
index 00000000000..87aa8122caf
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.settings.fuelgauge;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.backup.BackupDataOutput;
+import android.content.Context;
+import android.os.IDeviceIdleController;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {BatteryBackupHelperTest.ShadowUserHandle.class})
+public final class BatteryBackupHelperTest {
+
+ private Context mContext;
+ private BatteryBackupHelper mBatteryBackupHelper;
+
+ @Mock
+ private BackupDataOutput mBackupDataOutput;
+ @Mock
+ private IDeviceIdleController mDeviceController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ mBatteryBackupHelper = new BatteryBackupHelper(mContext);
+ mBatteryBackupHelper.mIDeviceIdleController = mDeviceController;
+ }
+
+ @After
+ public void resetShadows() {
+ ShadowUserHandle.reset();
+ }
+
+ @Test
+ public void performBackup_nullPowerList_notBackupPowerList() throws Exception {
+ doReturn(null).when(mDeviceController).getFullPowerWhitelist();
+ mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
+
+ verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt());
+ }
+
+ @Test
+ public void performBackup_emptyPowerList_notBackupPowerList() throws Exception {
+ doReturn(new String[0]).when(mDeviceController).getFullPowerWhitelist();
+ mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
+
+ verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt());
+ }
+
+ @Test
+ public void performBackup_remoteException_notBackupPowerList() throws Exception {
+ doThrow(new RemoteException()).when(mDeviceController).getFullPowerWhitelist();
+ mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
+
+ verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt());
+ }
+
+ @Test
+ public void performBackup_oneFullPowerListElement_backupFullPowerListData()
+ throws Exception {
+ final String[] fullPowerList = {"com.android.package"};
+ doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
+
+ mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
+
+ final byte[] expectedBytes = fullPowerList[0].getBytes();
+ verify(mBackupDataOutput).writeEntityHeader(
+ BatteryBackupHelper.KEY_FULL_POWER_LIST, expectedBytes.length);
+ verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
+ }
+
+ @Test
+ public void performBackup_backupFullPowerListData() throws Exception {
+ final String[] fullPowerList = {"com.android.package1", "com.android.package2"};
+ doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
+
+ mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
+
+ final String expectedResult = fullPowerList[0]
+ + BatteryBackupHelper.DELIMITER + fullPowerList[1];
+ final byte[] expectedBytes = expectedResult.getBytes();
+ verify(mBackupDataOutput).writeEntityHeader(
+ BatteryBackupHelper.KEY_FULL_POWER_LIST, expectedBytes.length);
+ verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
+ }
+
+ @Test
+ public void performBackup_nonOwner_ignoreAllBackupAction() throws Exception {
+ ShadowUserHandle.setUid(1);
+ final String[] fullPowerList = {"com.android.package"};
+ doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
+
+ mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
+
+ verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt());
+ }
+
+ @Implements(UserHandle.class)
+ public static class ShadowUserHandle {
+ // Sets the default as thte OWNER role.
+ private static int sUid = 0;
+
+ public static void setUid(int uid) {
+ sUid = uid;
+ }
+
+ @Implementation
+ public static int myUserId() {
+ return sUid;
+ }
+
+ @Resetter
+ public static void reset() {
+ sUid = 0;
+ }
+ }
+}