blob: 68b09982be9855d765ae3635a58a9bbba5286855 [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;
Tadashi G. Takaokadee5a4d2018-09-19 11:59:40 +090022
Daichi Hirono1821c5a2017-12-12 17:54:12 +090023import static org.junit.Assert.assertNotNull;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090024import 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 Hironoa1fb9be2017-12-18 17:02:54 +090031import android.graphics.PixelFormat;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090032import android.os.IBinder;
Daichi Hironoda0748d2017-12-13 12:48:59 +090033import android.os.Looper;
34import android.os.UserHandle;
35import android.os.UserManagerInternal;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090036import android.platform.test.annotations.Presubmit;
37import android.support.test.filters.SmallTest;
38import android.support.test.runner.AndroidJUnit4;
39import android.view.InputChannel;
Daichi Hironoa1fb9be2017-12-18 17:02:54 +090040import android.view.SurfaceControl;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090041import android.view.SurfaceSession;
Daichi Hironoda0748d2017-12-13 12:48:59 +090042import android.view.View;
Tadashi G. Takaokadee5a4d2018-09-19 11:59:40 +090043
Daichi Hironoda0748d2017-12-13 12:48:59 +090044import com.android.internal.annotations.GuardedBy;
45import com.android.server.LocalServices;
Tadashi G. Takaokadee5a4d2018-09-19 11:59:40 +090046
Daichi Hirono1821c5a2017-12-12 17:54:12 +090047import org.junit.After;
48import org.junit.Before;
49import org.junit.Test;
50import org.junit.runner.RunWith;
Daichi Hironoda0748d2017-12-13 12:48:59 +090051
Tadashi G. Takaokadee5a4d2018-09-19 11:59:40 +090052import java.util.concurrent.CountDownLatch;
53import java.util.concurrent.TimeUnit;
54
Daichi Hirono1821c5a2017-12-12 17:54:12 +090055/**
56 * Tests for the {@link DragDropController} class.
57 *
Tadashi G. Takaokadee5a4d2018-09-19 11:59:40 +090058 * Build/Install/Run:
59 * atest WmTests:DragDropControllerTests
Daichi Hirono1821c5a2017-12-12 17:54:12 +090060 */
61@SmallTest
62@RunWith(AndroidJUnit4.class)
63@Presubmit
64public class DragDropControllerTests extends WindowTestsBase {
Daichi Hironoda0748d2017-12-13 12:48:59 +090065 private static final int TIMEOUT_MS = 3000;
66 private TestDragDropController mTarget;
Daichi Hirono1821c5a2017-12-12 17:54:12 +090067 private WindowState mWindow;
68 private IBinder mToken;
69
Daichi Hironoda0748d2017-12-13 12:48:59 +090070 static class TestDragDropController extends DragDropController {
71 @GuardedBy("sWm.mWindowMap")
72 private Runnable mCloseCallback;
73
74 TestDragDropController(WindowManagerService service, Looper looper) {
75 super(service, looper);
76 }
77
78 void setOnClosedCallbackLocked(Runnable runnable) {
79 assertTrue(dragDropActiveLocked());
80 mCloseCallback = runnable;
81 }
82
83 @Override
84 void onDragStateClosedLocked(DragState dragState) {
85 super.onDragStateClosedLocked(dragState);
86 if (mCloseCallback != null) {
87 mCloseCallback.run();
88 mCloseCallback = null;
89 }
90 }
91 }
92
93 /**
94 * Creates a window state which can be used as a drop target.
95 */
96 private WindowState createDropTargetWindow(String name, int ownerId) {
chaviw97d28202018-02-27 16:23:53 -080097 final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
Daichi Hironoda0748d2017-12-13 12:48:59 +090098 mDisplayContent);
99 final TaskStack stack = createStackControllerOnStackOnDisplay(
100 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
101 final Task task = createTaskInStack(stack, ownerId);
102 task.addChild(token, 0);
103
104 final WindowState window = createWindow(
105 null, TYPE_BASE_APPLICATION, token, name, ownerId, false);
106 window.mInputChannel = new InputChannel();
107 window.mHasSurface = true;
108 return window;
109 }
110
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900111 @Before
112 public void setUp() throws Exception {
Daichi Hironoda0748d2017-12-13 12:48:59 +0900113 final UserManagerInternal userManager = mock(UserManagerInternal.class);
114 LocalServices.addService(UserManagerInternal.class, userManager);
115
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900116 super.setUp();
Daichi Hironoda0748d2017-12-13 12:48:59 +0900117
118 mTarget = new TestDragDropController(sWm, sWm.mH.getLooper());
119 mDisplayContent = spy(mDisplayContent);
120 mWindow = createDropTargetWindow("Drag test window", 0);
121 when(mDisplayContent.getTouchableWinAtPointLocked(0, 0)).thenReturn(mWindow);
122 when(sWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
123
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900124 synchronized (sWm.mWindowMap) {
Daichi Hironoda0748d2017-12-13 12:48:59 +0900125 sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900126 }
127 }
128
129 @After
Daichi Hironoda0748d2017-12-13 12:48:59 +0900130 public void tearDown() throws Exception {
131 LocalServices.removeServiceForTest(UserManagerInternal.class);
132 final CountDownLatch latch;
133 synchronized (sWm.mWindowMap) {
134 if (!mTarget.dragDropActiveLocked()) {
135 return;
136 }
137 if (mToken != null) {
138 mTarget.cancelDragAndDrop(mToken);
139 }
140 latch = new CountDownLatch(1);
141 mTarget.setOnClosedCallbackLocked(() -> {
142 latch.countDown();
143 });
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900144 }
Daichi Hironoda0748d2017-12-13 12:48:59 +0900145 assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900146 }
147
148 @Test
Daichi Hironoda0748d2017-12-13 12:48:59 +0900149 public void testDragFlow() throws Exception {
150 dragFlow(0, ClipData.newPlainText("label", "Test"), 0, 0);
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900151 }
152
153 @Test
Daichi Hironoda0748d2017-12-13 12:48:59 +0900154 public void testPerformDrag_NullDataWithGrantUri() throws Exception {
155 dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
156 }
157
158 @Test
159 public void testPerformDrag_NullDataToOtherUser() throws Exception {
160 final WindowState otherUsersWindow =
161 createDropTargetWindow("Other user's window", 1 * UserHandle.PER_USER_RANGE);
162 when(mDisplayContent.getTouchableWinAtPointLocked(10, 10))
163 .thenReturn(otherUsersWindow);
164
165 dragFlow(0, null, 10, 10);
166 }
167
168 private void dragFlow(int flag, ClipData data, float dropX, float dropY) {
Daichi Hironoa1fb9be2017-12-18 17:02:54 +0900169 final SurfaceSession appSession = new SurfaceSession();
170 try {
171 final SurfaceControl surface = new SurfaceControl.Builder(appSession)
172 .setName("drag surface")
173 .setSize(100, 100)
174 .setFormat(PixelFormat.TRANSLUCENT)
175 .build();
Daichi Hironoda0748d2017-12-13 12:48:59 +0900176
Daichi Hironoa1fb9be2017-12-18 17:02:54 +0900177 assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
Daichi Hironofabca092017-12-19 15:02:50 +0900178 mToken = mTarget.performDrag(
179 new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0,
180 data);
181 assertNotNull(mToken);
Daichi Hironoda0748d2017-12-13 12:48:59 +0900182
Daichi Hironoa1fb9be2017-12-18 17:02:54 +0900183 mTarget.handleMotionEvent(false, dropX, dropY);
184 mToken = mWindow.mClient.asBinder();
185 } finally {
186 appSession.kill();
187 }
Daichi Hironoda0748d2017-12-13 12:48:59 +0900188 }
Daichi Hirono1821c5a2017-12-12 17:54:12 +0900189}