1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.wallpaperbackup;
18 
19 import static android.app.WallpaperManager.FLAG_LOCK;
20 import static android.app.WallpaperManager.FLAG_SYSTEM;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.mockito.ArgumentMatchers.anyInt;
25 import static org.mockito.ArgumentMatchers.anyString;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.Mockito.doNothing;
28 import static org.mockito.Mockito.inOrder;
29 import static org.mockito.Mockito.never;
30 import static org.mockito.Mockito.times;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.app.WallpaperManager;
35 import android.app.backup.FullBackupDataOutput;
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.content.SharedPreferences;
39 import android.os.UserHandle;
40 
41 import androidx.test.core.app.ApplicationProvider;
42 import androidx.test.runner.AndroidJUnit4;
43 
44 import com.android.internal.content.PackageMonitor;
45 import com.android.wallpaperbackup.WallpaperBackupAgent;
46 import com.android.wallpaperbackup.utils.ContextWithServiceOverrides;
47 
48 import org.junit.Before;
49 import org.junit.Rule;
50 import org.junit.Test;
51 import org.junit.rules.TemporaryFolder;
52 import org.junit.runner.RunWith;
53 import org.mockito.InOrder;
54 import org.mockito.Mock;
55 import org.mockito.MockitoAnnotations;
56 
57 import java.io.File;
58 import java.io.IOException;
59 import java.util.ArrayList;
60 import java.util.List;
61 
62 @RunWith(AndroidJUnit4.class)
63 public class WallpaperBackupAgentTest {
64     private static final String SYSTEM_GENERATION = "system_gen";
65     private static final String LOCK_GENERATION = "lock_gen";
66     private static final String TEST_WALLPAPER_PACKAGE = "wallpaper_package";
67 
68     private static final int TEST_SYSTEM_WALLPAPER_ID = 1;
69     private static final int TEST_LOCK_WALLPAPER_ID = 2;
70 
71     @Mock private FullBackupDataOutput mOutput;
72     @Mock private WallpaperManager mWallpaperManager;
73     @Mock private SharedPreferences mSharedPreferences;
74     @Mock private SharedPreferences.Editor mSharedPreferenceEditor;
75     @Mock private Context mMockContext;
76 
77     @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
78 
79     private ContextWithServiceOverrides mContext;
80     private IsolatedWallpaperBackupAgent mWallpaperBackupAgent;
81     private ComponentName mWallpaperComponent;
82 
83     @Before
setUp()84     public void setUp() {
85         MockitoAnnotations.initMocks(this);
86 
87         when(mSharedPreferences.edit()).thenReturn(mSharedPreferenceEditor);
88         when(mSharedPreferenceEditor.putInt(anyString(), anyInt()))
89                 .thenReturn(mSharedPreferenceEditor);
90         doNothing().when(mSharedPreferenceEditor).apply();
91 
92         mContext = new ContextWithServiceOverrides(ApplicationProvider.getApplicationContext());
93         mContext.injectSystemService(WallpaperManager.class, mWallpaperManager);
94         mContext.setSharedPreferencesOverride(mSharedPreferences);
95 
96         mWallpaperBackupAgent = new IsolatedWallpaperBackupAgent(mTemporaryFolder.getRoot());
97         mWallpaperBackupAgent.attach(mContext);
98         mWallpaperBackupAgent.onCreate();
99 
100         mWallpaperComponent = new ComponentName(TEST_WALLPAPER_PACKAGE, "");
101     }
102 
103     @Test
testOnFullBackup_withNoChanges_onlyBacksUpEmptyFile()104     public void testOnFullBackup_withNoChanges_onlyBacksUpEmptyFile() throws IOException {
105         mockBackedUpState();
106         mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
107 
108         mWallpaperBackupAgent.onFullBackup(mOutput);
109 
110         assertThat(mWallpaperBackupAgent.mBackedUpFiles.size()).isEqualTo(1);
111         assertThat(mWallpaperBackupAgent.mBackedUpFiles.get(0).getName()).isEqualTo("empty");
112     }
113 
114     @Test
testOnFullBackup_withOnlyChangedSystem_updatesTheSharedPreferences()115     public void testOnFullBackup_withOnlyChangedSystem_updatesTheSharedPreferences()
116             throws IOException {
117         mockSystemWallpaperReadyToBackUp();
118         mockUnbackedUpState();
119         mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
120 
121         mWallpaperBackupAgent.onFullBackup(mOutput);
122 
123         verify(mSharedPreferenceEditor).putInt(eq(SYSTEM_GENERATION), eq(TEST_SYSTEM_WALLPAPER_ID));
124     }
125 
126     @Test
testOnFullBackup_withLockChangedToMatchSystem_updatesTheSharedPreferences()127     public void testOnFullBackup_withLockChangedToMatchSystem_updatesTheSharedPreferences()
128             throws IOException {
129         mockBackedUpState();
130         mockSystemWallpaperReadyToBackUp();
131         mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, -1);
132 
133         mWallpaperBackupAgent.onFullBackup(mOutput);
134 
135         InOrder inOrder = inOrder(mSharedPreferenceEditor);
136         inOrder.verify(mSharedPreferenceEditor)
137                 .putInt(eq(SYSTEM_GENERATION), eq(TEST_SYSTEM_WALLPAPER_ID));
138         inOrder.verify(mSharedPreferenceEditor).apply();
139         inOrder.verify(mSharedPreferenceEditor).putInt(eq(LOCK_GENERATION), eq(-1));
140         inOrder.verify(mSharedPreferenceEditor).apply();
141     }
142 
143     @Test
updateWallpaperComponent_doesApplyLater()144     public void updateWallpaperComponent_doesApplyLater() throws IOException {
145         mWallpaperBackupAgent.mIsDeviceInRestore = true;
146 
147         mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
148                 /* applyToLock */ true);
149 
150         // Imitate wallpaper component installation.
151         mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
152                 /* uid */0);
153 
154         verify(mWallpaperManager, times(1)).setWallpaperComponent(mWallpaperComponent);
155         verify(mWallpaperManager, times(1)).clear(eq(FLAG_LOCK));
156     }
157 
158     @Test
updateWallpaperComponent_applyToLockFalse_doesApplyLaterOnlyToMainScreen()159     public void updateWallpaperComponent_applyToLockFalse_doesApplyLaterOnlyToMainScreen()
160             throws IOException {
161         mWallpaperBackupAgent.mIsDeviceInRestore = true;
162 
163         mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
164                 /* applyToLock */ false);
165 
166         // Imitate wallpaper component installation.
167         mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
168                 /* uid */0);
169 
170         verify(mWallpaperManager, times(1)).setWallpaperComponent(mWallpaperComponent);
171         verify(mWallpaperManager, never()).clear(eq(FLAG_LOCK));
172     }
173 
174     @Test
updateWallpaperComponent_deviceNotInRestore_doesNotApply()175     public void updateWallpaperComponent_deviceNotInRestore_doesNotApply()
176             throws IOException {
177         mWallpaperBackupAgent.mIsDeviceInRestore = false;
178 
179         mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
180                 /* applyToLock */ true);
181 
182         // Imitate wallpaper component installation.
183         mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE,
184                 /* uid */0);
185 
186         verify(mWallpaperManager, never()).setWallpaperComponent(mWallpaperComponent);
187         verify(mWallpaperManager, never()).clear(eq(FLAG_LOCK));
188     }
189 
190     @Test
updateWallpaperComponent_differentPackageInstalled_doesNotApply()191     public void updateWallpaperComponent_differentPackageInstalled_doesNotApply()
192             throws IOException {
193         mWallpaperBackupAgent.mIsDeviceInRestore = false;
194 
195         mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent,
196                 /* applyToLock */ true);
197 
198         // Imitate "wrong" wallpaper component installation.
199         mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(/* packageName */"",
200                 /* uid */0);
201 
202         verify(mWallpaperManager, never()).setWallpaperComponent(mWallpaperComponent);
203         verify(mWallpaperManager, never()).clear(eq(FLAG_LOCK));
204     }
205 
mockUnbackedUpState()206     private void mockUnbackedUpState() {
207         mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
208         when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(-1);
209         when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(-1);
210     }
211 
mockBackedUpState()212     private void mockBackedUpState() {
213         when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1)))
214                 .thenReturn(TEST_SYSTEM_WALLPAPER_ID);
215         when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1)))
216                 .thenReturn(TEST_LOCK_WALLPAPER_ID);
217     }
218 
mockCurrentWallpapers(int systemWallpaperId, int lockWallpaperId)219     private void mockCurrentWallpapers(int systemWallpaperId, int lockWallpaperId) {
220         when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM)))
221                 .thenReturn(systemWallpaperId);
222         when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM)))
223                 .thenReturn(lockWallpaperId);
224         when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_SYSTEM))).thenReturn(true);
225         when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_LOCK))).thenReturn(true);
226     }
227 
mockSystemWallpaperReadyToBackUp()228     private void mockSystemWallpaperReadyToBackUp() throws IOException {
229         // Create a system wallpaper file
230         mTemporaryFolder.newFile("wallpaper_orig");
231         // Create staging file to simulate he wallpaper being ready to back up
232         new File(mContext.getFilesDir(), "wallpaper-stage").createNewFile();
233     }
234 
235     private class IsolatedWallpaperBackupAgent extends WallpaperBackupAgent {
236         File mWallpaperBaseDirectory;
237         List<File> mBackedUpFiles = new ArrayList<>();
238         PackageMonitor mWallpaperPackageMonitor;
239         boolean mIsDeviceInRestore = false;
240 
IsolatedWallpaperBackupAgent(File wallpaperBaseDirectory)241         IsolatedWallpaperBackupAgent(File wallpaperBaseDirectory) {
242             mWallpaperBaseDirectory = wallpaperBaseDirectory;
243         }
244 
245         @Override
getWallpaperDir()246         protected File getWallpaperDir() {
247             return mWallpaperBaseDirectory;
248         }
249 
250         @Override
backupFile(File file, FullBackupDataOutput data)251         protected void backupFile(File file, FullBackupDataOutput data) {
252             mBackedUpFiles.add(file);
253         }
254 
255         @Override
getSharedPreferences(File file, int mode)256         public SharedPreferences getSharedPreferences(File file, int mode) {
257             return mSharedPreferences;
258         }
259 
260         @Override
servicePackageExists(ComponentName comp)261         boolean servicePackageExists(ComponentName comp) {
262             return false;
263         }
264 
265         @Override
isDeviceInRestore()266         boolean isDeviceInRestore() {
267             return mIsDeviceInRestore;
268         }
269 
270         @Override
getWallpaperPackageMonitor(ComponentName componentName, boolean applyToLock)271         PackageMonitor getWallpaperPackageMonitor(ComponentName componentName,
272                 boolean applyToLock) {
273             mWallpaperPackageMonitor = super.getWallpaperPackageMonitor(componentName, applyToLock);
274             return mWallpaperPackageMonitor;
275         }
276 
277         @Override
getBaseContext()278         public Context getBaseContext() {
279             return mMockContext;
280         }
281     }
282 }
283