1 /* 2 * Copyright 2024 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.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.Activity; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.ServiceConnection; 26 import android.graphics.Canvas; 27 import android.graphics.Color; 28 import android.graphics.Paint; 29 import android.graphics.Rect; 30 import android.os.Bundle; 31 import android.os.IBinder; 32 import android.os.RemoteException; 33 import android.util.Log; 34 import android.view.AttachedSurfaceControl; 35 import android.view.Choreographer; 36 import android.view.Gravity; 37 import android.view.Surface; 38 import android.view.SurfaceControl; 39 import android.view.SurfaceHolder; 40 import android.view.SurfaceView; 41 import android.view.ViewTreeObserver; 42 import android.view.WindowManager; 43 import android.widget.LinearLayout; 44 45 /** 46 * Used to manually test that {@link android.view.SurfaceControlInputReceiver} API works. 47 */ 48 public class SurfaceInputTestActivity extends Activity { 49 50 private static final String TAG = "SurfaceInputTestActivity"; 51 private SurfaceView mLocalSurfaceView; 52 private SurfaceView mRemoteSurfaceView; 53 private IAttachEmbeddedWindow mIAttachEmbeddedWindow; 54 private SurfaceControl mParentSurfaceControl; 55 56 private SurfaceControl mLocalSurfaceControl; 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 mIAttachEmbeddedWindow = IAttachEmbeddedWindow.Stub.asInterface(service); 63 loadEmbedded(); 64 } 65 66 public void onServiceDisconnected(ComponentName className) { 67 Log.d(TAG, "Service Disconnected"); 68 mIAttachEmbeddedWindow = null; 69 } 70 }; 71 72 @Override onAttachedToWindow()73 public void onAttachedToWindow() { 74 super.onAttachedToWindow(); 75 ViewTreeObserver viewTreeObserver = getWindow().getDecorView().getViewTreeObserver(); 76 viewTreeObserver.addOnPreDrawListener( 77 new ViewTreeObserver.OnPreDrawListener() { 78 @Override 79 public boolean onPreDraw() { 80 addLocalChildSurfaceControl(getWindow().getRootSurfaceControl()); 81 viewTreeObserver.removeOnPreDrawListener(this); 82 return true; 83 } 84 }); 85 } 86 87 @Override onCreate(@ullable Bundle savedInstanceState)88 protected void onCreate(@Nullable Bundle savedInstanceState) { 89 super.onCreate(savedInstanceState); 90 LinearLayout content = new LinearLayout(this); 91 mLocalSurfaceView = new SurfaceView(this); 92 content.addView(mLocalSurfaceView, new LinearLayout.LayoutParams( 93 500, 500, Gravity.CENTER_HORIZONTAL | Gravity.TOP)); 94 95 mRemoteSurfaceView = new SurfaceView(this); 96 content.addView(mRemoteSurfaceView, new LinearLayout.LayoutParams( 97 500, 500, Gravity.CENTER_HORIZONTAL | Gravity.TOP)); 98 99 setContentView(content); 100 101 mLocalSurfaceView.setZOrderOnTop(true); 102 mLocalSurfaceView.getHolder().addCallback(mLocalSurfaceViewCallback); 103 104 mRemoteSurfaceView.setZOrderOnTop(true); 105 mRemoteSurfaceView.getHolder().addCallback(mRemoteSurfaceViewHolder); 106 107 Intent intent = new Intent(this, EmbeddedWindowService.class); 108 intent.setAction(IAttachEmbeddedWindow.class.getName()); 109 Log.d(TAG, "bindService"); 110 bindService(intent, mConnection, Context.BIND_AUTO_CREATE); 111 } 112 113 @Override onDestroy()114 protected void onDestroy() { 115 super.onDestroy(); 116 if (mLocalSurfaceControl != null) { 117 getWindowManager().unregisterSurfaceControlInputReceiver(mLocalSurfaceControl); 118 new SurfaceControl.Transaction().remove(mLocalSurfaceControl).apply(); 119 } 120 } 121 addLocalChildSurfaceControl(AttachedSurfaceControl attachedSurfaceControl)122 private void addLocalChildSurfaceControl(AttachedSurfaceControl attachedSurfaceControl) { 123 mLocalSurfaceControl = new SurfaceControl.Builder().setName("LocalSC") 124 .setBufferSize(100, 100).build(); 125 attachedSurfaceControl.buildReparentTransaction(mLocalSurfaceControl) 126 .setVisibility(mLocalSurfaceControl, true) 127 .setCrop(mLocalSurfaceControl, new Rect(0, 0, 100, 100)) 128 .setPosition(mLocalSurfaceControl, 250, 1000) 129 .setLayer(mLocalSurfaceControl, 1).apply(); 130 131 Paint paint = new Paint(); 132 paint.setColor(Color.WHITE); 133 paint.setTextSize(20); 134 135 Surface surface = new Surface(mLocalSurfaceControl); 136 Canvas c = surface.lockCanvas(null); 137 c.drawColor(Color.GREEN); 138 c.drawText("Local SC", 0, 0, paint); 139 surface.unlockCanvasAndPost(c); 140 WindowManager wm = getSystemService(WindowManager.class); 141 wm.registerBatchedSurfaceControlInputReceiver( 142 attachedSurfaceControl.getInputTransferToken(), mLocalSurfaceControl, 143 Choreographer.getInstance(), event -> { 144 Log.d(TAG, "onInputEvent-sc " + event); 145 return false; 146 }); 147 } 148 149 private final SurfaceHolder.Callback mLocalSurfaceViewCallback = new SurfaceHolder.Callback() { 150 @Override 151 public void surfaceCreated(@NonNull SurfaceHolder holder) { 152 Paint paint = new Paint(); 153 paint.setColor(Color.WHITE); 154 paint.setTextSize(40); 155 156 Canvas c = holder.lockCanvas(); 157 c.drawColor(Color.RED); 158 c.drawText("Local", 250, 250, paint); 159 holder.unlockCanvasAndPost(c); 160 161 WindowManager wm = getSystemService(WindowManager.class); 162 wm.registerBatchedSurfaceControlInputReceiver( 163 mLocalSurfaceView.getRootSurfaceControl().getInputTransferToken(), 164 mLocalSurfaceView.getSurfaceControl(), 165 Choreographer.getInstance(), event -> { 166 Log.d(TAG, "onInputEvent-local " + event); 167 return false; 168 }); 169 } 170 171 @Override 172 public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, 173 int height) { 174 175 } 176 177 @Override 178 public void surfaceDestroyed(@NonNull SurfaceHolder holder) { 179 getWindowManager().unregisterSurfaceControlInputReceiver( 180 mLocalSurfaceView.getSurfaceControl()); 181 } 182 }; 183 184 private final SurfaceHolder.Callback mRemoteSurfaceViewHolder = new SurfaceHolder.Callback() { 185 @Override 186 public void surfaceCreated(@NonNull SurfaceHolder holder) { 187 mParentSurfaceControl = mRemoteSurfaceView.getSurfaceControl(); 188 loadEmbedded(); 189 } 190 191 @Override 192 public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, 193 int height) { 194 } 195 196 @Override 197 public void surfaceDestroyed(@NonNull SurfaceHolder holder) { 198 if (mIAttachEmbeddedWindow != null) { 199 try { 200 mIAttachEmbeddedWindow.tearDownEmbeddedSurfaceControl(); 201 } catch (RemoteException e) { 202 Log.e(TAG, "Failed to tear down embedded SurfaceControl", e); 203 } 204 } 205 } 206 }; 207 loadEmbedded()208 private void loadEmbedded() { 209 if (mParentSurfaceControl == null || mIAttachEmbeddedWindow == null) { 210 return; 211 } 212 try { 213 mIAttachEmbeddedWindow.attachEmbeddedSurfaceControl(mParentSurfaceControl, 214 getDisplayId(), 215 mRemoteSurfaceView.getRootSurfaceControl().getInputTransferToken()); 216 } catch (RemoteException e) { 217 Log.e(TAG, "Failed to load embedded SurfaceControl", e); 218 } 219 } 220 } 221