···77 * @ingroup ipc_android
88 */
991010-1110package org.freedesktop.monado.ipc;
12111312import android.app.Activity;
···37363837/**
3938 * Provides the client-side code to initiate connection to Monado IPC service.
4040- * <p>
4141- * This class will get loaded into the OpenXR client application by our native code.
3939+ *
4040+ * <p>This class will get loaded into the OpenXR client application by our native code.
4241 */
4342@Keep
4443public class Client implements ServiceConnection {
4544 private static final String TAG = "monado-ipc-client";
4646- /**
4747- * Used to block until binder is ready.
4848- */
4545+ /** Used to block until binder is ready. */
4946 private final Object binderSync = new Object();
5050- /**
5151- * Keep track of the ipc_client_android instance over on the native side.
5252- */
4747+ /** Keep track of the ipc_client_android instance over on the native side. */
5348 private final NativeCounterpart nativeCounterpart;
5449 /**
5555- * Pointer to local IPC proxy: calling methods on it automatically transports arguments across binder IPC.
5656- * <p>
5757- * May be null!
5050+ * Pointer to local IPC proxy: calling methods on it automatically transports arguments across
5151+ * binder IPC.
5252+ *
5353+ * <p>May be null!
5854 */
5959- @Keep
6060- public IMonado monado = null;
5555+ @Keep public IMonado monado = null;
6156 /**
6257 * Indicates that we tried to connect but failed.
6363- * <p>
6464- * Used to distinguish a "not yet fully connected" null monado member from a "tried and failed"
6565- * null monado member.
5858+ *
5959+ * <p>Used to distinguish a "not yet fully connected" null monado member from a "tried and
6060+ * failed" null monado member.
6661 */
6767- @Keep
6868- public boolean failed = false;
6262+ @Keep public boolean failed = false;
6963 /**
7070- * "Our" side of the socket pair - the other side is sent to the server automatically on connection.
6464+ * "Our" side of the socket pair - the other side is sent to the server automatically on
6565+ * connection.
7166 */
7267 private ParcelFileDescriptor fd = null;
7373- /**
7474- * Context provided by app.
7575- */
6868+ /** Context provided by app. */
7669 private Context context = null;
7777- /**
7878- * Context of the runtime package
7979- */
7070+ /** Context of the runtime package */
8071 private Context runtimePackageContext = null;
8181- /**
8282- * Control system ui visibility
8383- */
7272+ /** Control system ui visibility */
8473 private SystemUiController systemUiController = null;
85748675 /**
···11099 }
111100 }
112101113113- /**
114114- * Let the native code notify us that it is no longer using this class.
115115- */
102102+ /** Let the native code notify us that it is no longer using this class. */
116103 @Keep
117104 public void markAsDiscardedByNative() {
118105 nativeCounterpart.markAsDiscardedByNative(TAG);
···121108122109 /**
123110 * Bind to the Monado IPC service, and block until it is fully connected.
124124- * <p>
125125- * The IPC client code on Android should load this class (from the right package), instantiate
126126- * this class (retaining a reference to it!), and call this method.
127127- * <p>
128128- * This method must not be called from the main (UI) thread.
129111 *
130130- * @param context_ Context to use to make the connection. (We get the application context
131131- * from it.)
112112+ * <p>The IPC client code on Android should load this class (from the right package),
113113+ * instantiate this class (retaining a reference to it!), and call this method.
114114+ *
115115+ * <p>This method must not be called from the main (UI) thread.
116116+ *
117117+ * @param context_ Context to use to make the connection. (We get the application context from
118118+ * it.)
132119 * @param packageName The package name containing the Monado runtime. The caller is guaranteed
133133- * to know this because it had to load this class from that package.
134134- * There's a define in xrt_config_android.h to use for this.
120120+ * to know this because it had to load this class from that package. There's a define in
121121+ * xrt_config_android.h to use for this.
135122 * @return the fd number - do not close! (dup if you want to be able to close it) Returns -1 if
136136- * something went wrong.
137137- * <p>
138138- * Various builds, variants, etc. will have different package names, but we must specify the
139139- * package name explicitly to avoid violating security restrictions.
123123+ * something went wrong.
124124+ * <p>Various builds, variants, etc. will have different package names, but we must specify
125125+ * the package name explicitly to avoid violating security restrictions.
140126 */
141127 @Keep
142128 public int blockingConnect(Context context_, String packageName) {
···167153 // TODO: just initiate MonadoView attachment and add callback to native code to
168154 // notify about Surface status and pass it to OpenXR application as a Session lifecycle
169155 // (ready ... synchronized ... visible ... focused)
170170- new Thread(()-> {
171171- boolean surfaceCreated = false;
172172- Activity activity = null;
173173- if (context_ instanceof Activity) {
174174- activity = (Activity) context_;
175175- }
156156+ new Thread(
157157+ () -> {
158158+ boolean surfaceCreated = false;
159159+ Activity activity = null;
160160+ if (context_ instanceof Activity) {
161161+ activity = (Activity) context_;
162162+ }
176163177177- try {
178178- // Determine whether runtime or client should create surface
179179- if (monado.canDrawOverOtherApps()) {
180180- WindowManager wm = (WindowManager) context_.getSystemService(Context.WINDOW_SERVICE);
181181- surfaceCreated = monado.createSurface(wm.getDefaultDisplay().getDisplayId(), false);
182182- } else {
183183- if (activity != null) {
184184- Surface surface = attachViewAndGetSurface(activity);
185185- surfaceCreated = (surface != null);
186186- if (surfaceCreated) {
187187- monado.passAppSurface(surface);
188188- }
189189- }
190190- }
191191- } catch (RemoteException e) {
192192- e.printStackTrace();
193193- }
164164+ try {
165165+ // Determine whether runtime or client should create surface
166166+ if (monado.canDrawOverOtherApps()) {
167167+ WindowManager wm =
168168+ (WindowManager)
169169+ context_.getSystemService(
170170+ Context.WINDOW_SERVICE);
171171+ surfaceCreated =
172172+ monado.createSurface(
173173+ wm.getDefaultDisplay().getDisplayId(), false);
174174+ } else {
175175+ if (activity != null) {
176176+ Surface surface = attachViewAndGetSurface(activity);
177177+ surfaceCreated = (surface != null);
178178+ if (surfaceCreated) {
179179+ monado.passAppSurface(surface);
180180+ }
181181+ }
182182+ }
183183+ } catch (RemoteException e) {
184184+ e.printStackTrace();
185185+ }
194186195195- if (!surfaceCreated) {
196196- Log.e(TAG, "Failed to create surface");
197197- handleFailure();
198198- return;
199199- }
187187+ if (!surfaceCreated) {
188188+ Log.e(TAG, "Failed to create surface");
189189+ handleFailure();
190190+ return;
191191+ }
200192201201- if (activity != null) {
202202- systemUiController = new SystemUiController(activity);
203203- systemUiController.hide();
204204- }
205205- }).start();
193193+ if (activity != null) {
194194+ systemUiController = new SystemUiController(activity);
195195+ systemUiController.hide();
196196+ }
197197+ })
198198+ .start();
206199207200 // Create socket pair
208201 ParcelFileDescriptor theirs;
···233226 * Bind to the Monado IPC service - this asynchronously starts connecting (and launching the
234227 * service if it's not already running)
235228 *
236236- * @param context_ Context to use to make the connection. (We get the application context
237237- * from it.)
229229+ * @param context_ Context to use to make the connection. (We get the application context from
230230+ * it.)
238231 * @param packageName The package name containing the Monado runtime. The caller is guaranteed
239239- * to know this because it had to load this class from that package.
240240- * There's a define in xrt_config_android.h to use for this.
241241- * <p>
242242- * Various builds, variants, etc. will have different package names, but we
243243- * must specify the package name explicitly to avoid violating security
244244- * restrictions.
232232+ * to know this because it had to load this class from that package. There's a define in
233233+ * xrt_config_android.h to use for this.
234234+ * <p>Various builds, variants, etc. will have different package names, but we must specify
235235+ * the package name explicitly to avoid violating security restrictions.
245236 */
246237 public boolean bind(Context context_, String packageName) {
247238 Log.i(TAG, "bind");
···251242 context = context_;
252243 }
253244 try {
254254- runtimePackageContext = context.createPackageContext(packageName,
255255- Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
245245+ runtimePackageContext =
246246+ context.createPackageContext(
247247+ packageName,
248248+ Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
256249 } catch (PackageManager.NameNotFoundException e) {
257250 e.printStackTrace();
258251 Log.e(TAG, "bind: Could not find package " + packageName);
259252 return false;
260253 }
261254262262- Intent intent = new Intent(BuildConfig.SERVICE_ACTION)
263263- .setPackage(packageName);
255255+ Intent intent = new Intent(BuildConfig.SERVICE_ACTION).setPackage(packageName);
264256265257 if (!bindService(context, intent)) {
266266- Log.e(TAG,
267267- "bindService: Service " + intent + " could not be found to bind!");
258258+ Log.e(TAG, "bindService: Service " + intent + " could not be found to bind!");
268259 return false;
269260 }
270261···276267 boolean result;
277268 int flags = Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | Context.BIND_ABOVE_CLIENT;
278269 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
279279- result = context.bindService(intent, flags | Context.BIND_INCLUDE_CAPABILITIES,
280280- Executors.newSingleThreadExecutor(), this);
270270+ result =
271271+ context.bindService(
272272+ intent,
273273+ flags | Context.BIND_INCLUDE_CAPABILITIES,
274274+ Executors.newSingleThreadExecutor(),
275275+ this);
281276 } else {
282277 result = context.bindService(intent, this, flags);
283278 }
···285280 return result;
286281 }
287282288288- /**
289289- * Some on-failure cleanup.
290290- */
283283+ /** Some on-failure cleanup. */
291284 private void handleFailure() {
292285 failed = true;
293286 shutdown();
294287 }
295288296296- @Nullable
297297- private Surface attachViewAndGetSurface(Activity activity) {
289289+ @Nullable private Surface attachViewAndGetSurface(Activity activity) {
298290 MonadoView monadoView = MonadoView.attachToActivity(activity);
299291 SurfaceHolder holder = monadoView.waitGetSurfaceHolder(2000);
300292 Surface surface = null;
···308300 /**
309301 * Handle the asynchronous connection of the binder IPC.
310302 *
311311- * @param name should match the preceding intent, but not used.
303303+ * @param name should match the preceding intent, but not used.
312304 * @param service the associated service, which we cast in this function.
313305 */
314306 @Override
···330322 public void onServiceDisconnected(ComponentName name) {
331323 Log.i(TAG, "onServiceDisconnected");
332324 shutdown();
333333- //! @todo tell C/C++ that the world is crumbling, then close the fd here.
325325+ // ! @todo tell C/C++ that the world is crumbling, then close the fd here.
334326 }
335327336328 /*
···77 * @ingroup ipc_android
88 */
991010-1110package org.freedesktop.monado.ipc;
12111312import android.os.ParcelFileDescriptor;
···23222423/**
2524 * Java implementation of the IMonado IPC interface.
2626- * <p>
2727- * (This is the server-side code.)
2828- * <p>
2929- * All this does is delegate calls to native JNI implementations.
3030- * The warning suppression is because Android Studio tends to have a hard time finding
3131- * the (very real) implementations of these in service-lib.
2525+ *
2626+ * <p>(This is the server-side code.)
2727+ *
2828+ * <p>All this does is delegate calls to native JNI implementations. The warning suppression is
2929+ * because Android Studio tends to have a hard time finding the (very real) implementations of these
3030+ * in service-lib.
3231 */
3332@Keep
3433public class MonadoImpl extends IMonado.Stub {
···45444645 public MonadoImpl(@NonNull SurfaceManager surfaceManager) {
4746 this.surfaceManager = surfaceManager;
4848- this.surfaceManager.setCallback(new SurfaceHolder.Callback() {
4949- @Override
5050- public void surfaceCreated(@NonNull SurfaceHolder holder) {
5151- Log.i(TAG, "surfaceCreated");
5252- passAppSurface(holder.getSurface());
5353- }
4747+ this.surfaceManager.setCallback(
4848+ new SurfaceHolder.Callback() {
4949+ @Override
5050+ public void surfaceCreated(@NonNull SurfaceHolder holder) {
5151+ Log.i(TAG, "surfaceCreated");
5252+ passAppSurface(holder.getSurface());
5353+ }
54545555- @Override
5656- public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
5757- }
5555+ @Override
5656+ public void surfaceChanged(
5757+ @NonNull SurfaceHolder holder, int format, int width, int height) {}
58585959- @Override
6060- public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
6161- }
6262- });
5959+ @Override
6060+ public void surfaceDestroyed(@NonNull SurfaceHolder holder) {}
6161+ });
6362 }
64636564 @Override
···111110 nativeShutdownServer();
112111 }
113112114114- /**
115115- * Native method that starts server.
116116- */
113113+ /** Native method that starts server. */
117114 @SuppressWarnings("JavaJniMissingFunction")
118115 private native void nativeStartServer();
119116120117 /**
121118 * Native handling of receiving a surface: should convert it to an ANativeWindow then do stuff
122119 * with it.
123123- * <p>
124124- * Ignore warnings that this function is missing: it is not, it is just in a different module.
125125- * See `src/xrt/targets/service-lib/service_target.cpp` for the implementation.
120120+ *
121121+ * <p>Ignore warnings that this function is missing: it is not, it is just in a different
122122+ * module. See `src/xrt/targets/service-lib/service_target.cpp` for the implementation.
126123 *
127124 * @param surface The surface to pass to native code
128125 * @todo figure out a good way to have a client ID
···133130 /**
134131 * Native handling of receiving an FD for a new client: the FD should be used to start up the
135132 * rest of the native IPC code on that socket.
136136- * <p>
137137- * This is essentially the entry point for the monado service on Android: if it's already
133133+ *
134134+ * <p>This is essentially the entry point for the monado service on Android: if it's already
138135 * running, this will be called in it. If it's not already running, a process will be created,
139136 * and this will be the first native code executed in that process.
140140- * <p>
141141- * Ignore warnings that this function is missing: it is not, it is just in a different module.
142142- * See `src/xrt/targets/service-lib/service_target.cpp` for the implementation.
137137+ *
138138+ * <p>Ignore warnings that this function is missing: it is not, it is just in a different
139139+ * module. See `src/xrt/targets/service-lib/service_target.cpp` for the implementation.
143140 *
144141 * @param fd The incoming file descriptor: ownership is transferred to native code here.
145142 * @return 0 on success, anything else means the fd wasn't sent and ownership not transferred.
···2424import java.util.concurrent.locks.Condition
2525import java.util.concurrent.locks.ReentrantLock
26262727-/**
2828- * Class that creates/manages surface on display.
2929- */
2727+/** Class that creates/manages surface on display. */
3028class SurfaceManager(context: Context) : SurfaceHolder.Callback {
3129 private val appContext: Context = context.applicationContext
3230 private val surfaceLock: ReentrantLock = ReentrantLock()
···109107 /**
110108 * Check if current process has the capability to draw over other applications.
111109 *
112112- * Implementation of [Settings.canDrawOverlays] checks both context and UID,
113113- * therefore this cannot be done in client side.
110110+ * Implementation of [Settings.canDrawOverlays] checks both context and UID, therefore this
111111+ * cannot be done in client side.
114112 *
115113 * @return True if current process can draw over other applications; otherwise false.
116114 */
···118116 return Settings.canDrawOverlays(appContext)
119117 }
120118121121- /**
122122- * Destroy created surface.
123123- */
119119+ /** Destroy created surface. */
124120 fun destroySurface() {
125121 viewHelper.removeView()
126122 }
127123128128- /**
129129- * Helper class that manages surface view.
130130- */
124124+ /** Helper class that manages surface view. */
131125 private class ViewHelper(private val callback: SurfaceHolder.Callback) {
132126 private var view: SurfaceView? = null
133127 private var displayContext: Context? = null
···162156 }
163157 }
164158165165- /**
166166- * Check whether given display is the one being used right now.
167167- */
159159+ /** Check whether given display is the one being used right now. */
168160 @Suppress("DEPRECATION")
169161 private fun isSameDisplay(context: Context, display: Display): Boolean {
170162 val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
···186178 lp.flags = if (focusable) VIEW_FLAG_FOCUSABLE else VIEW_FLAG_NOT_FOCUSABLE
187179 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
188180 lp.layoutInDisplayCutoutMode =
189189- WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
181181+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
190182 }
191183192184 val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
···212204 @Suppress("DEPRECATION")
213205 private const val VIEW_FLAG_NOT_FOCUSABLE =
214206 WindowManager.LayoutParams.FLAG_FULLSCREEN or
215215- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
207207+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
216208 }
217209 }
218210219211 companion object {
220212 private const val TAG = "SurfaceManager"
221213 }
222222-223214}
···1313import android.os.Message
1414import java.util.concurrent.atomic.AtomicInteger
15151616-/**
1717- * Client watchdog, to determine whether runtime service should be stopped.
1818- */
1616+/** Client watchdog, to determine whether runtime service should be stopped. */
1917class Watchdog(
2018 private val shutdownDelayMilliseconds: Long,
2119 private val shutdownListener: ShutdownListener
···2523 * all the callbacks run on background thread.
2624 */
2725 interface ShutdownListener {
2828- /**
2929- * Callback to be invoked when last client disconnected.
3030- */
2626+ /** Callback to be invoked when last client disconnected. */
3127 fun onPrepareShutdown()
32283333- /**
3434- * Callback to be invoked when shutdown delay ended and there's no new client connected.
3535- */
2929+ /** Callback to be invoked when shutdown delay ended and there's no new client connected. */
3630 fun onShutdown()
3731 }
3832···4539 fun startMonitor() {
4640 shutdownThread = HandlerThread("monado-client-watchdog")
4741 shutdownThread.start()
4848- shutdownHandler = object : Handler(shutdownThread.looper) {
4949- override fun handleMessage(msg: Message) {
5050- when (msg.what) {
5151- MSG_SHUTDOWN -> if (clientCount.get() == 0) {
5252- shutdownListener.onShutdown()
4242+ shutdownHandler =
4343+ object : Handler(shutdownThread.looper) {
4444+ override fun handleMessage(msg: Message) {
4545+ when (msg.what) {
4646+ MSG_SHUTDOWN ->
4747+ if (clientCount.get() == 0) {
4848+ shutdownListener.onShutdown()
4949+ }
5350 }
5451 }
5552 }
5656- }
5753 }
58545955 fun stopMonitor() {