diff options
6 files changed, 289 insertions, 5 deletions
diff --git a/packages/WallpaperBackup/Android.bp b/packages/WallpaperBackup/Android.bp index 56020cd573b1..748eb40cb8b8 100644 --- a/packages/WallpaperBackup/Android.bp +++ b/packages/WallpaperBackup/Android.bp @@ -24,3 +24,27 @@ android_app { certificate: "platform", privileged: false, } + +android_test { + name: "WallpaperBackupAgentTests", + manifest: "test/AndroidManifest.xml", + test_config: "test/AndroidTest.xml", + srcs: [ + // Include the app source code because the app runs as the system user on-device. + "src/**/*.java", + "test/src/**/*.java" + ], + libs: [ + "android.test.base", + "android.test.runner", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.rules", + "mockito-target-minus-junit4", + "truth-prebuilt", + ], + certificate: "platform", + platform_apis: true, + test_suites: ["device-tests"] +} diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java index da9018996fe7..1c2c640daa7b 100644 --- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java +++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java @@ -39,6 +39,8 @@ import android.os.UserHandle; import android.util.Slog; import android.util.Xml; +import com.android.internal.annotations.VisibleForTesting; + import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; @@ -89,7 +91,7 @@ public class WallpaperBackupAgent extends BackupAgent { Slog.v(TAG, "onCreate()"); } - File wallpaperDir = Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM); + File wallpaperDir = getWallpaperDir(); mWallpaperInfo = new File(wallpaperDir, WALLPAPER_INFO); mWallpaperFile = new File(wallpaperDir, WALLPAPER); mLockWallpaperFile = new File(wallpaperDir, WALLPAPER_LOCK); @@ -102,6 +104,11 @@ public class WallpaperBackupAgent extends BackupAgent { } } + @VisibleForTesting + protected File getWallpaperDir() { + return Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM); + } + @Override public void onFullBackup(FullBackupDataOutput data) throws IOException { // To avoid data duplication and disk churn, use links as the stage. @@ -119,7 +126,7 @@ public class WallpaperBackupAgent extends BackupAgent { FileOutputStream touch = new FileOutputStream(empty); touch.close(); } - fullBackupFile(empty, data); + backupFile(empty, data); SharedPreferences prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); final int lastSysGeneration = prefs.getInt(SYSTEM_GENERATION, -1); @@ -155,7 +162,7 @@ public class WallpaperBackupAgent extends BackupAgent { FileUtils.copyFileOrThrow(mWallpaperInfo, infoStage); } if (DEBUG) Slog.v(TAG, "Storing wallpaper metadata"); - fullBackupFile(infoStage, data); + backupFile(infoStage, data); } if (sysEligible && mWallpaperFile.exists()) { if (sysChanged || !imageStage.exists()) { @@ -163,7 +170,7 @@ public class WallpaperBackupAgent extends BackupAgent { FileUtils.copyFileOrThrow(mWallpaperFile, imageStage); } if (DEBUG) Slog.v(TAG, "Storing system wallpaper image"); - fullBackupFile(imageStage, data); + backupFile(imageStage, data); prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply(); } @@ -174,7 +181,7 @@ public class WallpaperBackupAgent extends BackupAgent { FileUtils.copyFileOrThrow(mLockWallpaperFile, lockImageStage); } if (DEBUG) Slog.v(TAG, "Storing lock wallpaper image"); - fullBackupFile(lockImageStage, data); + backupFile(lockImageStage, data); prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply(); } } catch (Exception e) { @@ -189,6 +196,12 @@ public class WallpaperBackupAgent extends BackupAgent { } } + @VisibleForTesting + // fullBackupFile is final, so we intercept backups here in tests. + protected void backupFile(File file, FullBackupDataOutput data) { + fullBackupFile(file, data); + } + @Override public void onQuotaExceeded(long backupDataBytes, long quotaBytes) { if (DEBUG) { diff --git a/packages/WallpaperBackup/test/AndroidManifest.xml b/packages/WallpaperBackup/test/AndroidManifest.xml new file mode 100644 index 000000000000..44ab1b6d65ba --- /dev/null +++ b/packages/WallpaperBackup/test/AndroidManifest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.wallpaperbackup.tests"> + + <application android:label="WallpaperBackup Tests"> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.wallpaperbackup.tests" + android:label="WallpaperBackup Tests"/> +</manifest> + diff --git a/packages/WallpaperBackup/test/AndroidTest.xml b/packages/WallpaperBackup/test/AndroidTest.xml new file mode 100644 index 000000000000..f2e77821e492 --- /dev/null +++ b/packages/WallpaperBackup/test/AndroidTest.xml @@ -0,0 +1,27 @@ +<!-- Copyright (C) 2019 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. +--> +<configuration description="Runs sample instrumentation test."> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="WallpaperBackupAgentTests.apk" /> + </target_preparer> + + <option name="test-suite-tag" value="apct" /> + <option name="test-tag" value="WallpaperBackupAgentTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.wallpaperbackup.tests" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration> diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java new file mode 100644 index 000000000000..46a7dfeed233 --- /dev/null +++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2019 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.wallpaperbackup.tests; + +import static android.app.WallpaperManager.FLAG_LOCK; +import static android.app.WallpaperManager.FLAG_SYSTEM; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.WallpaperManager; +import android.app.backup.FullBackupDataOutput; +import android.content.SharedPreferences; +import android.os.UserHandle; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.runner.AndroidJUnit4; + +import com.android.wallpaperbackup.WallpaperBackupAgent; +import com.android.wallpaperbackup.utils.ContextWithServiceOverrides; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public class WallpaperBackupAgentTest { + private static final String SYSTEM_GENERATION = "system_gen"; + private static final String LOCK_GENERATION = "lock_gen"; + + @Mock private FullBackupDataOutput mOutput; + @Mock private WallpaperManager mWallpaperManager; + @Mock private SharedPreferences mSharedPreferences; + + @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); + + private ContextWithServiceOverrides mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = new ContextWithServiceOverrides(ApplicationProvider.getApplicationContext()); + mContext.injectSystemService(WallpaperManager.class, mWallpaperManager); + mContext.setSharedPreferencesOverride(mSharedPreferences); + } + + @Test + public void testOnFullBackup_withNoChanges_onlyBacksUpEmptyFile() throws IOException { + WallpaperBackupAgent wallpaperBackupAgent = new WallpaperBackupAgent(); + initialiseAgent(wallpaperBackupAgent); + + when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM))) + .thenReturn(1); + when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM))) + .thenReturn(1); + when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(1); + when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(1); + + wallpaperBackupAgent.onFullBackup(mOutput); + + verify(mOutput); // Backup of empty file only + } + + @Test + public void testOnFullBackup_withOnlyChangedSystem_updatesTheSharedPreferences() + throws IOException { + // Create a system wallpaper file + mTemporaryFolder.newFile("wallpaper_orig"); + // Create stageing file to simulate he wallpaper being ready to back up + new File(mContext.getFilesDir(), "wallpaper-stage").createNewFile(); + + WallpaperBackupAgent wallpaperBackupAgent = + new IsolatedWallpaperBackupAgent(mTemporaryFolder.getRoot()); + initialiseAgent(wallpaperBackupAgent); + + SharedPreferences.Editor preferenceEditor = mock(SharedPreferences.Editor.class); + + when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM))) + .thenReturn(2); + when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM))) + .thenReturn(1); + when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_SYSTEM))).thenReturn(true); + when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_LOCK))).thenReturn(true); + when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(1); + when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(1); + when(mSharedPreferences.edit()).thenReturn(preferenceEditor); + when(preferenceEditor.putInt(eq(SYSTEM_GENERATION), eq(2))).thenReturn(preferenceEditor); + + wallpaperBackupAgent.onFullBackup(mOutput); + + verify(preferenceEditor).putInt(eq(SYSTEM_GENERATION), eq(2)); + } + + private void initialiseAgent(WallpaperBackupAgent agent) { + agent.attach(mContext); + agent.onCreate(); + } + + private static class IsolatedWallpaperBackupAgent extends WallpaperBackupAgent { + File mWallpaperBaseDirectory; + List<File> mBackedUpFiles = new ArrayList(); + + IsolatedWallpaperBackupAgent(File wallpaperBaseDirectory) { + mWallpaperBaseDirectory = wallpaperBaseDirectory; + } + + @Override + protected File getWallpaperDir() { + return mWallpaperBaseDirectory; + } + + @Override + protected void backupFile(File file, FullBackupDataOutput data) { + mBackedUpFiles.add(file); + } + } +} diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/ContextWithServiceOverrides.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/ContextWithServiceOverrides.java new file mode 100644 index 000000000000..df5d74acfcad --- /dev/null +++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/ContextWithServiceOverrides.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 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.wallpaperbackup.utils; + +import android.content.Context; +import android.content.ContextWrapper; +import android.content.SharedPreferences; + +import java.util.HashMap; +import java.util.Map; + +public class ContextWithServiceOverrides extends ContextWrapper { + private static final String TAG = "ContextWithOverrides"; + + private Map<String, Object> mInjectedSystemServices = new HashMap<>(); + private SharedPreferences mSharedPreferencesOverride; + + public ContextWithServiceOverrides(Context base) { + super(base); + } + + public <S> void injectSystemService(Class<S> cls, S service) { + final String name = getSystemServiceName(cls); + mInjectedSystemServices.put(name, service); + } + + @Override + public Context getApplicationContext() { + return this; + } + + @Override + public Object getSystemService(String name) { + if (mInjectedSystemServices.containsKey(name)) { + return mInjectedSystemServices.get(name); + } + return super.getSystemService(name); + } + + public void setSharedPreferencesOverride(SharedPreferences override) { + mSharedPreferencesOverride = override; + } + + @Override + public SharedPreferences getSharedPreferences(String name, int mode) { + return mSharedPreferencesOverride == null + ? super.getSharedPreferences(name, mode) + : mSharedPreferencesOverride; + } +} |