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 com.android.test.viewembed; 18 19 import android.app.Activity; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.ServiceConnection; 24 import android.graphics.PixelFormat; 25 import android.graphics.Point; 26 import android.os.Bundle; 27 import android.os.IBinder; 28 import android.os.RemoteException; 29 import android.util.Log; 30 import android.view.Gravity; 31 import android.view.SurfaceControlViewHost.SurfacePackage; 32 import android.view.SurfaceHolder; 33 import android.view.SurfaceView; 34 import android.view.ViewGroup; 35 import android.view.WindowManager; 36 import android.widget.Button; 37 import android.widget.FrameLayout; 38 import android.widget.Switch; 39 import android.window.SurfaceSyncGroup; 40 41 public class SurfaceControlViewHostSyncTest extends Activity implements SurfaceHolder.Callback { 42 private static final String TAG = "SurfaceControlViewHostSyncTest"; 43 private SurfaceView mSv; 44 45 private final Object mLock = new Object(); 46 private boolean mIsAttached; 47 private boolean mSurfaceCreated; 48 49 private IAttachEmbeddedWindow mIAttachEmbeddedWindow; 50 private SurfacePackage mSurfacePackage; 51 52 private final Point[] mSizes = new Point[]{new Point(500, 500), new Point(700, 400), 53 new Point(300, 800), new Point(200, 200)}; 54 private int mLastSizeIndex = 0; 55 56 private boolean mSync = true; 57 58 private final ServiceConnection mConnection = new ServiceConnection() { 59 // Called when the connection with the service is established 60 public void onServiceConnected(ComponentName className, IBinder service) { 61 Log.d(TAG, "Service Connected"); 62 synchronized (mLock) { 63 mIAttachEmbeddedWindow = IAttachEmbeddedWindow.Stub.asInterface(service); 64 } 65 loadEmbedded(); 66 } 67 68 public void onServiceDisconnected(ComponentName className) { 69 Log.d(TAG, "Service Disconnected"); 70 mIAttachEmbeddedWindow = null; 71 } 72 }; 73 onCreate(Bundle savedInstanceState)74 protected void onCreate(Bundle savedInstanceState) { 75 FrameLayout content = new FrameLayout(this); 76 super.onCreate(savedInstanceState); 77 mSv = new SurfaceView(this); 78 Button button = new Button(this); 79 Switch enableSyncButton = new Switch(this); 80 content.addView(mSv, new FrameLayout.LayoutParams( 81 mSizes[0].x, mSizes[0].y, Gravity.CENTER_HORIZONTAL | Gravity.TOP)); 82 content.addView(button, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 83 ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM)); 84 content.addView(enableSyncButton, 85 new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 86 ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.RIGHT | Gravity.BOTTOM)); 87 setContentView(content); 88 89 mSv.setZOrderOnTop(false); 90 mSv.getHolder().addCallback(this); 91 92 button.setText("Change Size"); 93 enableSyncButton.setText("Enable Sync"); 94 enableSyncButton.setChecked(true); 95 button.setOnClickListener(v -> { 96 resize(); 97 }); 98 99 enableSyncButton.setOnCheckedChangeListener((buttonView, isChecked) -> { 100 mSync = isChecked; 101 }); 102 103 Intent intent = new Intent(this, EmbeddedWindowService.class); 104 intent.setAction(IAttachEmbeddedWindow.class.getName()); 105 Log.d(TAG, "bindService"); 106 bindService(intent, mConnection, Context.BIND_AUTO_CREATE); 107 } 108 resize()109 private void resize() { 110 if (mSurfacePackage == null) { 111 return; 112 } 113 Point size = mSizes[mLastSizeIndex % mSizes.length]; 114 115 Runnable svResizeRunnable = () -> { 116 mSv.getLayoutParams().width = size.x; 117 mSv.getLayoutParams().height = size.y; 118 mSv.requestLayout(); 119 }; 120 121 Runnable resizeRunnable = () -> { 122 try { 123 final WindowManager.LayoutParams lp = 124 new WindowManager.LayoutParams(size.x, size.y, 125 WindowManager.LayoutParams.TYPE_APPLICATION, 0, 126 PixelFormat.TRANSPARENT); 127 mIAttachEmbeddedWindow.relayout(lp); 128 } catch (RemoteException e) { 129 } 130 }; 131 132 if (mSync) { 133 SurfaceSyncGroup syncGroup = new SurfaceSyncGroup(TAG); 134 syncGroup.add(getWindow().getRootSurfaceControl(), svResizeRunnable); 135 syncGroup.add(mSurfacePackage, resizeRunnable); 136 syncGroup.markSyncReady(); 137 } else { 138 svResizeRunnable.run(); 139 resizeRunnable.run(); 140 } 141 142 mLastSizeIndex++; 143 } 144 145 @Override surfaceCreated(SurfaceHolder holder)146 public void surfaceCreated(SurfaceHolder holder) { 147 synchronized (mLock) { 148 mSurfaceCreated = true; 149 } 150 attachEmbedded(); 151 } 152 isReadyToAttach()153 private boolean isReadyToAttach() { 154 synchronized (mLock) { 155 if (!mSurfaceCreated) { 156 Log.d(TAG, "surface is not created"); 157 } 158 if (mIAttachEmbeddedWindow == null) { 159 Log.d(TAG, "Service is not attached"); 160 } 161 if (mIsAttached) { 162 Log.d(TAG, "Already attached"); 163 } 164 165 return mSurfaceCreated && mIAttachEmbeddedWindow != null && !mIsAttached 166 && mSurfacePackage != null; 167 } 168 } 169 loadEmbedded()170 private void loadEmbedded() { 171 try { 172 mIAttachEmbeddedWindow.attachEmbedded(mSv.getHostToken(), mSizes[0].x, mSizes[0].y, 173 new IAttachEmbeddedWindowCallback.Stub() { 174 @Override 175 public void onEmbeddedWindowAttached(SurfacePackage surfacePackage) { 176 getMainThreadHandler().post(() -> { 177 mSurfacePackage = surfacePackage; 178 attachEmbedded(); 179 }); 180 } 181 }); 182 mLastSizeIndex++; 183 } catch (RemoteException e) { 184 } 185 } 186 attachEmbedded()187 private void attachEmbedded() { 188 if (!isReadyToAttach()) { 189 return; 190 } 191 192 synchronized (mLock) { 193 mIsAttached = true; 194 } 195 mSv.setChildSurfacePackage(mSurfacePackage); 196 } 197 198 @Override surfaceChanged(SurfaceHolder holder, int format, int width, int height)199 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 200 } 201 202 @Override surfaceDestroyed(SurfaceHolder holder)203 public void surfaceDestroyed(SurfaceHolder holder) { 204 synchronized (mLock) { 205 mSurfaceCreated = false; 206 } 207 } 208 209 @Override onStart()210 protected void onStart() { 211 super.onStart(); 212 Log.d(TAG, "onStart"); 213 resize(); 214 } 215 } 216