1 /* 2 * Copyright (C) 2022 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.scvh; 18 19 import static android.server.wm.BuildUtils.HW_TIMEOUT_MULTIPLIER; 20 21 import static org.junit.Assert.assertTrue; 22 23 import android.app.Service; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.os.Handler; 27 import android.os.IBinder; 28 import android.os.Looper; 29 import android.server.wm.CtsWindowInfoUtils; 30 import android.server.wm.shared.ICrossProcessSurfaceControlViewHostTestService; 31 import android.view.Display; 32 import android.view.MotionEvent; 33 import android.view.SurfaceControlViewHost; 34 import android.view.View; 35 import android.view.WindowManager; 36 37 import androidx.annotation.Nullable; 38 39 import java.util.concurrent.CountDownLatch; 40 import java.util.concurrent.TimeUnit; 41 42 public class CrossProcessSurfaceControlViewHostTestService extends Service { 43 private final ICrossProcessSurfaceControlViewHostTestService mBinder = new ServiceImpl(); 44 private Handler mHandler; 45 46 class MotionRecordingView extends View { 47 boolean mGotEvent = false; 48 boolean mGotObscuredEvent = false; 49 50 private CountDownLatch mReceivedTouchLatch = new CountDownLatch(1); 51 MotionRecordingView(Context c)52 MotionRecordingView(Context c) { 53 super(c); 54 } 55 onTouchEvent(MotionEvent e)56 public boolean onTouchEvent(MotionEvent e) { 57 super.onTouchEvent(e); 58 synchronized (this) { 59 mGotEvent = true; 60 if ((e.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 61 mGotObscuredEvent = true; 62 } 63 } 64 mReceivedTouchLatch.countDown(); 65 return true; 66 } 67 gotEvent()68 boolean gotEvent() { 69 synchronized (this) { 70 return mGotEvent; 71 } 72 } 73 gotObscuredTouch()74 boolean gotObscuredTouch() { 75 synchronized (this) { 76 return mGotObscuredEvent; 77 } 78 } 79 waitOnEvent()80 void waitOnEvent() { 81 try { 82 mReceivedTouchLatch.await(HW_TIMEOUT_MULTIPLIER * 5L, TimeUnit.SECONDS); 83 } catch (InterruptedException e) { 84 } 85 } 86 } 87 88 @Override onCreate()89 public void onCreate() { 90 mHandler = new Handler(Looper.getMainLooper()); 91 } 92 93 @Nullable 94 @Override onBind(Intent intent)95 public IBinder onBind(Intent intent) { 96 return mBinder.asBinder(); 97 } 98 getDefaultDisplay()99 Display getDefaultDisplay() { 100 WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); 101 return wm.getDefaultDisplay(); 102 } 103 104 SurfaceControlViewHost mSurfaceControlViewHost; 105 MotionRecordingView mView; 106 createSurfacePackage(IBinder hostInputToken)107 SurfaceControlViewHost.SurfacePackage createSurfacePackage(IBinder hostInputToken) { 108 mView = new MotionRecordingView(this); 109 mSurfaceControlViewHost = new SurfaceControlViewHost(this, getDefaultDisplay(), 110 hostInputToken); 111 mSurfaceControlViewHost.setView(mView, 100, 100); 112 return mSurfaceControlViewHost.getSurfacePackage(); 113 } 114 115 private class ServiceImpl extends ICrossProcessSurfaceControlViewHostTestService.Stub { drainHandler()116 private void drainHandler() { 117 final CountDownLatch latch = new CountDownLatch(1); 118 mHandler.post(latch::countDown); 119 try { 120 assertTrue("Failed to wait for handler to drain", 121 latch.await(HW_TIMEOUT_MULTIPLIER * 1L, TimeUnit.SECONDS)); 122 } catch (Exception e) { 123 } 124 } 125 126 @Override getSurfacePackage(IBinder hostInputToken)127 public SurfaceControlViewHost.SurfacePackage getSurfacePackage(IBinder hostInputToken) { 128 final CountDownLatch latch = new CountDownLatch(1); 129 mHandler.post(() -> { 130 createSurfacePackage(hostInputToken); 131 mView.getViewTreeObserver().registerFrameCommitCallback(latch::countDown); 132 mView.invalidate(); 133 }); 134 try { 135 assertTrue("Failed to wait for frame to draw", 136 latch.await(HW_TIMEOUT_MULTIPLIER * 1L, TimeUnit.SECONDS)); 137 } catch (Exception e) { 138 return null; 139 } 140 return mSurfaceControlViewHost.getSurfacePackage(); 141 } 142 143 @Override getViewIsTouched()144 public boolean getViewIsTouched() { 145 drainHandler(); 146 mView.waitOnEvent(); 147 return mView.gotEvent(); 148 } 149 150 @Override getViewIsTouchedAndObscured()151 public boolean getViewIsTouchedAndObscured() { 152 return getViewIsTouched() && mView.gotObscuredTouch(); 153 } 154 155 @Override getWindowToken()156 public IBinder getWindowToken() { 157 return mView.getWindowToken(); 158 } 159 160 @Override waitForFocus(boolean waitForFocus)161 public boolean waitForFocus(boolean waitForFocus) { 162 return CtsWindowInfoUtils.waitForWindowFocus(mView, waitForFocus); 163 } 164 165 } 166 } 167