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.documentsui;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.times;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
26 
27 import android.app.Activity;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.om.OverlayInfo;
31 import android.content.om.OverlayManager;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.PackageManager;
34 import android.os.UserHandle;
35 
36 import androidx.core.util.Consumer;
37 import androidx.test.filters.SmallTest;
38 import androidx.test.platform.app.InstrumentationRegistry;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import com.android.documentsui.theme.ThemeOverlayManager;
42 
43 import com.google.common.collect.Lists;
44 
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 import org.mockito.Mock;
49 import org.mockito.MockitoAnnotations;
50 
51 import java.util.concurrent.CountDownLatch;
52 import java.util.concurrent.TimeUnit;
53 
54 @SmallTest
55 @RunWith(AndroidJUnit4.class)
56 public class ThemeOverlayManagerTest {
57     private static final String TEST_DISABLED_PREFIX = "com.example.";
58     private static final String TEST_ENABLED_PREFIX = "com.example.enabled.";
59     private static final String TEST_OVERLAY_PACKAGE = "test.overlay";
60     private static final String TEST_TARGET_PACKAGE = "test.target";
61 
62     @Mock
63     OverlayManager mOverlayManager;
64 
65     @Mock
66     PackageManager mPackageManager;
67 
68     Consumer<Boolean> mCallback;
69     Context mContext;
70     CountDownLatch mLatch;
71     ThemeOverlayManager mThemeOverlayManager;
72     UserHandle mUserHandle;
73 
74     @Before
setUp()75     public void setUp() throws Exception {
76         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
77                 "android.permission.CHANGE_OVERLAY_PACKAGES");
78 
79         MockitoAnnotations.initMocks(this);
80         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
81         mLatch = new CountDownLatch(1);
82         mUserHandle = UserHandle.of(UserHandle.myUserId());
83         mCallback = result -> mLatch.countDown();
84 
85         when(mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId(),
86                 mUserHandle)).thenReturn(Lists.newArrayList(
87                 createOverlayInfo(getOverlayPackageId(), getEnabledTargetPackageId(), true)));
88 
89         when(mOverlayManager.getOverlayInfosForTarget(getDisabledTargetPackageId(),
90                 mUserHandle)).thenReturn(Lists.newArrayList(
91                 createOverlayInfo(getOverlayPackageId(), getDisabledTargetPackageId(), false)));
92     }
93 
94     @Test
testApplyOverlays_shouldSetEnabled()95     public void testApplyOverlays_shouldSetEnabled() throws Exception {
96         final boolean enabled = true;
97 
98         mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
99                 getDisabledTargetPackageId());
100 
101         mThemeOverlayManager.applyOverlays(mContext, enabled, mCallback);
102         mLatch.await(5, TimeUnit.SECONDS);
103 
104         verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled,
105                 mUserHandle);
106     }
107 
108     @Test
testApplyOverlays_shouldGetOverlayInfo()109     public void testApplyOverlays_shouldGetOverlayInfo() throws Exception {
110         mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
111                 getEnabledTargetPackageId());
112 
113         mThemeOverlayManager.applyOverlays(mContext, true /* enabled */, mCallback);
114         mLatch.await(5, TimeUnit.SECONDS);
115 
116         verify(mOverlayManager, times(1)).getOverlayInfosForTarget(getEnabledTargetPackageId(),
117                 mUserHandle);
118     }
119 
120     @Test
testApplyOverlays_shouldCheckEnabled_beforeSetEnabled()121     public void testApplyOverlays_shouldCheckEnabled_beforeSetEnabled() {
122         final boolean enabled = true;
123 
124         mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
125                 getEnabledTargetPackageId());
126 
127         mThemeOverlayManager.applyOverlays(mContext, enabled, mCallback);
128 
129         verify(mOverlayManager, never()).setEnabled(getOverlayPackageId(), enabled,
130                 mUserHandle);
131     }
132 
133     @Test
testDefaultDisabled_applyOverlays_shouldEnabled()134     public void testDefaultDisabled_applyOverlays_shouldEnabled() throws Exception {
135         final boolean enabled = true;
136 
137         assertThat(mOverlayManager.getOverlayInfosForTarget(getDisabledTargetPackageId(),
138                 mUserHandle).get(0).isEnabled()).isEqualTo(!enabled);
139 
140         mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
141                 getDisabledTargetPackageId());
142 
143         mThemeOverlayManager.applyOverlays(mContext, enabled, mCallback);
144         mLatch.await(5, TimeUnit.SECONDS);
145 
146         verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled,
147                 mUserHandle);
148     }
149 
150     @Test
testDefaultEnabled_applyOverlays_shouldDisabled()151     public void testDefaultEnabled_applyOverlays_shouldDisabled() throws Exception {
152         final boolean enabled = false;
153 
154         assertThat(mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId(),
155                 mUserHandle).get(0).isEnabled()).isEqualTo(!enabled);
156 
157         mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
158                 getEnabledTargetPackageId());
159 
160         mThemeOverlayManager.applyOverlays(mContext, enabled, mCallback);
161         mLatch.await(5, TimeUnit.SECONDS);
162 
163         verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled,
164                 mUserHandle);
165     }
166 
167     @Test
testDefaultEnabled_launchDocumentsUI_shouldSuccess()168     public void testDefaultEnabled_launchDocumentsUI_shouldSuccess() throws Exception {
169         final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
170         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
171 
172         final Activity activity =
173                 InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
174 
175         assertThat(activity).isNotNull();
176 
177         if (activity != null) {
178             activity.finish();
179         }
180     }
181 
182     @Test
testGetValidOverlay_system_valid()183     public void testGetValidOverlay_system_valid() throws Exception {
184         mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
185                 getEnabledTargetPackageId());
186 
187         ApplicationInfo ai = mock(ApplicationInfo.class);
188         ai.flags |= ApplicationInfo.FLAG_SYSTEM;
189         when(mPackageManager.getApplicationInfo(getOverlayPackageId(), 0)).thenReturn(ai);
190 
191         assertThat(mThemeOverlayManager.getValidOverlay(mPackageManager)).isEqualTo(
192                 mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId(),
193                         mUserHandle).iterator().next());
194     }
195 
196     @Test
testGetValidOverlay_data_invalid()197     public void testGetValidOverlay_data_invalid() throws Exception {
198         mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager,
199                 getEnabledTargetPackageId());
200 
201         ApplicationInfo ai = mock(ApplicationInfo.class);
202         String path = "/data/app/DocumentUIOverlay/DocumentUIOverlay.apk";
203         ai.sourceDir = path;
204         when(mPackageManager.getApplicationInfo(getOverlayPackageId(), 0)).thenReturn(ai);
205 
206         assertThat(mThemeOverlayManager.getValidOverlay(mPackageManager)).isEqualTo(null);
207     }
208 
createOverlayInfo(String packageName, String targetPackageName, boolean enabled)209     private static OverlayInfo createOverlayInfo(String packageName, String targetPackageName,
210             boolean enabled) {
211         return new OverlayInfo(packageName, targetPackageName, null, null, "",
212                 enabled ? OverlayInfo.STATE_ENABLED : OverlayInfo.STATE_DISABLED, 0, 0, false);
213     }
214 
getDisabledTargetPackageId()215     private static String getDisabledTargetPackageId() {
216         return TEST_DISABLED_PREFIX + TEST_TARGET_PACKAGE;
217     }
218 
getEnabledTargetPackageId()219     private static String getEnabledTargetPackageId() {
220         return TEST_ENABLED_PREFIX + TEST_TARGET_PACKAGE;
221     }
222 
getOverlayPackageId()223     private static String getOverlayPackageId() {
224         return TEST_DISABLED_PREFIX + TEST_OVERLAY_PACKAGE;
225     }
226 
227 }
228