• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 android.app.cts.wallpapers;
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 android.app.WallpaperManager;
25 import android.content.ComponentName;
26 import android.util.Log;
27 
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.stream.Stream;
32 
33 public class WallpaperManagerTestUtils {
34 
35     private static final String TAG = "WallpaperManagerTest";
36 
37     public static final ComponentName TEST_LIVE_WALLPAPER_COMPONENT = new ComponentName(
38             TestLiveWallpaper.class.getPackageName(),
39             TestLiveWallpaper.class.getName());
40 
41     public static final ComponentName TEST_LIVE_WALLPAPER_NO_UNFOLD_COMPONENT = new ComponentName(
42             TestLiveWallpaperNoUnfoldTransition.class.getPackageName(),
43             TestLiveWallpaperNoUnfoldTransition.class.getName());
44 
45     public static final ComponentName TEST_LIVE_WALLPAPER_AMBIENT_COMPONENT = new ComponentName(
46             TestLiveWallpaperSupportingAmbientMode.class.getPackageName(),
47             TestLiveWallpaperSupportingAmbientMode.class.getName());
48 
49     /**
50      * enumeration of all wallpapers used for test purposes: 3 static, 3 live wallpapers:   <br>
51      * static1 <=> red bitmap <br>
52      * static2 <=> green bitmap <br>
53      * static3 <=> blue bitmap <br>
54      * <br>
55      * live1 <=> TestLiveWallpaper (cyan) <br>
56      * live2 <=> TestLiveWallpaperNoUnfoldTransition (magenta) <br>
57      * live3 <=> TestLiveWallpaperSupportingAmbientMode (yellow) <br>
58      */
59     public enum TestWallpaper {
60         STATIC1(R.drawable.icon_red, null),
61         STATIC2(R.drawable.icon_green, null),
62         STATIC3(R.drawable.icon_blue, null),
63         LIVE1(null, TEST_LIVE_WALLPAPER_COMPONENT),
64         LIVE2(null, TEST_LIVE_WALLPAPER_NO_UNFOLD_COMPONENT),
65         LIVE3(null, TEST_LIVE_WALLPAPER_AMBIENT_COMPONENT);
66 
67         private final Integer mBitmapResourceId;
68         private final ComponentName mComponentName;
69 
TestWallpaper(Integer bitmapResourceId, ComponentName componentName)70         TestWallpaper(Integer bitmapResourceId, ComponentName componentName) {
71             mBitmapResourceId = bitmapResourceId;
72             mComponentName = componentName;
73         }
74 
getBitmapResourceId()75         int getBitmapResourceId() {
76             return mBitmapResourceId;
77         }
78 
getComponentName()79         ComponentName getComponentName() {
80             return mComponentName;
81         }
82 
type()83         private String type() {
84             return isStatic() ? "static" : "live";
85         }
86 
isStatic()87         private boolean isStatic() {
88             return mComponentName == null;
89         }
90 
isLive()91         private boolean isLive() {
92             return !isStatic();
93         }
94     }
95 
allStaticTestWallpapers()96     private static List<TestWallpaper> allStaticTestWallpapers() {
97         return List.of(TestWallpaper.STATIC1, TestWallpaper.STATIC2, TestWallpaper.STATIC3);
98     }
99 
allLiveTestWallpapers()100     private static List<TestWallpaper> allLiveTestWallpapers() {
101         return List.of(TestWallpaper.LIVE1, TestWallpaper.LIVE2, TestWallpaper.LIVE3);
102     }
103 
104     public static class WallpaperChange {
105         TestWallpaper mWallpaper;
106         int mDestination;
WallpaperChange( TestWallpaper wallpaper, int destination)107         public WallpaperChange(
108                 TestWallpaper wallpaper, int destination) {
109             this.mWallpaper = wallpaper;
110             this.mDestination = destination;
111         }
112     }
113 
114     /**
115      * Class representing a state in which our WallpaperManager may be during our tests.
116      * A state is fully represented by the wallpaper that are present on home and lock screen.
117      */
118     public static class WallpaperState {
119         private final TestWallpaper mHomeWallpaper;
120         private final TestWallpaper mLockWallpaper;
121 
122         /**
123          * it is possible to have two copies of the same engine on home + lock screen,
124          * in which this flag would be false.
125          * True means that mHomeWallpaper == mLockWallpaper and there is only one active engine.
126          */
127         private final boolean mSingleEngine;
128 
WallpaperState( TestWallpaper homeWallpaper, TestWallpaper lockWallpaper, boolean singleEngine)129         public WallpaperState(
130                 TestWallpaper homeWallpaper, TestWallpaper lockWallpaper, boolean singleEngine) {
131             mHomeWallpaper = homeWallpaper;
132             mLockWallpaper = lockWallpaper;
133             assertThat(!singleEngine || (homeWallpaper == lockWallpaper)).isTrue();
134             mSingleEngine = singleEngine;
135         }
136 
pickUnused(List<TestWallpaper> choices)137         private TestWallpaper pickUnused(List<TestWallpaper> choices) {
138             return choices.stream()
139                     .filter(wallpaper -> wallpaper != mHomeWallpaper && wallpaper != mLockWallpaper)
140                     .findFirst().orElseThrow();
141         }
142 
pickUnusedStatic()143         private TestWallpaper pickUnusedStatic() {
144             return pickUnused(allStaticTestWallpapers());
145         }
146 
pickUnusedLive()147         private TestWallpaper pickUnusedLive() {
148             return pickUnused(allLiveTestWallpapers());
149         }
150 
151         /**
152          * Enumerate all the possible logically different {@link WallpaperChange} changes from
153          * this state. <br>
154          * Two changes are considered logically different if their destination is different,
155          * or if their wallpaper type (static or live) is different.
156          */
allPossibleChanges()157         public List<WallpaperChange> allPossibleChanges() {
158             TestWallpaper unusedStatic = pickUnusedStatic();
159             TestWallpaper unusedLive = pickUnusedLive();
160 
161             // one can always add a new wallpaper, either static or live, at any destination
162             List<WallpaperChange> result = new ArrayList<>(Stream.of(unusedStatic, unusedLive)
163                     .flatMap(newWallpaper -> Stream
164                             .of(FLAG_LOCK, FLAG_SYSTEM, FLAG_LOCK | FLAG_SYSTEM)
165                             .map(destination -> new WallpaperChange(newWallpaper, destination)))
166                     .toList());
167 
168             // if we have a lock & home single engine, we can separate it
169             if (mSingleEngine) {
170                 result.addAll(List.of(
171                         new WallpaperChange(mHomeWallpaper, FLAG_SYSTEM),
172                         new WallpaperChange(mHomeWallpaper, FLAG_LOCK)
173                 ));
174 
175                 // else if we have the same engine twice, we can merge it
176             } else if (mHomeWallpaper == mLockWallpaper) {
177                 result.add(new WallpaperChange(mHomeWallpaper, FLAG_SYSTEM | FLAG_LOCK));
178             }
179 
180             // if we have different engines on home / lock,
181             // we can set one of them at the other location or at both locations
182             if (mHomeWallpaper != mLockWallpaper) {
183                 result.addAll(List.of(
184                         new WallpaperChange(mHomeWallpaper, FLAG_LOCK | FLAG_SYSTEM),
185                         new WallpaperChange(mLockWallpaper, FLAG_LOCK | FLAG_SYSTEM),
186                         new WallpaperChange(mHomeWallpaper, FLAG_LOCK),
187                         new WallpaperChange(mLockWallpaper, FLAG_SYSTEM)
188                 ));
189             }
190             return result;
191         }
192 
193         /**
194          * Given a change, return the number of times we expect an engine.onCreate operation
195          * of a live wallpaper from this state
196          */
expectedNumberOfLiveWallpaperCreate(WallpaperChange change)197         public int expectedNumberOfLiveWallpaperCreate(WallpaperChange change) {
198 
199             if (change.mWallpaper.isStatic()) return 0;
200             switch (change.mDestination) {
201                 case FLAG_SYSTEM | FLAG_LOCK:
202                     return change.mWallpaper != mHomeWallpaper ? 1 : 0;
203                 case FLAG_SYSTEM:
204                     return mSingleEngine || (change.mWallpaper != mHomeWallpaper) ? 1 : 0;
205                 case FLAG_LOCK:
206                     return mSingleEngine || (change.mWallpaper != mLockWallpaper) ? 1 : 0;
207                 default:
208                     throw new IllegalArgumentException();
209             }
210         }
211 
212 
213         /**
214          * Given a change, return the number of times we expect an engine.onDestroy operation
215          * of a live wallpaper from this state
216          */
expectedNumberOfLiveWallpaperDestroy(WallpaperChange change)217         public int expectedNumberOfLiveWallpaperDestroy(WallpaperChange change) {
218 
219             if (mSingleEngine) {
220                 return mHomeWallpaper.isLive()
221                         && mHomeWallpaper != change.mWallpaper
222                         && change.mDestination == (FLAG_LOCK | FLAG_SYSTEM) ? 1 : 0;
223             }
224 
225             boolean changeSystem = (change.mDestination & FLAG_SYSTEM) != 0;
226             boolean changeLock = (change.mDestination & FLAG_LOCK) != 0;
227             boolean systemReplaced = changeSystem && change.mWallpaper != mHomeWallpaper;
228             boolean lockReplaced =
229                     changeLock && (change.mWallpaper != mLockWallpaper || changeSystem);
230 
231             int result = 0;
232             if (systemReplaced && mHomeWallpaper.isLive()) result += 1;
233             if (lockReplaced && mLockWallpaper.isLive()) result += 1;
234             return result;
235         }
236 
237         /**
238          * Describes how to reproduce a failure obtained from this state with the given change
239          */
reproduceDescription(WallpaperChange change)240         public String reproduceDescription(WallpaperChange change) {
241             return String.format("To reproduce, start with:\n%s\nand %s",
242                     description(), changeDescription(change));
243         }
244 
description()245         private String description() {
246             String homeType = mHomeWallpaper.type();
247             String lockType = mLockWallpaper.type();
248             return mLockWallpaper == mHomeWallpaper
249                     ? String.format(" - the same %s wallpaper on home & lock screen (%s)", homeType,
250                     mSingleEngine ? "sharing the same engine" : "each using its own engine")
251                     : String.format(" - a %s wallpaper on home screen\n"
252                                     + " - %s %s wallpaper on lock screen",
253                             homeType, homeType.equals(lockType) ? "another" : "a", lockType);
254         }
255 
changeDescription(WallpaperChange change)256         private String changeDescription(WallpaperChange change) {
257             String newWallpaperDescription =
258                     change.mWallpaper == mHomeWallpaper || change.mWallpaper == mLockWallpaper
259                             ? String.format("the same %s wallpaper as %s screen",
260                             change.mWallpaper.type(),
261                             change.mWallpaper == mHomeWallpaper ? "home" : "lock")
262                             : String.format("a different %s wallpaper", change.mWallpaper.type());
263 
264             String destinationDescription =
265                     change.mDestination == FLAG_SYSTEM ? "home screen only"
266                             : change.mDestination == FLAG_LOCK ? "lock screen only"
267                                     : "both home & lock screens";
268 
269             String methodUsed = change.mWallpaper.isLive()
270                     ? "setWallpaperComponentWithFlags" : "setResource";
271 
272             String flagDescription =
273                     change.mDestination == FLAG_SYSTEM ? "FLAG_SYSTEM"
274                             : change.mDestination == FLAG_LOCK ? "FLAG_LOCK"
275                                     : "FLAG_SYSTEM|FLAG_LOCK";
276 
277             return String.format("apply %s on %s (via WallpaperManager#%s(..., %s))",
278                     newWallpaperDescription, destinationDescription, methodUsed, flagDescription);
279         }
280     }
281 
282     /**
283      * Uses the provided wallpaperManager instance to perform a {@link WallpaperChange}.
284      */
performChange( WallpaperManager wallpaperManager, WallpaperChange change)285     public static void performChange(
286             WallpaperManager wallpaperManager, WallpaperChange change) throws IOException {
287         if (change.mWallpaper.isStatic()) {
288             wallpaperManager.setResource(
289                     change.mWallpaper.getBitmapResourceId(), change.mDestination);
290         } else {
291             wallpaperManager.setWallpaperComponentWithFlags(
292                     change.mWallpaper.getComponentName(), change.mDestination);
293         }
294         try {
295             // Allow time for callbacks
296             Thread.sleep(500);
297         } catch (InterruptedException e) {
298             Log.e(TAG, "wallpaper wait interrupted", e);
299         }
300     }
301 
302     /**
303      * Sets a wallpaperManager in some state. Always proceeds the same way: <br>
304      *   - put the home wallpaper on lock and home screens <br>
305      *   - put the lock wallpaper on lock screen, if it is different from the home screen wallpaper
306      */
goToState(WallpaperManager wallpaperManager, WallpaperState state)307     public static void goToState(WallpaperManager wallpaperManager, WallpaperState state)
308             throws IOException {
309         WallpaperChange change1 = new WallpaperChange(
310                 state.mHomeWallpaper, FLAG_SYSTEM | FLAG_LOCK);
311         performChange(wallpaperManager, change1);
312 
313         WallpaperChange change2 = new WallpaperChange(state.mLockWallpaper, FLAG_LOCK);
314         if (!state.mSingleEngine) performChange(wallpaperManager, change2);
315     }
316 
317     /**
318      * Return a list of all logically different states
319      * Two states are logically different if at least one of this statement: <br>
320      *   - home screen is live <br>
321      *   - lock screen is live <br>
322      *   - home screen and lock screen are the same wallpaper <br>
323      *   - home screen and lock screen share the same engine <br>
324      *  is different between the two states.
325      */
allPossibleStates()326     public static List<WallpaperState> allPossibleStates() {
327         return List.of(
328                 new WallpaperState(TestWallpaper.LIVE1, TestWallpaper.LIVE1, true),
329                 new WallpaperState(TestWallpaper.LIVE1, TestWallpaper.LIVE1, false),
330                 new WallpaperState(TestWallpaper.LIVE1, TestWallpaper.LIVE2, false),
331                 new WallpaperState(TestWallpaper.LIVE1, TestWallpaper.STATIC1, false),
332                 new WallpaperState(TestWallpaper.STATIC1, TestWallpaper.STATIC1, true),
333                 new WallpaperState(TestWallpaper.STATIC1, TestWallpaper.STATIC1, false),
334                 new WallpaperState(TestWallpaper.STATIC1, TestWallpaper.STATIC2, false),
335                 new WallpaperState(TestWallpaper.STATIC1, TestWallpaper.LIVE1, false)
336         );
337     }
338 
339     public static final WallpaperState TWO_DIFFERENT_LIVE_WALLPAPERS = new WallpaperState(
340             TestWallpaper.LIVE1, TestWallpaper.LIVE3, false);
341 
342     public static final WallpaperState TWO_SAME_LIVE_WALLPAPERS = new WallpaperState(
343             TestWallpaper.LIVE2, TestWallpaper.LIVE2, true);
344 }
345