• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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;
18 
19 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
20 import static android.server.wm.UiDeviceUtils.dragPointer;
21 import static android.server.wm.dndsourceapp.Components.DRAG_SOURCE;
22 import static android.server.wm.dndtargetapp.Components.DROP_TARGET;
23 import static android.server.wm.dndtargetappsdk23.Components.DROP_TARGET_SDK23;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28 import static org.junit.Assume.assumeTrue;
29 
30 import android.content.ComponentName;
31 import android.graphics.Point;
32 import android.graphics.Rect;
33 import android.hardware.display.DisplayManager;
34 import android.os.SystemClock;
35 import android.platform.test.annotations.AppModeFull;
36 import android.platform.test.annotations.Presubmit;
37 import android.server.wm.ActivityManagerState.ActivityTask;
38 import android.util.Log;
39 import android.view.Display;
40 import java.util.Map;
41 import org.junit.After;
42 import org.junit.Before;
43 import org.junit.Test;
44 
45 /**
46  * Build/Install/Run:
47  *     atest CtsWindowManagerDeviceTestCases:CrossAppDragAndDropTests
48  */
49 @Presubmit
50 @AppModeFull(reason = "Requires android.permission.MANAGE_ACTIVITY_STACKS")
51 public class CrossAppDragAndDropTests extends ActivityManagerTestBase {
52     private static final String TAG = "CrossAppDragAndDrop";
53 
54     private static final int SWIPE_STEPS = 100;
55 
56     private static final String FILE_GLOBAL = "file_global";
57     private static final String FILE_LOCAL = "file_local";
58     private static final String DISALLOW_GLOBAL = "disallow_global";
59     private static final String CANCEL_SOON = "cancel_soon";
60     private static final String GRANT_NONE = "grant_none";
61     private static final String GRANT_READ = "grant_read";
62     private static final String GRANT_WRITE = "grant_write";
63     private static final String GRANT_READ_PREFIX = "grant_read_prefix";
64     private static final String GRANT_READ_NOPREFIX = "grant_read_noprefix";
65     private static final String GRANT_READ_PERSISTABLE = "grant_read_persistable";
66 
67     private static final String REQUEST_NONE = "request_none";
68     private static final String REQUEST_READ = "request_read";
69     private static final String REQUEST_READ_NESTED = "request_read_nested";
70     private static final String REQUEST_TAKE_PERSISTABLE = "request_take_persistable";
71     private static final String REQUEST_WRITE = "request_write";
72 
73     private static final String SOURCE_LOG_TAG = "DragSource";
74     private static final String TARGET_LOG_TAG = "DropTarget";
75 
76     private static final String RESULT_KEY_START_DRAG = "START_DRAG";
77     private static final String RESULT_KEY_DRAG_STARTED = "DRAG_STARTED";
78     private static final String RESULT_KEY_DRAG_ENDED = "DRAG_ENDED";
79     private static final String RESULT_KEY_EXTRAS = "EXTRAS";
80     private static final String RESULT_KEY_DROP_RESULT = "DROP";
81     private static final String RESULT_KEY_ACCESS_BEFORE = "BEFORE";
82     private static final String RESULT_KEY_ACCESS_AFTER = "AFTER";
83     private static final String RESULT_KEY_CLIP_DATA_ERROR = "CLIP_DATA_ERROR";
84     private static final String RESULT_KEY_CLIP_DESCR_ERROR = "CLIP_DESCR_ERROR";
85     private static final String RESULT_KEY_LOCAL_STATE_ERROR = "LOCAL_STATE_ERROR";
86 
87     private static final String RESULT_MISSING = "Missing";
88     private static final String RESULT_OK = "OK";
89     private static final String RESULT_EXCEPTION = "Exception";
90     private static final String RESULT_NULL_DROP_PERMISSIONS = "Null DragAndDropPermissions";
91 
92     private static final String EXTRA_MODE = "mode";
93     private static final String EXTRA_LOGTAG = "logtag";
94 
95     protected DisplayManager mDm;
96 
97     private Map<String, String> mSourceResults;
98     private Map<String, String> mTargetResults;
99 
100     private String mSessionId;
101     private String mSourceLogTag;
102     private String mTargetLogTag;
103 
104     @Before
105     @Override
setUp()106     public void setUp() throws Exception {
107         super.setUp();
108         assumeTrue(supportsSplitScreenMultiWindow() || supportsFreeform());
109 
110         // Use uptime in seconds as unique test invocation id.
111         mSessionId = Long.toString(SystemClock.uptimeMillis() / 1000);
112         mSourceLogTag = SOURCE_LOG_TAG + mSessionId;
113         mTargetLogTag = TARGET_LOG_TAG + mSessionId;
114 
115         mDm = mContext.getSystemService(DisplayManager.class);
116         cleanupState();
117     }
118 
119     @After
120     @Override
tearDown()121     public void tearDown() throws Exception {
122         super.tearDown();
123         cleanupState();
124     }
125 
126     /**
127      * Make sure that the special activity stacks are removed and the ActivityManager/WindowManager
128      * is in a good state.
129      */
cleanupState()130     private void cleanupState() throws Exception {
131         stopTestPackage(DRAG_SOURCE.getPackageName());
132         stopTestPackage(DROP_TARGET.getPackageName());
133         stopTestPackage(DROP_TARGET_SDK23.getPackageName());
134     }
135 
136     /**
137      * @param displaySize size of the display
138      * @param leftSide {@code true} to launch the app taking up the left half of the display,
139      *         {@code false} to launch the app taking up the right half of the display.
140      */
launchFreeformActivity(ComponentName componentName, String mode, String logtag, Point displaySize, boolean leftSide)141     private void launchFreeformActivity(ComponentName componentName, String mode,
142             String logtag, Point displaySize, boolean leftSide) throws Exception {
143         launchActivity(componentName, WINDOWING_MODE_FREEFORM, "mode", mode, "logtag", logtag);
144         Point topLeft = new Point(leftSide ? 0 : displaySize.x / 2, 0);
145         Point bottomRight = new Point(leftSide ? displaySize.x / 2 : displaySize.x, displaySize.y);
146         resizeActivityTask(componentName, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
147     }
148 
injectInput(Point from, Point to, int steps)149     private void injectInput(Point from, Point to, int steps) throws Exception {
150         dragPointer(from, to, steps);
151     }
152 
getDisplaySize()153     private Point getDisplaySize() throws Exception {
154         final Point displaySize = new Point();
155         mDm.getDisplay(Display.DEFAULT_DISPLAY).getRealSize(displaySize);
156         return displaySize;
157     }
158 
getWindowCenter(ComponentName name)159     private Point getWindowCenter(ComponentName name) throws Exception {
160         final ActivityTask sideTask = mAmWmState.getAmState().getTaskByActivity(name);
161         Rect bounds = sideTask.getBounds();
162         if (bounds != null) {
163             return new Point(bounds.centerX(), bounds.centerY());
164         }
165         return null;
166     }
167 
assertDropResult(String sourceMode, String targetMode, String expectedDropResult)168     private void assertDropResult(String sourceMode, String targetMode, String expectedDropResult)
169             throws Exception {
170         assertDragAndDropResults(DRAG_SOURCE, sourceMode, DROP_TARGET, targetMode,
171                 RESULT_OK, expectedDropResult, RESULT_OK);
172     }
173 
assertNoGlobalDragEvents(ComponentName sourceComponentName, String sourceMode, ComponentName targetComponentName, String expectedStartDragResult)174     private void assertNoGlobalDragEvents(ComponentName sourceComponentName, String sourceMode,
175             ComponentName targetComponentName, String expectedStartDragResult)
176             throws Exception {
177         assertDragAndDropResults(
178                 sourceComponentName, sourceMode, targetComponentName, REQUEST_NONE,
179                 expectedStartDragResult, RESULT_MISSING, RESULT_MISSING);
180     }
181 
assertDragAndDropResults(ComponentName sourceComponentName, String sourceMode, ComponentName targetComponentName, String targetMode, String expectedStartDragResult, String expectedDropResult, String expectedListenerResults)182     private void assertDragAndDropResults(ComponentName sourceComponentName, String sourceMode,
183             ComponentName targetComponentName, String targetMode,
184             String expectedStartDragResult, String expectedDropResult,
185             String expectedListenerResults) throws Exception {
186         Log.e(TAG, "session: " + mSessionId + ", source: " + sourceMode
187                 + ", target: " + targetMode);
188 
189         if (supportsFreeform()) {
190             // Fallback to try to launch two freeform windows side by side.
191             Point displaySize = getDisplaySize();
192             launchFreeformActivity(sourceComponentName, sourceMode, mSourceLogTag,
193                 displaySize, true /* leftSide */);
194             launchFreeformActivity(targetComponentName, targetMode, mTargetLogTag,
195                 displaySize, false /* leftSide */);
196         } else {
197             launchActivitiesInSplitScreen(getLaunchActivityBuilder()
198                     .setTargetActivity(sourceComponentName)
199                     .setIntentExtra(bundle -> {
200                         bundle.putString(EXTRA_MODE, sourceMode);
201                         bundle.putString(EXTRA_LOGTAG, mSourceLogTag);
202                     }),
203                     getLaunchActivityBuilder().setTargetActivity(targetComponentName)
204                     .setIntentExtra(bundle -> {
205                         bundle.putString(EXTRA_MODE, targetMode);
206                         bundle.putString(EXTRA_LOGTAG, mTargetLogTag);
207                     }));
208         }
209 
210         Point p1 = getWindowCenter(sourceComponentName);
211         assertNotNull(p1);
212         Point p2 = getWindowCenter(targetComponentName);
213         assertNotNull(p2);
214 
215         TestLogService.registerClient(mSourceLogTag, RESULT_KEY_START_DRAG);
216         TestLogService.registerClient(mTargetLogTag, RESULT_KEY_DRAG_ENDED);
217 
218         injectInput(p1, p2, SWIPE_STEPS);
219 
220         mSourceResults = TestLogService.getResultsForClient(mSourceLogTag, 1000);
221         assertSourceResult(RESULT_KEY_START_DRAG, expectedStartDragResult);
222 
223         mTargetResults = TestLogService.getResultsForClient(mTargetLogTag, 1000);
224         assertTargetResult(RESULT_KEY_DROP_RESULT, expectedDropResult);
225         if (!RESULT_MISSING.equals(expectedDropResult)) {
226             assertTargetResult(RESULT_KEY_ACCESS_BEFORE, RESULT_EXCEPTION);
227             assertTargetResult(RESULT_KEY_ACCESS_AFTER, RESULT_EXCEPTION);
228         }
229         assertListenerResults(expectedListenerResults);
230     }
231 
assertListenerResults(String expectedResult)232     private void assertListenerResults(String expectedResult) throws Exception {
233         assertTargetResult(RESULT_KEY_DRAG_STARTED, expectedResult);
234         assertTargetResult(RESULT_KEY_DRAG_ENDED, expectedResult);
235         assertTargetResult(RESULT_KEY_EXTRAS, expectedResult);
236 
237         assertTargetResult(RESULT_KEY_CLIP_DATA_ERROR, RESULT_MISSING);
238         assertTargetResult(RESULT_KEY_CLIP_DESCR_ERROR, RESULT_MISSING);
239         assertTargetResult(RESULT_KEY_LOCAL_STATE_ERROR, RESULT_MISSING);
240     }
241 
assertSourceResult(String resultKey, String expectedResult)242     private void assertSourceResult(String resultKey, String expectedResult) throws Exception {
243         assertResult(mSourceResults, resultKey, expectedResult);
244     }
245 
assertTargetResult(String resultKey, String expectedResult)246     private void assertTargetResult(String resultKey, String expectedResult) throws Exception {
247         assertResult(mTargetResults, resultKey, expectedResult);
248     }
249 
assertResult(Map<String, String> results, String resultKey, String expectedResult)250     private void assertResult(Map<String, String> results, String resultKey, String expectedResult)
251             throws Exception {
252         if (RESULT_MISSING.equals(expectedResult)) {
253             if (results.containsKey(resultKey)) {
254                 fail("Unexpected " + resultKey + "=" + results.get(resultKey));
255             }
256         } else {
257             assertTrue("Missing " + resultKey, results.containsKey(resultKey));
258             assertEquals(resultKey + " result mismatch,", expectedResult,
259                     results.get(resultKey));
260         }
261     }
262 
263     @Test
testCancelSoon()264     public void testCancelSoon() throws Exception {
265         assertDropResult(CANCEL_SOON, REQUEST_NONE, RESULT_MISSING);
266     }
267 
268     @Test
testDisallowGlobal()269     public void testDisallowGlobal() throws Exception {
270         assertNoGlobalDragEvents(DRAG_SOURCE, DISALLOW_GLOBAL, DROP_TARGET, RESULT_OK);
271     }
272 
273     @Test
testDisallowGlobalBelowSdk24()274     public void testDisallowGlobalBelowSdk24() throws Exception {
275         assertNoGlobalDragEvents(DRAG_SOURCE, GRANT_NONE, DROP_TARGET_SDK23, RESULT_OK);
276     }
277 
278     @Test
testFileUriLocal()279     public void testFileUriLocal() throws Exception {
280         assertNoGlobalDragEvents(DRAG_SOURCE, FILE_LOCAL, DROP_TARGET, RESULT_OK);
281     }
282 
283     @Test
testFileUriGlobal()284     public void testFileUriGlobal() throws Exception {
285         assertNoGlobalDragEvents(DRAG_SOURCE, FILE_GLOBAL, DROP_TARGET, RESULT_EXCEPTION);
286     }
287 
288     @Test
testGrantNoneRequestNone()289     public void testGrantNoneRequestNone() throws Exception {
290         assertDropResult(GRANT_NONE, REQUEST_NONE, RESULT_EXCEPTION);
291     }
292 
293     @Test
testGrantNoneRequestRead()294     public void testGrantNoneRequestRead() throws Exception {
295         assertDropResult(GRANT_NONE, REQUEST_READ, RESULT_NULL_DROP_PERMISSIONS);
296     }
297 
298     @Test
testGrantNoneRequestWrite()299     public void testGrantNoneRequestWrite() throws Exception {
300         assertDropResult(GRANT_NONE, REQUEST_WRITE, RESULT_NULL_DROP_PERMISSIONS);
301     }
302 
303     @Test
testGrantReadRequestNone()304     public void testGrantReadRequestNone() throws Exception {
305         assertDropResult(GRANT_READ, REQUEST_NONE, RESULT_EXCEPTION);
306     }
307 
308     @Test
testGrantReadRequestRead()309     public void testGrantReadRequestRead() throws Exception {
310         assertDropResult(GRANT_READ, REQUEST_READ, RESULT_OK);
311     }
312 
313     @Test
testGrantReadRequestWrite()314     public void testGrantReadRequestWrite() throws Exception {
315         assertDropResult(GRANT_READ, REQUEST_WRITE, RESULT_EXCEPTION);
316     }
317 
318     @Test
testGrantReadNoPrefixRequestReadNested()319     public void testGrantReadNoPrefixRequestReadNested() throws Exception {
320         assertDropResult(GRANT_READ_NOPREFIX, REQUEST_READ_NESTED, RESULT_EXCEPTION);
321     }
322 
323     @Test
testGrantReadPrefixRequestReadNested()324     public void testGrantReadPrefixRequestReadNested() throws Exception {
325         assertDropResult(GRANT_READ_PREFIX, REQUEST_READ_NESTED, RESULT_OK);
326     }
327 
328     @Test
testGrantPersistableRequestTakePersistable()329     public void testGrantPersistableRequestTakePersistable() throws Exception {
330         assertDropResult(GRANT_READ_PERSISTABLE, REQUEST_TAKE_PERSISTABLE, RESULT_OK);
331     }
332 
333     @Test
testGrantReadRequestTakePersistable()334     public void testGrantReadRequestTakePersistable() throws Exception {
335         assertDropResult(GRANT_READ, REQUEST_TAKE_PERSISTABLE, RESULT_EXCEPTION);
336     }
337 
338     @Test
testGrantWriteRequestNone()339     public void testGrantWriteRequestNone() throws Exception {
340         assertDropResult(GRANT_WRITE, REQUEST_NONE, RESULT_EXCEPTION);
341     }
342 
343     @Test
testGrantWriteRequestRead()344     public void testGrantWriteRequestRead() throws Exception {
345         assertDropResult(GRANT_WRITE, REQUEST_READ, RESULT_EXCEPTION);
346     }
347 
348     @Test
testGrantWriteRequestWrite()349     public void testGrantWriteRequestWrite() throws Exception {
350         assertDropResult(GRANT_WRITE, REQUEST_WRITE, RESULT_OK);
351     }
352 }
353