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