• 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.server.wm.scvh;
18 
19 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
20 
21 import android.app.Service;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.graphics.Color;
25 import android.graphics.PixelFormat;
26 import android.hardware.display.DisplayManager;
27 import android.os.Handler;
28 import android.os.IBinder;
29 import android.os.Looper;
30 import android.util.Log;
31 import android.view.Display;
32 import android.view.SurfaceControl.Transaction;
33 import android.view.SurfaceControlViewHost;
34 import android.view.View;
35 import android.view.WindowManager;
36 import android.widget.FrameLayout;
37 import android.widget.TextView;
38 
39 import androidx.annotation.NonNull;
40 import androidx.annotation.Nullable;
41 
42 import java.util.concurrent.CountDownLatch;
43 import java.util.concurrent.TimeUnit;
44 
45 public class EmbeddedSCVHService extends Service {
46     private static final String TAG = "SCVHEmbeddedService";
47     private SurfaceControlViewHost mVr;
48 
49     private Handler mHandler;
50 
51     private SlowView mSlowView;
52 
53     @Override
onCreate()54     public void onCreate() {
55         super.onCreate();
56         mHandler = new Handler(Looper.getMainLooper());
57     }
58 
59     @Nullable
60     @Override
onBind(Intent intent)61     public IBinder onBind(Intent intent) {
62         // Return the interface
63         return new AttachEmbeddedWindow();
64     }
65 
66     public static class SlowView extends TextView {
67         private long mDelayMs;
68 
SlowView(Context context)69         public SlowView(Context context) {
70             super(context);
71         }
72 
73         @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)74         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
75             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
76             try {
77                 Thread.sleep(mDelayMs);
78             } catch (InterruptedException e) {
79             }
80         }
81 
setDelay(long delayMs)82         public void setDelay(long delayMs) {
83             mDelayMs = delayMs;
84         }
85     }
86 
87     private class AttachEmbeddedWindow extends IAttachEmbeddedWindow.Stub {
88         @Override
attachEmbedded(IBinder hostToken, int width, int height, int displayId, long delayMs)89         public SurfaceControlViewHost.SurfacePackage attachEmbedded(IBinder hostToken, int width,
90                 int height, int displayId, long delayMs) {
91             CountDownLatch countDownLatch = new CountDownLatch(1);
92             mHandler.post(() -> {
93                 Context context = EmbeddedSCVHService.this;
94                 Display display = getApplicationContext().getSystemService(
95                         DisplayManager.class).getDisplay(displayId);
96                 mVr = new SurfaceControlViewHost(context, display, hostToken);
97                 FrameLayout content = new FrameLayout(context);
98 
99                 mSlowView = new SlowView(context);
100                 mSlowView.setDelay(delayMs);
101                 mSlowView.setBackgroundColor(Color.BLUE);
102                 mSlowView.setTextColor(Color.WHITE);
103                 content.addView(mSlowView);
104                 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
105                         TYPE_APPLICATION, 0, PixelFormat.OPAQUE);
106                 lp.setTitle("EmbeddedWindow");
107                 mVr.setView(content, lp);
108 
109                 content.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
110                     @Override
111                     public void onViewAttachedToWindow(@NonNull View v) {
112                         // First frame isn't included in the sync so don't notify the host about the
113                         // surface package until the first draw has completed.
114                         Transaction transaction = new Transaction().addTransactionCommittedListener(
115                                 getMainExecutor(), countDownLatch::countDown);
116                         v.getRootSurfaceControl().applyTransactionOnDraw(transaction);
117                     }
118 
119                     @Override
120                     public void onViewDetachedFromWindow(@NonNull View v) {
121                     }
122                 });
123             });
124             try {
125                 countDownLatch.await(5, TimeUnit.SECONDS);
126             } catch (InterruptedException e) {
127                 Log.e(TAG, "Failed to wait for timeout");
128             }
129             return mVr.getSurfacePackage();
130         }
131 
132         @Override
relayout(WindowManager.LayoutParams lp)133         public void relayout(WindowManager.LayoutParams lp) {
134             Runnable runnable = () -> {
135                 mSlowView.setText(lp.width + "x" + lp.height);
136                 mVr.relayout(lp);
137             };
138 
139             if (Thread.currentThread() == mHandler.getLooper().getThread()) {
140                 runnable.run();
141             } else {
142                 mHandler.post(runnable);
143             }
144 
145         }
146 
147         @Override
sendCrash()148         public void sendCrash() {
149             mVr.getView().getViewTreeObserver().addOnPreDrawListener(() -> {
150                 throw new RuntimeException();
151             });
152         }
153     }
154 }
155