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.server.wm.jetpack;
18 
19 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
20 
21 import static com.android.window.flags.Flags.FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG;
22 
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assume.assumeFalse;
26 import static org.junit.Assume.assumeTrue;
27 
28 import android.app.ActivityTaskManager;
29 import android.content.Context;
30 import android.content.pm.PackageManager;
31 import android.hardware.display.DisplayManager;
32 import android.platform.test.annotations.Presubmit;
33 import android.platform.test.annotations.RequiresFlagsDisabled;
34 import android.platform.test.annotations.RequiresFlagsEnabled;
35 import android.platform.test.flag.junit.CheckFlagsRule;
36 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
37 import android.server.wm.jetpack.extensions.util.ExtensionsUtil;
38 import android.server.wm.jetpack.extensions.util.SidecarUtil;
39 import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
40 import android.view.Display;
41 import android.view.WindowManager;
42 
43 import androidx.annotation.NonNull;
44 import androidx.test.core.app.ApplicationProvider;
45 import androidx.test.ext.junit.runners.AndroidJUnit4;
46 import androidx.window.extensions.WindowExtensions;
47 import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
48 
49 import com.android.compatibility.common.util.ApiTest;
50 import com.android.compatibility.common.util.CddTest;
51 
52 import org.junit.Before;
53 import org.junit.Rule;
54 import org.junit.Test;
55 import org.junit.runner.RunWith;
56 
57 import java.util.Arrays;
58 
59 /**
60  * Tests for devices implementations include an Android-compatible display(s)
61  * that has a minimum screen dimension greater than or equal to
62  * {@link WindowManager#LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP} and support multi window.
63  * For more information, read
64  * <a href="https://source.android.com/docs/core/display/windowmanager-extensions">WindowManager
65  * Extensions</a>
66  *
67  * Build/Install/Run:
68  * atest CtsWindowManagerJetpackTestCases:SdkAvailabilityTest
69  */
70 @Presubmit
71 @RunWith(AndroidJUnit4.class)
72 @CddTest(requirements = {"3.8.14/C-5-1"})
73 public class SdkAvailabilityTest extends WindowManagerJetpackTestBase {
74 
75     @Rule
76     public final CheckFlagsRule mCheckFlagsRule =
77             DeviceFlagsValueProvider.createCheckFlagsRule();
78 
79     @Before
80     @Override
setUp()81     public void setUp() throws Exception {
82         super.setUp();
83         assumeFalse("Skip Watch for WM Jetpack/Extensions availability",
84                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
85         assumeTrue("Device's default display doesn't support multi window",
86                 ActivityTaskManager.supportsMultiWindow(mContext));
87     }
88 
89     /**
90      * MUST implement the latest available stable version of the extensions API
91      * to be used by Window Manager Jetpack library, and declares the window extension
92      * is enabled.
93      */
94     @RequiresFlagsDisabled(FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG)
95     @ApiTest(apis = {
96             "androidx.window.extensions.WindowExtensionsProvider#getWindowExtensions",
97             "androidx.window.extensions.WindowExtensions#getVendorApiLevel",
98             "android.view.WindowManager#hasWindowExtensionsEnabled"
99     })
100     @Test
testWindowExtensionsAvailability()101     public void testWindowExtensionsAvailability() {
102         assumeHasLargeScreenDisplayOrExtensionEnabled();
103         assertTrue("WindowExtension version is not latest",
104                 ExtensionsUtil.isExtensionVersionLatest());
105         assertTrue("Device must declared that the WindowExtension is enabled",
106                 WindowManager.hasWindowExtensionsEnabled());
107     }
108 
109     /**
110      * MUST implement the latest available stable version of the extensions API
111      * to be used by Window Manager Jetpack library, and declares the window extension
112      * is enabled.
113      */
114     @RequiresFlagsEnabled(FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG)
115     @ApiTest(apis = {
116             "androidx.window.extensions.WindowExtensionsProvider#getWindowExtensions",
117             "androidx.window.extensions.WindowExtensions#getVendorApiLevel",
118             "android.view.WindowManager#hasWindowExtensionsEnabled"
119     })
120     @Test
testWindowExtensionsOnAllDevices()121     public void testWindowExtensionsOnAllDevices() {
122         assertTrue("WindowExtension version is not latest",
123                 ExtensionsUtil.isExtensionVersionLatest());
124         assertTrue("Device must declared that the WindowExtension is enabled",
125                 WindowManager.hasWindowExtensionsEnabled());
126     }
127 
128     /**
129      * MUST support Activity Embedding APIs and make ActivityEmbeddingComponent available via
130      * WindowExtensions interface.
131      */
132     @RequiresFlagsDisabled(FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG)
133     @ApiTest(apis = {"androidx.window.extensions.WindowExtensions#getActivityEmbeddingComponent"})
134     @Test
testActivityEmbeddingAvailability()135     public void testActivityEmbeddingAvailability() {
136         assumeHasLargeScreenDisplay();
137         WindowExtensions windowExtensions = ExtensionsUtil.getWindowExtensions();
138         assertNotNull("WindowExtensions is not available", windowExtensions);
139         ActivityEmbeddingComponent activityEmbeddingComponent =
140                 windowExtensions.getActivityEmbeddingComponent();
141         assertNotNull("ActivityEmbeddingComponent is not available", activityEmbeddingComponent);
142     }
143 
144     /**
145      * MUST support Activity Embedding APIs and make ActivityEmbeddingComponent available via
146      * WindowExtensions interface.
147      */
148     @RequiresFlagsEnabled(FLAG_ENABLE_WM_EXTENSIONS_FOR_ALL_FLAG)
149     @ApiTest(apis = {"androidx.window.extensions.WindowExtensions#getActivityEmbeddingComponent"})
150     @Test
testActivityEmbeddingOnAllDevices()151     public void testActivityEmbeddingOnAllDevices() {
152         final WindowExtensions windowExtensions = ExtensionsUtil.getWindowExtensions();
153         assertNotNull("WindowExtensions is not available", windowExtensions);
154         final ActivityEmbeddingComponent activityEmbeddingComponent =
155                 windowExtensions.getActivityEmbeddingComponent();
156         assertNotNull("ActivityEmbeddingComponent is not available", activityEmbeddingComponent);
157     }
158 
159     /**
160      * MUST also implement the stable version of sidecar API for compatibility with older
161      * applications.
162      */
163     @ApiTest(apis = {"androidx.window.sidecar.SidecarProvider#getApiVersion"})
164     @Test
testSidecarAvailability()165     public void testSidecarAvailability() {
166         assumeHasLargeScreenDisplayOrExtensionEnabled();
167         assertTrue("Sidecar is not available", SidecarUtil.isSidecarVersionValid());
168     }
169 
hasLargeScreenDisplay()170     private boolean hasLargeScreenDisplay() {
171         final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
172         return Arrays.stream(displayManager.getDisplays())
173                 .filter(display -> display.getType() == Display.TYPE_INTERNAL)
174                 .anyMatch(this::isLargeScreenDisplay);
175     }
176 
assumeHasLargeScreenDisplay()177     private void assumeHasLargeScreenDisplay() {
178         assumeTrue("Device does not has a minimum screen dimension greater than or equal to "
179                         + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP + "dp",
180                 hasLargeScreenDisplay());
181     }
182 
assumeHasLargeScreenDisplayOrExtensionEnabled()183     private void assumeHasLargeScreenDisplayOrExtensionEnabled() {
184         assumeTrue("Device does not has a minimum screen dimension greater than or equal to "
185                         + WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP + "dp and window "
186                         + "extensions are not enabled.",
187                 hasLargeScreenDisplay() || WindowManager.hasWindowExtensionsEnabled());
188     }
189 
isLargeScreenDisplay(@onNull Display display)190     private boolean isLargeScreenDisplay(@NonNull Display display) {
191         // Use WindowContext with type application overlay to prevent the metrics overridden by
192         // activity bounds. Note that process configuration may still be overridden by
193         // foreground Activity.
194         final Context appContext = ApplicationProvider.getApplicationContext();
195         final Context windowContext = appContext.createWindowContext(display,
196                 TYPE_APPLICATION_OVERLAY, null /* options */);
197         return windowContext.getResources().getConfiguration().smallestScreenWidthDp
198                 >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
199     }
200 }
201