• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.view.cts.util;
18 
19 import static android.server.wm.BuildUtils.HW_TIMEOUT_MULTIPLIER;
20 
21 import static org.junit.Assert.assertTrue;
22 
23 import android.content.Context;
24 import android.graphics.Color;
25 import android.graphics.PixelFormat;
26 import android.os.Handler;
27 import android.os.Looper;
28 import android.os.RemoteException;
29 import android.util.Log;
30 import android.util.Size;
31 import android.view.AttachedSurfaceControl;
32 import android.view.Gravity;
33 import android.view.SurfaceControl;
34 import android.view.SurfaceControlViewHost.SurfacePackage;
35 import android.view.SurfaceView;
36 import android.view.ViewGroup;
37 import android.view.WindowManager;
38 import android.view.cts.surfacevalidator.ISurfaceValidatorTestCase;
39 import android.view.cts.surfacevalidator.PixelChecker;
40 import android.view.cts.util.aidl.IAttachEmbeddedWindow;
41 import android.widget.FrameLayout;
42 import android.widget.TextView;
43 import android.window.SurfaceSyncGroup;
44 
45 import java.util.concurrent.CountDownLatch;
46 import java.util.concurrent.TimeUnit;
47 
48 public class SyncValidatorSCVHTestCase implements ISurfaceValidatorTestCase {
49     private static final String TAG = "SCVHSyncValidatorTestCase";
50 
51     private final Size[] mSizes = new Size[]{new Size(500, 500), new Size(700, 400),
52             new Size(300, 800), new Size(200, 200)};
53     private int mLastSizeIndex = 0;
54 
55     private final long mDelayMs;
56 
57     private SurfaceControlViewHostHelper mSurfaceControlViewHostHelper;
58 
59     private IAttachEmbeddedWindow mIAttachEmbeddedWindow;
60 
61     private Handler mHandler;
62     private TextView mTextView;
63     private SurfaceView mSurfaceView;
64     private SurfacePackage mSurfacePackage;
65 
66     private final CountDownLatch mReadyToStart = new CountDownLatch(1);
67 
68     private final boolean mInProcess;
69 
SyncValidatorSCVHTestCase(long delayMs, boolean inProcess)70     public SyncValidatorSCVHTestCase(long delayMs, boolean inProcess) {
71         mDelayMs = delayMs;
72         mInProcess = inProcess;
73     }
74 
75     private final Runnable mResizeWithSurfaceSyncGroup = new Runnable() {
76         @Override
77         public void run() {
78             Size size = mSizes[mLastSizeIndex % mSizes.length];
79 
80             Runnable svResizeRunnable = () -> {
81                 ViewGroup.LayoutParams svParams = mSurfaceView.getLayoutParams();
82                 svParams.width = size.getWidth();
83                 svParams.height = size.getHeight();
84                 mSurfaceView.setLayoutParams(svParams);
85 
86                 mTextView.setText(size.getWidth() + "x" + size.getHeight());
87             };
88 
89             Runnable embeddedResizeRunnable = () -> {
90                 try {
91                     final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
92                             size.getWidth(), size.getHeight(),
93                             WindowManager.LayoutParams.TYPE_APPLICATION, 0,
94                             PixelFormat.TRANSPARENT);
95                     mIAttachEmbeddedWindow.relayout(lp);
96                 } catch (RemoteException e) {
97                     Log.e(TAG, "Failed to call relayout for embedded window");
98                 }
99             };
100 
101             SurfaceSyncGroup syncGroup = new SurfaceSyncGroup(TAG);
102             syncGroup.add(mSurfaceView.getRootSurfaceControl(), svResizeRunnable);
103             syncGroup.add(mSurfacePackage, embeddedResizeRunnable);
104             syncGroup.markSyncReady();
105 
106             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
107             t.addTransactionCommittedListener(Runnable::run, () -> {
108                 if (mSurfaceView.isAttachedToWindow()) {
109                     mHandler.postDelayed(mResizeWithSurfaceSyncGroup, mDelayMs);
110                 }
111             });
112             AttachedSurfaceControl attachedSurfaceControl = mSurfaceView.getRootSurfaceControl();
113             if (attachedSurfaceControl != null) {
114                 mSurfaceView.getRootSurfaceControl().applyTransactionOnDraw(t);
115             }
116 
117             mLastSizeIndex++;
118         }
119     };
120 
121     @Override
getChecker()122     public PixelChecker getChecker() {
123         return new PixelChecker(Color.BLACK) {
124             @Override
125             public boolean checkPixels(int matchingPixelCount, int width, int height) {
126                 // Content has been set up yet.
127                 if (mSurfacePackage == null) {
128                     return true;
129                 }
130                 return matchingPixelCount == 0;
131             }
132         };
133     }
134 
135     @Override
136     public void start(Context context, FrameLayout parent) {
137         mHandler = new Handler(Looper.getMainLooper());
138 
139         mSurfaceControlViewHostHelper = new SurfaceControlViewHostHelper(TAG, mReadyToStart,
140                 context, mDelayMs, mSizes[0]);
141 
142         mSurfaceControlViewHostHelper.bindEmbeddedService(mInProcess);
143 
144         FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(mSizes[0].getWidth(),
145                 mSizes[0].getHeight());
146         layoutParams.gravity = Gravity.CENTER;
147 
148         mSurfaceView = mSurfaceControlViewHostHelper.attachSurfaceView(parent, layoutParams);
149 
150         mTextView = new TextView(context);
151         mTextView.setTextColor(Color.GREEN);
152         mTextView.setText(mSizes[0].getWidth() + "x" + mSizes[0].getHeight());
153         FrameLayout.LayoutParams txtParams = new FrameLayout.LayoutParams(
154                 ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
155         txtParams.gravity = Gravity.TOP | Gravity.LEFT;
156         parent.addView(mTextView, txtParams);
157     }
158 
159     @Override
160     public boolean waitForReady() {
161         boolean ready;
162         try {
163             ready = mReadyToStart.await(3L * HW_TIMEOUT_MULTIPLIER, TimeUnit.SECONDS);
164         } catch (InterruptedException e) {
165             Log.e(TAG, "Failed to wait for SCVH to attach");
166             return false;
167         }
168 
169         assertTrue("Failed to attach SCVH", ready);
170 
171         mSurfacePackage = mSurfaceControlViewHostHelper.getSurfacePackage();
172         mIAttachEmbeddedWindow = mSurfaceControlViewHostHelper.getAttachedEmbeddedWindow();
173 
174         mHandler.post(mResizeWithSurfaceSyncGroup);
175         return true;
176     }
177 
178     @Override
179     public void end() {
180         mHandler.removeCallbacks(mResizeWithSurfaceSyncGroup);
181     }
182 }
183