blob: ac291632c877247a515abf5f6fb76d84fffac259 [file] [log] [blame]
Daichi Hirono1821c5a2017-12-12 17:54:12 +09001/*
2 * Copyright (C) 2017 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
17package com.android.server.wm;
18
Daichi Hironoda0748d2017-12-13 12:48:59 +090019import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090021import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090022import static org.junit.Assert.assertNotNull;
23import static org.junit.Assert.assertNull;
24import static org.junit.Assert.assertTrue;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090025import static org.mockito.Mockito.any;
26import static org.mockito.Mockito.mock;
Daichi Hironoda0748d2017-12-13 12:48:59 +090027import static org.mockito.Mockito.spy;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090028import static org.mockito.Mockito.when;
29
Daichi Hironoda0748d2017-12-13 12:48:59 +090030import android.content.ClipData;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090031import android.os.IBinder;
Daichi Hironoda0748d2017-12-13 12:48:59 +090032import android.os.Looper;
33import android.os.UserHandle;
34import android.os.UserManagerInternal;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090035import android.platform.test.annotations.Presubmit;
36import android.support.test.filters.SmallTest;
37import android.support.test.runner.AndroidJUnit4;
38import android.view.InputChannel;
39import android.view.Surface;
40import android.view.SurfaceSession;
Daichi Hironoda0748d2017-12-13 12:48:59 +090041import android.view.View;
42import com.android.internal.annotations.GuardedBy;
43import com.android.server.LocalServices;
44import java.util.concurrent.CountDownLatch;
45import java.util.concurrent.TimeUnit;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090046import org.junit.After;
47import org.junit.Before;
48import org.junit.Test;
49import org.junit.runner.RunWith;
Daichi Hironoda0748d2017-12-13 12:48:59 +090050
Daichi Hirono1821c5a2017-12-12 17:54:12 +090051/**
52 * Tests for the {@link DragDropController} class.
53 *
54 * atest com.android.server.wm.DragDropControllerTests
55 */
56@SmallTest
57@RunWith(AndroidJUnit4.class)
58@Presubmit
59public class DragDropControllerTests extends WindowTestsBase {
Daichi Hironoda0748d2017-12-13 12:48:59 +090060 private static final int TIMEOUT_MS = 3000;
61 private TestDragDropController mTarget;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090062 private WindowState mWindow;
63 private IBinder mToken;
64
Daichi Hironoda0748d2017-12-13 12:48:59 +090065 static class TestDragDropController extends DragDropController {
66 @GuardedBy("sWm.mWindowMap")
67 private Runnable mCloseCallback;
68
69 TestDragDropController(WindowManagerService service, Looper looper) {
70 super(service, looper);
71 }
72
73 void setOnClosedCallbackLocked(Runnable runnable) {
74 assertTrue(dragDropActiveLocked());
75 mCloseCallback = runnable;
76 }
77
78 @Override
79 void onDragStateClosedLocked(DragState dragState) {
80 super.onDragStateClosedLocked(dragState);
81 if (mCloseCallback != null) {
82 mCloseCallback.run();
83 mCloseCallback = null;
84 }
85 }
86 }
87
88 /**
89 * Creates a window state which can be used as a drop target.
90 */
91 private WindowState createDropTargetWindow(String name, int ownerId) {
92 final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(
93 mDisplayContent);
94 final TaskStack stack = createStackControllerOnStackOnDisplay(
95 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
96 final Task task = createTaskInStack(stack, ownerId);
97 task.addChild(token, 0);
98
99 final WindowState window = createWindow(
100 null, TYPE_BASE_APPLICATION, token, name, ownerId, false);
101 window.mInputChannel = new InputChannel();
102 window.mHasSurface = true;
103 return window;
104 }
105
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900106 @Before
107 public void setUp() throws Exception {
Daichi Hironoda0748d2017-12-13 12:48:59 +0900108 final UserManagerInternal userManager = mock(UserManagerInternal.class);
109 LocalServices.addService(UserManagerInternal.class, userManager);
110
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900111 super.setUp();
Daichi Hironoda0748d2017-12-13 12:48:59 +0900112
113 mTarget = new TestDragDropController(sWm, sWm.mH.getLooper());
114 mDisplayContent = spy(mDisplayContent);
115 mWindow = createDropTargetWindow("Drag test window", 0);
116 when(mDisplayContent.getTouchableWinAtPointLocked(0, 0)).thenReturn(mWindow);
117 when(sWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
118
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900119 synchronized (sWm.mWindowMap) {
Daichi Hironoda0748d2017-12-13 12:48:59 +0900120 sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900121 }
122 }
123
124 @After
Daichi Hironoda0748d2017-12-13 12:48:59 +0900125 public void tearDown() throws Exception {
126 LocalServices.removeServiceForTest(UserManagerInternal.class);
127 final CountDownLatch latch;
128 synchronized (sWm.mWindowMap) {
129 if (!mTarget.dragDropActiveLocked()) {
130 return;
131 }
132 if (mToken != null) {
133 mTarget.cancelDragAndDrop(mToken);
134 }
135 latch = new CountDownLatch(1);
136 mTarget.setOnClosedCallbackLocked(() -> {
137 latch.countDown();
138 });
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900139 }
Daichi Hironoda0748d2017-12-13 12:48:59 +0900140 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900141 }
142
143 @Test
Daichi Hironoda0748d2017-12-13 12:48:59 +0900144 public void testDragFlow() throws Exception {
145 dragFlow(0, ClipData.newPlainText("label", "Test"), 0, 0);
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900146 }
147
148 @Test
149 public void testPrepareDrag_ZeroSizeSurface() throws Exception {
150 final Surface surface = new Surface();
151 mToken = mTarget.prepareDrag(
152 new SurfaceSession(), 0, 0, mWindow.mClient, 0, 0, 0, surface);
153 assertNull(mToken);
154 }
Daichi Hironoda0748d2017-12-13 12:48:59 +0900155
156 @Test
157 public void testPerformDrag_NullDataWithGrantUri() throws Exception {
158 dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
159 }
160
161 @Test
162 public void testPerformDrag_NullDataToOtherUser() throws Exception {
163 final WindowState otherUsersWindow =
164 createDropTargetWindow("Other user's window", 1 * UserHandle.PER_USER_RANGE);
165 when(mDisplayContent.getTouchableWinAtPointLocked(10, 10))
166 .thenReturn(otherUsersWindow);
167
168 dragFlow(0, null, 10, 10);
169 }
170
171 private void dragFlow(int flag, ClipData data, float dropX, float dropY) {
172 final Surface surface = new Surface();
173 mToken = mTarget.prepareDrag(
174 new SurfaceSession(), 0, 0, mWindow.mClient, flag, 100, 100, surface);
175 assertNotNull(mToken);
176
177 assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
178 assertTrue(mTarget.performDrag(
179 mWindow.mClient, mToken, 0, 0, 0, 0, 0, data));
180
181 mTarget.handleMotionEvent(false, dropX, dropY);
182 mToken = mWindow.mClient.asBinder();
183 }
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900184}