• 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 android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.ServiceConnection;
23 import android.os.Handler;
24 import android.os.HandlerThread;
25 import android.os.IBinder;
26 import android.os.RemoteException;
27 import android.util.Log;
28 import android.util.Size;
29 import android.view.SurfaceControlViewHost;
30 import android.view.SurfaceHolder;
31 import android.view.SurfaceView;
32 import android.view.ViewGroup;
33 
34 import androidx.annotation.NonNull;
35 
36 import java.util.concurrent.CountDownLatch;
37 
38 public class SurfaceControlViewHostHelper {
39     private final String mTag;
40 
41     private final Object mLock = new Object();
42     private boolean mIsAttached;
43 
44     private IAttachEmbeddedWindow mIAttachEmbeddedWindow;
45 
46     private SurfaceView mSurfaceView;
47 
48     private final int mDisplayId;
49 
50     private final long mDelayMs;
51     private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
52 
53     private final Size mInitialSize;
54 
55     private boolean mSurfaceCreated;
56 
57     private final CountDownLatch mReadyLatch;
58 
59     private final Context mContext;
60 
61     HandlerThread mHandlerThread;
62 
SurfaceControlViewHostHelper(String tag, CountDownLatch countDownLatch, Context context, long delayMs, Size initialSize)63     public SurfaceControlViewHostHelper(String tag, CountDownLatch countDownLatch, Context context,
64             long delayMs, Size initialSize) {
65         mTag = tag;
66         mContext = context;
67         mDisplayId = context.getDisplayId();
68         mDelayMs = delayMs;
69         mInitialSize = initialSize;
70         mReadyLatch = countDownLatch;
71         mHandlerThread = new HandlerThread("SurfaceControlViewHostHelper");
72         mHandlerThread.start();
73     }
74 
attachSurfaceView(ViewGroup parent, ViewGroup.LayoutParams layoutParams)75     public SurfaceView attachSurfaceView(ViewGroup parent, ViewGroup.LayoutParams layoutParams) {
76         mSurfaceView = new SurfaceView(mContext);
77         mSurfaceView.getHolder().addCallback(mCallback);
78         parent.addView(mSurfaceView, layoutParams);
79         return mSurfaceView;
80     }
81 
82     private final ServiceConnection mConnection = new ServiceConnection() {
83         // Called when the connection with the service is established
84         public void onServiceConnected(ComponentName className, IBinder service) {
85             Log.d(mTag, "Service Connected");
86             mIAttachEmbeddedWindow = IAttachEmbeddedWindow.Stub.asInterface(service);
87             if (isReadyToAttach()) {
88                 attachEmbedded();
89             }
90         }
91 
92         public void onServiceDisconnected(ComponentName className) {
93             Log.d(mTag, "Service Disconnected");
94             mIAttachEmbeddedWindow = null;
95             synchronized (mLock) {
96                 mIsAttached = false;
97             }
98         }
99     };
100 
101     final SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {
102         @Override
103         public void surfaceCreated(@NonNull SurfaceHolder holder) {
104             Log.d(mTag, "surface created");
105             synchronized (mLock) {
106                 mSurfaceCreated = true;
107             }
108             if (isReadyToAttach()) {
109                 attachEmbedded();
110             }
111         }
112 
113         @Override
114         public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
115                 int height) {
116         }
117 
118         @Override
119         public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
120         }
121     };
122 
isReadyToAttach()123     private boolean isReadyToAttach() {
124         synchronized (mLock) {
125             if (!mSurfaceCreated) {
126                 Log.d(mTag, "surface is not created");
127             }
128             if (mIAttachEmbeddedWindow == null) {
129                 Log.d(mTag, "Service is not attached");
130             }
131             if (mIsAttached) {
132                 Log.d(mTag, "Already attached");
133             }
134 
135             return mSurfaceCreated && mIAttachEmbeddedWindow != null && !mIsAttached;
136         }
137     }
138 
attachEmbedded()139     private void attachEmbedded() {
140         synchronized (mLock) {
141             mIsAttached = true;
142         }
143         Handler handler = new Handler(mHandlerThread.getLooper());
144         handler.post(() -> {
145             try {
146                 mSurfacePackage = mIAttachEmbeddedWindow.attachEmbedded(mSurfaceView.getHostToken(),
147                         mInitialSize.getWidth(), mInitialSize.getHeight(), mDisplayId, mDelayMs);
148                 mSurfaceView.setChildSurfacePackage(mSurfacePackage);
149             } catch (RemoteException e) {
150                 Log.e(mTag, "Failed to attach embedded window");
151             }
152 
153             mReadyLatch.countDown();
154         });
155     }
156 
getSurfacePackage()157     public SurfaceControlViewHost.SurfacePackage getSurfacePackage() {
158         return mSurfacePackage;
159     }
160 
getAttachedEmbeddedWindow()161     public IAttachEmbeddedWindow getAttachedEmbeddedWindow() {
162         return mIAttachEmbeddedWindow;
163     }
164 
bindEmbeddedService(boolean inProcess)165     public void bindEmbeddedService(boolean inProcess) {
166         Class<? extends EmbeddedSCVHService> classToBind;
167         if (inProcess) {
168             classToBind = InProcessEmbeddedSCVHService.class;
169         } else {
170             classToBind = EmbeddedSCVHService.class;
171         }
172         Intent intent = new Intent(mContext, classToBind);
173         intent.setAction(classToBind.getName());
174         mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
175     }
176 
177     // Use this one for in process requests.
178     public static class InProcessEmbeddedSCVHService extends EmbeddedSCVHService {
179     }
180 }
181