• 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 android.view.Display.DEFAULT_DISPLAY;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertNotNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.fail;
29 import static org.junit.Assume.assumeTrue;
30 
31 import android.content.ComponentName;
32 import android.graphics.Point;
33 import android.graphics.Rect;
34 import android.os.SystemClock;
35 import android.platform.test.annotations.AppModeFull;
36 import android.platform.test.annotations.Presubmit;
37 import android.server.wm.WindowManagerState.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     private Map<String, String> mSourceResults;
96     private Map<String, String> mTargetResults;
97 
98     private String mSessionId;
99     private String mSourceLogTag;
100     private String mTargetLogTag;
101 
102     @Before
103     @Override
setUp()104     public void setUp() throws Exception {
105         super.setUp();
106         assumeTrue(supportsSplitScreenMultiWindow() || supportsFreeform());
107 
108         // Use uptime in seconds as unique test invocation id.
109         mSessionId = Long.toString(SystemClock.uptimeMillis() / 1000);
110         mSourceLogTag = SOURCE_LOG_TAG + mSessionId;
111         mTargetLogTag = TARGET_LOG_TAG + mSessionId;
112 
113         cleanupState();
114         mUseTaskOrganizer = false;
115     }
116 
117     @After
tearDown()118     public void tearDown() {
119         cleanupState();
120     }
121 
122     /**
123      * Make sure that the special activity stacks are removed and the ActivityManager/WindowManager
124      * is in a good state.
125      */
cleanupState()126     private void cleanupState() {
127         stopTestPackage(DRAG_SOURCE.getPackageName());
128         stopTestPackage(DROP_TARGET.getPackageName());
129         stopTestPackage(DROP_TARGET_SDK23.getPackageName());
130     }
131 
132     /**
133      * @param displaySize size of the display
134      * @param leftSide {@code true} to launch the app taking up the left half of the display,
135      *         {@code false} to launch the app taking up the right half of the display.
136      */
launchFreeformActivity(ComponentName componentName, String mode, String logtag, Point displaySize, boolean leftSide)137     private void launchFreeformActivity(ComponentName componentName, String mode,
138             String logtag, Point displaySize, boolean leftSide) throws Exception {
139         launchActivity(componentName, WINDOWING_MODE_FREEFORM, "mode", mode, "logtag", logtag);
140         Point topLeft = new Point(leftSide ? 0 : displaySize.x / 2, 0);
141         Point bottomRight = new Point(leftSide ? displaySize.x / 2 : displaySize.x, displaySize.y);
142         resizeActivityTask(componentName, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
143         waitAndAssertTopResumedActivity(componentName, DEFAULT_DISPLAY,
144                 "Activity launched as freeform should be resumed");
145     }
146 
injectInput(Point from, Point to, int steps)147     private void injectInput(Point from, Point to, int steps) throws Exception {
148         dragPointer(from, to, steps);
149     }
150 
getDisplaySize()151     private Point getDisplaySize() throws Exception {
152         final Point displaySize = new Point();
153         mDm.getDisplay(Display.DEFAULT_DISPLAY).getRealSize(displaySize);
154         return displaySize;
155     }
156 
getWindowCenter(ComponentName name)157     private Point getWindowCenter(ComponentName name) throws Exception {
158         final ActivityTask sideTask = mWmState.getTaskByActivity(name);
159         Rect bounds = sideTask.getBounds();
160         if (bounds != null) {
161             return new Point(bounds.centerX(), bounds.centerY());
162         }
163         return null;
164     }
165 
assertDropResult(String sourceMode, String targetMode, String expectedDropResult)166     private void assertDropResult(String sourceMode, String targetMode, String expectedDropResult)
167             throws Exception {
168         assertDragAndDropResults(DRAG_SOURCE, sourceMode, DROP_TARGET, targetMode,
169                 RESULT_OK, expectedDropResult, RESULT_OK);
170     }
171 
assertNoGlobalDragEvents(ComponentName sourceComponentName, String sourceMode, ComponentName targetComponentName, String expectedStartDragResult)172     private void assertNoGlobalDragEvents(ComponentName sourceComponentName, String sourceMode,
173             ComponentName targetComponentName, String expectedStartDragResult)
174             throws Exception {
175         assertDragAndDropResults(
176                 sourceComponentName, sourceMode, targetComponentName, REQUEST_NONE,
177                 expectedStartDragResult, RESULT_MISSING, RESULT_MISSING);
178     }
179 
assertDragAndDropResults(ComponentName sourceComponentName, String sourceMode, ComponentName targetComponentName, String targetMode, String expectedStartDragResult, String expectedDropResult, String expectedListenerResults)180     private void assertDragAndDropResults(ComponentName sourceComponentName, String sourceMode,
181             ComponentName targetComponentName, String targetMode,
182             String expectedStartDragResult, String expectedDropResult,
183             String expectedListenerResults) throws Exception {
184         Log.e(TAG, "session: " + mSessionId + ", source: " + sourceMode
185                 + ", target: " + targetMode);
186 
187         if (supportsFreeform()) {
188             // Fallback to try to launch two freeform windows side by side.
189             Point displaySize = getDisplaySize();
190             launchFreeformActivity(sourceComponentName, sourceMode, mSourceLogTag,
191                 displaySize, true /* leftSide */);
192             launchFreeformActivity(targetComponentName, targetMode, mTargetLogTag,
193                 displaySize, false /* leftSide */);
194         } else {
195             launchActivitiesInSplitScreen(getLaunchActivityBuilder()
196                     .setTargetActivity(sourceComponentName)
197                     .setIntentExtra(bundle -> {
198                         bundle.putString(EXTRA_MODE, sourceMode);
199                         bundle.putString(EXTRA_LOGTAG, mSourceLogTag);
200                     }),
201                     getLaunchActivityBuilder().setTargetActivity(targetComponentName)
202                     .setIntentExtra(bundle -> {
203                         bundle.putString(EXTRA_MODE, targetMode);
204                         bundle.putString(EXTRA_LOGTAG, mTargetLogTag);
205                     }));
206         }
207 
208         Point p1 = getWindowCenter(sourceComponentName);
209         assertNotNull(p1);
210         Point p2 = getWindowCenter(targetComponentName);
211         assertNotNull(p2);
212 
213         TestLogService.registerClient(mSourceLogTag, RESULT_KEY_START_DRAG);
214         TestLogService.registerClient(mTargetLogTag, RESULT_KEY_DRAG_ENDED);
215 
216         injectInput(p1, p2, SWIPE_STEPS);
217 
218         mSourceResults = TestLogService.getResultsForClient(mSourceLogTag, 1000);
219         assertSourceResult(RESULT_KEY_START_DRAG, expectedStartDragResult);
220 
221         mTargetResults = TestLogService.getResultsForClient(mTargetLogTag, 1000);
222         assertTargetResult(RESULT_KEY_DROP_RESULT, expectedDropResult);
223         if (!RESULT_MISSING.equals(expectedDropResult)) {
224             assertTargetResult(RESULT_KEY_ACCESS_BEFORE, RESULT_EXCEPTION);
225             assertTargetResult(RESULT_KEY_ACCESS_AFTER, RESULT_EXCEPTION);
226         }
227         assertListenerResults(expectedListenerResults);
228     }
229 
assertListenerResults(String expectedResult)230     private void assertListenerResults(String expectedResult) throws Exception {
231         assertTargetResult(RESULT_KEY_DRAG_STARTED, expectedResult);
232         assertTargetResult(RESULT_KEY_DRAG_ENDED, expectedResult);
233         assertTargetResult(RESULT_KEY_EXTRAS, expectedResult);
234 
235         assertTargetResult(RESULT_KEY_CLIP_DATA_ERROR, RESULT_MISSING);
236         assertTargetResult(RESULT_KEY_CLIP_DESCR_ERROR, RESULT_MISSING);
237         assertTargetResult(RESULT_KEY_LOCAL_STATE_ERROR, RESULT_MISSING);
238     }
239 
assertSourceResult(String resultKey, String expectedResult)240     private void assertSourceResult(String resultKey, String expectedResult) throws Exception {
241         assertResult(mSourceResults, resultKey, expectedResult);
242     }
243 
assertTargetResult(String resultKey, String expectedResult)244     private void assertTargetResult(String resultKey, String expectedResult) throws Exception {
245         assertResult(mTargetResults, resultKey, expectedResult);
246     }
247 
assertResult(Map<String, String> results, String resultKey, String expectedResult)248     private void assertResult(Map<String, String> results, String resultKey, String expectedResult)
249             throws Exception {
250         if (RESULT_MISSING.equals(expectedResult)) {
251             if (results.containsKey(resultKey)) {
252                 fail("Unexpected " + resultKey + "=" + results.get(resultKey));
253             }
254         } else {
255             assertTrue("Missing " + resultKey, results.containsKey(resultKey));
256             assertEquals(resultKey + " result mismatch,", expectedResult,
257                     results.get(resultKey));
258         }
259     }
260 
261     @Test
testCancelSoon()262     public void testCancelSoon() throws Exception {
263         assertDropResult(CANCEL_SOON, REQUEST_NONE, RESULT_MISSING);
264     }
265 
266     @Test
testDisallowGlobal()267     public void testDisallowGlobal() throws Exception {
268         assertNoGlobalDragEvents(DRAG_SOURCE, DISALLOW_GLOBAL, DROP_TARGET, RESULT_OK);
269     }
270 
271     @Test
testDisallowGlobalBelowSdk24()272     public void testDisallowGlobalBelowSdk24() throws Exception {
273         assertNoGlobalDragEvents(DRAG_SOURCE, GRANT_NONE, DROP_TARGET_SDK23, RESULT_OK);
274     }
275 
276     @Test
testFileUriLocal()277     public void testFileUriLocal() throws Exception {
278         assertNoGlobalDragEvents(DRAG_SOURCE, FILE_LOCAL, DROP_TARGET, RESULT_OK);
279     }
280 
281     @Test
testFileUriGlobal()282     public void testFileUriGlobal() throws Exception {
283         assertNoGlobalDragEvents(DRAG_SOURCE, FILE_GLOBAL, DROP_TARGET, RESULT_EXCEPTION);
284     }
285 
286     @Test
testGrantNoneRequestNone()287     public void testGrantNoneRequestNone() throws Exception {
288         assertDropResult(GRANT_NONE, REQUEST_NONE, RESULT_EXCEPTION);
289     }
290 
291     @Test
testGrantNoneRequestRead()292     public void testGrantNoneRequestRead() throws Exception {
293         assertDropResult(GRANT_NONE, REQUEST_READ, RESULT_NULL_DROP_PERMISSIONS);
294     }
295 
296     @Test
testGrantNoneRequestWrite()297     public void testGrantNoneRequestWrite() throws Exception {
298         assertDropResult(GRANT_NONE, REQUEST_WRITE, RESULT_NULL_DROP_PERMISSIONS);
299     }
300 
301     @Test
testGrantReadRequestNone()302     public void testGrantReadRequestNone() throws Exception {
303         assertDropResult(GRANT_READ, REQUEST_NONE, RESULT_EXCEPTION);
304     }
305 
306     @Test
testGrantReadRequestRead()307     public void testGrantReadRequestRead() throws Exception {
308         assertDropResult(GRANT_READ, REQUEST_READ, RESULT_OK);
309     }
310 
311     @Test
testGrantReadRequestWrite()312     public void testGrantReadRequestWrite() throws Exception {
313         assertDropResult(GRANT_READ, REQUEST_WRITE, RESULT_EXCEPTION);
314     }
315 
316     @Test
testGrantReadNoPrefixRequestReadNested()317     public void testGrantReadNoPrefixRequestReadNested() throws Exception {
318         assertDropResult(GRANT_READ_NOPREFIX, REQUEST_READ_NESTED, RESULT_EXCEPTION);
319     }
320 
321     @Test
testGrantReadPrefixRequestReadNested()322     public void testGrantReadPrefixRequestReadNested() throws Exception {
323         assertDropResult(GRANT_READ_PREFIX, REQUEST_READ_NESTED, RESULT_OK);
324     }
325 
326     @Test
testGrantPersistableRequestTakePersistable()327     public void testGrantPersistableRequestTakePersistable() throws Exception {
328         assertDropResult(GRANT_READ_PERSISTABLE, REQUEST_TAKE_PERSISTABLE, RESULT_OK);
329     }
330 
331     @Test
testGrantReadRequestTakePersistable()332     public void testGrantReadRequestTakePersistable() throws Exception {
333         assertDropResult(GRANT_READ, REQUEST_TAKE_PERSISTABLE, RESULT_EXCEPTION);
334     }
335 
336     @Test
testGrantWriteRequestNone()337     public void testGrantWriteRequestNone() throws Exception {
338         assertDropResult(GRANT_WRITE, REQUEST_NONE, RESULT_EXCEPTION);
339     }
340 
341     @Test
testGrantWriteRequestRead()342     public void testGrantWriteRequestRead() throws Exception {
343         assertDropResult(GRANT_WRITE, REQUEST_READ, RESULT_EXCEPTION);
344     }
345 
346     @Test
testGrantWriteRequestWrite()347     public void testGrantWriteRequestWrite() throws Exception {
348         assertDropResult(GRANT_WRITE, REQUEST_WRITE, RESULT_OK);
349     }
350 }
351