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.overlaytest;
18 
19 import static java.util.concurrent.TimeUnit.SECONDS;
20 
21 import android.annotation.NonNull;
22 import android.content.Context;
23 import android.content.om.OverlayIdentifier;
24 import android.content.om.OverlayManager;
25 import android.content.om.OverlayManagerTransaction;
26 import android.os.UserHandle;
27 
28 import androidx.test.InstrumentationRegistry;
29 
30 import java.util.concurrent.Executor;
31 import java.util.concurrent.FutureTask;
32 
33 class LocalOverlayManager {
34     private static final long TIMEOUT = 30;
35 
toggleOverlaysAndWait(@onNull final OverlayIdentifier[] overlaysToEnable, @NonNull final OverlayIdentifier[] overlaysToDisable)36     public static void toggleOverlaysAndWait(@NonNull final OverlayIdentifier[] overlaysToEnable,
37             @NonNull final OverlayIdentifier[] overlaysToDisable) throws Exception {
38         final int userId = UserHandle.myUserId();
39         OverlayManagerTransaction.Builder builder = new OverlayManagerTransaction.Builder();
40         for (OverlayIdentifier pkg : overlaysToEnable) {
41             builder.setEnabled(pkg, true, userId);
42         }
43         for (OverlayIdentifier pkg : overlaysToDisable) {
44             builder.setEnabled(pkg, false, userId);
45         }
46         OverlayManagerTransaction transaction = builder.build();
47 
48         final Context ctx = InstrumentationRegistry.getTargetContext();
49         FutureTask<Boolean> task = new FutureTask<>(() -> {
50             while (true) {
51                 final String[] paths = ctx.getResources().getAssets().getApkPaths();
52                 if (arrayTailContainsOverlays(paths, overlaysToEnable)
53                         && arrayDoesNotContain(paths, overlaysToDisable)) {
54                     return true;
55                 }
56                 Thread.sleep(10);
57             }
58         });
59 
60         OverlayManager om = ctx.getSystemService(OverlayManager.class);
61         om.commit(transaction);
62 
63         Executor executor = (cmd) -> new Thread(cmd).start();
64         executor.execute(task);
65         task.get(TIMEOUT, SECONDS);
66     }
67 
arrayTailContainsOverlays(@onNull final String[] array, @NonNull final OverlayIdentifier[] overlays)68     private static boolean arrayTailContainsOverlays(@NonNull final String[] array,
69             @NonNull final OverlayIdentifier[] overlays) {
70         if (array.length < overlays.length) {
71             return false;
72         }
73         for (int i = 0; i < overlays.length; i++) {
74             String a = array[array.length - overlays.length + i];
75             OverlayIdentifier s = overlays[i];
76             if (!a.contains(s.getPackageName())) {
77                 return false;
78             }
79         }
80         return true;
81     }
82 
arrayDoesNotContain(@onNull final String[] array, @NonNull final OverlayIdentifier[] overlays)83     private static boolean arrayDoesNotContain(@NonNull final String[] array,
84             @NonNull final OverlayIdentifier[] overlays) {
85         for (OverlayIdentifier s : overlays) {
86             for (String a : array) {
87                 if (a.contains(s.getPackageName())) {
88                     return false;
89                 }
90             }
91         }
92         return true;
93     }
94 }
95