The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipc/android: Run spotlessApply to format Java and Kotlin code

+163 -188
+93 -101
src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Client.java
··· 7 7 * @ingroup ipc_android 8 8 */ 9 9 10 - 11 10 package org.freedesktop.monado.ipc; 12 11 13 12 import android.app.Activity; ··· 37 36 38 37 /** 39 38 * Provides the client-side code to initiate connection to Monado IPC service. 40 - * <p> 41 - * This class will get loaded into the OpenXR client application by our native code. 39 + * 40 + * <p>This class will get loaded into the OpenXR client application by our native code. 42 41 */ 43 42 @Keep 44 43 public class Client implements ServiceConnection { 45 44 private static final String TAG = "monado-ipc-client"; 46 - /** 47 - * Used to block until binder is ready. 48 - */ 45 + /** Used to block until binder is ready. */ 49 46 private final Object binderSync = new Object(); 50 - /** 51 - * Keep track of the ipc_client_android instance over on the native side. 52 - */ 47 + /** Keep track of the ipc_client_android instance over on the native side. */ 53 48 private final NativeCounterpart nativeCounterpart; 54 49 /** 55 - * Pointer to local IPC proxy: calling methods on it automatically transports arguments across binder IPC. 56 - * <p> 57 - * May be null! 50 + * Pointer to local IPC proxy: calling methods on it automatically transports arguments across 51 + * binder IPC. 52 + * 53 + * <p>May be null! 58 54 */ 59 - @Keep 60 - public IMonado monado = null; 55 + @Keep public IMonado monado = null; 61 56 /** 62 57 * Indicates that we tried to connect but failed. 63 - * <p> 64 - * Used to distinguish a "not yet fully connected" null monado member from a "tried and failed" 65 - * null monado member. 58 + * 59 + * <p>Used to distinguish a "not yet fully connected" null monado member from a "tried and 60 + * failed" null monado member. 66 61 */ 67 - @Keep 68 - public boolean failed = false; 62 + @Keep public boolean failed = false; 69 63 /** 70 - * "Our" side of the socket pair - the other side is sent to the server automatically on connection. 64 + * "Our" side of the socket pair - the other side is sent to the server automatically on 65 + * connection. 71 66 */ 72 67 private ParcelFileDescriptor fd = null; 73 - /** 74 - * Context provided by app. 75 - */ 68 + /** Context provided by app. */ 76 69 private Context context = null; 77 - /** 78 - * Context of the runtime package 79 - */ 70 + /** Context of the runtime package */ 80 71 private Context runtimePackageContext = null; 81 - /** 82 - * Control system ui visibility 83 - */ 72 + /** Control system ui visibility */ 84 73 private SystemUiController systemUiController = null; 85 74 86 75 /** ··· 110 99 } 111 100 } 112 101 113 - /** 114 - * Let the native code notify us that it is no longer using this class. 115 - */ 102 + /** Let the native code notify us that it is no longer using this class. */ 116 103 @Keep 117 104 public void markAsDiscardedByNative() { 118 105 nativeCounterpart.markAsDiscardedByNative(TAG); ··· 121 108 122 109 /** 123 110 * Bind to the Monado IPC service, and block until it is fully connected. 124 - * <p> 125 - * The IPC client code on Android should load this class (from the right package), instantiate 126 - * this class (retaining a reference to it!), and call this method. 127 - * <p> 128 - * This method must not be called from the main (UI) thread. 129 111 * 130 - * @param context_ Context to use to make the connection. (We get the application context 131 - * from it.) 112 + * <p>The IPC client code on Android should load this class (from the right package), 113 + * instantiate this class (retaining a reference to it!), and call this method. 114 + * 115 + * <p>This method must not be called from the main (UI) thread. 116 + * 117 + * @param context_ Context to use to make the connection. (We get the application context from 118 + * it.) 132 119 * @param packageName The package name containing the Monado runtime. The caller is guaranteed 133 - * to know this because it had to load this class from that package. 134 - * There's a define in xrt_config_android.h to use for this. 120 + * to know this because it had to load this class from that package. There's a define in 121 + * xrt_config_android.h to use for this. 135 122 * @return the fd number - do not close! (dup if you want to be able to close it) Returns -1 if 136 - * something went wrong. 137 - * <p> 138 - * Various builds, variants, etc. will have different package names, but we must specify the 139 - * package name explicitly to avoid violating security restrictions. 123 + * something went wrong. 124 + * <p>Various builds, variants, etc. will have different package names, but we must specify 125 + * the package name explicitly to avoid violating security restrictions. 140 126 */ 141 127 @Keep 142 128 public int blockingConnect(Context context_, String packageName) { ··· 167 153 // TODO: just initiate MonadoView attachment and add callback to native code to 168 154 // notify about Surface status and pass it to OpenXR application as a Session lifecycle 169 155 // (ready ... synchronized ... visible ... focused) 170 - new Thread(()-> { 171 - boolean surfaceCreated = false; 172 - Activity activity = null; 173 - if (context_ instanceof Activity) { 174 - activity = (Activity) context_; 175 - } 156 + new Thread( 157 + () -> { 158 + boolean surfaceCreated = false; 159 + Activity activity = null; 160 + if (context_ instanceof Activity) { 161 + activity = (Activity) context_; 162 + } 176 163 177 - try { 178 - // Determine whether runtime or client should create surface 179 - if (monado.canDrawOverOtherApps()) { 180 - WindowManager wm = (WindowManager) context_.getSystemService(Context.WINDOW_SERVICE); 181 - surfaceCreated = monado.createSurface(wm.getDefaultDisplay().getDisplayId(), false); 182 - } else { 183 - if (activity != null) { 184 - Surface surface = attachViewAndGetSurface(activity); 185 - surfaceCreated = (surface != null); 186 - if (surfaceCreated) { 187 - monado.passAppSurface(surface); 188 - } 189 - } 190 - } 191 - } catch (RemoteException e) { 192 - e.printStackTrace(); 193 - } 164 + try { 165 + // Determine whether runtime or client should create surface 166 + if (monado.canDrawOverOtherApps()) { 167 + WindowManager wm = 168 + (WindowManager) 169 + context_.getSystemService( 170 + Context.WINDOW_SERVICE); 171 + surfaceCreated = 172 + monado.createSurface( 173 + wm.getDefaultDisplay().getDisplayId(), false); 174 + } else { 175 + if (activity != null) { 176 + Surface surface = attachViewAndGetSurface(activity); 177 + surfaceCreated = (surface != null); 178 + if (surfaceCreated) { 179 + monado.passAppSurface(surface); 180 + } 181 + } 182 + } 183 + } catch (RemoteException e) { 184 + e.printStackTrace(); 185 + } 194 186 195 - if (!surfaceCreated) { 196 - Log.e(TAG, "Failed to create surface"); 197 - handleFailure(); 198 - return; 199 - } 187 + if (!surfaceCreated) { 188 + Log.e(TAG, "Failed to create surface"); 189 + handleFailure(); 190 + return; 191 + } 200 192 201 - if (activity != null) { 202 - systemUiController = new SystemUiController(activity); 203 - systemUiController.hide(); 204 - } 205 - }).start(); 193 + if (activity != null) { 194 + systemUiController = new SystemUiController(activity); 195 + systemUiController.hide(); 196 + } 197 + }) 198 + .start(); 206 199 207 200 // Create socket pair 208 201 ParcelFileDescriptor theirs; ··· 233 226 * Bind to the Monado IPC service - this asynchronously starts connecting (and launching the 234 227 * service if it's not already running) 235 228 * 236 - * @param context_ Context to use to make the connection. (We get the application context 237 - * from it.) 229 + * @param context_ Context to use to make the connection. (We get the application context from 230 + * it.) 238 231 * @param packageName The package name containing the Monado runtime. The caller is guaranteed 239 - * to know this because it had to load this class from that package. 240 - * There's a define in xrt_config_android.h to use for this. 241 - * <p> 242 - * Various builds, variants, etc. will have different package names, but we 243 - * must specify the package name explicitly to avoid violating security 244 - * restrictions. 232 + * to know this because it had to load this class from that package. There's a define in 233 + * xrt_config_android.h to use for this. 234 + * <p>Various builds, variants, etc. will have different package names, but we must specify 235 + * the package name explicitly to avoid violating security restrictions. 245 236 */ 246 237 public boolean bind(Context context_, String packageName) { 247 238 Log.i(TAG, "bind"); ··· 251 242 context = context_; 252 243 } 253 244 try { 254 - runtimePackageContext = context.createPackageContext(packageName, 255 - Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE); 245 + runtimePackageContext = 246 + context.createPackageContext( 247 + packageName, 248 + Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE); 256 249 } catch (PackageManager.NameNotFoundException e) { 257 250 e.printStackTrace(); 258 251 Log.e(TAG, "bind: Could not find package " + packageName); 259 252 return false; 260 253 } 261 254 262 - Intent intent = new Intent(BuildConfig.SERVICE_ACTION) 263 - .setPackage(packageName); 255 + Intent intent = new Intent(BuildConfig.SERVICE_ACTION).setPackage(packageName); 264 256 265 257 if (!bindService(context, intent)) { 266 - Log.e(TAG, 267 - "bindService: Service " + intent + " could not be found to bind!"); 258 + Log.e(TAG, "bindService: Service " + intent + " could not be found to bind!"); 268 259 return false; 269 260 } 270 261 ··· 276 267 boolean result; 277 268 int flags = Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | Context.BIND_ABOVE_CLIENT; 278 269 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 279 - result = context.bindService(intent, flags | Context.BIND_INCLUDE_CAPABILITIES, 280 - Executors.newSingleThreadExecutor(), this); 270 + result = 271 + context.bindService( 272 + intent, 273 + flags | Context.BIND_INCLUDE_CAPABILITIES, 274 + Executors.newSingleThreadExecutor(), 275 + this); 281 276 } else { 282 277 result = context.bindService(intent, this, flags); 283 278 } ··· 285 280 return result; 286 281 } 287 282 288 - /** 289 - * Some on-failure cleanup. 290 - */ 283 + /** Some on-failure cleanup. */ 291 284 private void handleFailure() { 292 285 failed = true; 293 286 shutdown(); 294 287 } 295 288 296 - @Nullable 297 - private Surface attachViewAndGetSurface(Activity activity) { 289 + @Nullable private Surface attachViewAndGetSurface(Activity activity) { 298 290 MonadoView monadoView = MonadoView.attachToActivity(activity); 299 291 SurfaceHolder holder = monadoView.waitGetSurfaceHolder(2000); 300 292 Surface surface = null; ··· 308 300 /** 309 301 * Handle the asynchronous connection of the binder IPC. 310 302 * 311 - * @param name should match the preceding intent, but not used. 303 + * @param name should match the preceding intent, but not used. 312 304 * @param service the associated service, which we cast in this function. 313 305 */ 314 306 @Override ··· 330 322 public void onServiceDisconnected(ComponentName name) { 331 323 Log.i(TAG, "onServiceDisconnected"); 332 324 shutdown(); 333 - //! @todo tell C/C++ that the world is crumbling, then close the fd here. 325 + // ! @todo tell C/C++ that the world is crumbling, then close the fd here. 334 326 } 335 327 336 328 /*
+28 -31
src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoImpl.java
··· 7 7 * @ingroup ipc_android 8 8 */ 9 9 10 - 11 10 package org.freedesktop.monado.ipc; 12 11 13 12 import android.os.ParcelFileDescriptor; ··· 23 22 24 23 /** 25 24 * Java implementation of the IMonado IPC interface. 26 - * <p> 27 - * (This is the server-side code.) 28 - * <p> 29 - * All this does is delegate calls to native JNI implementations. 30 - * The warning suppression is because Android Studio tends to have a hard time finding 31 - * the (very real) implementations of these in service-lib. 25 + * 26 + * <p>(This is the server-side code.) 27 + * 28 + * <p>All this does is delegate calls to native JNI implementations. The warning suppression is 29 + * because Android Studio tends to have a hard time finding the (very real) implementations of these 30 + * in service-lib. 32 31 */ 33 32 @Keep 34 33 public class MonadoImpl extends IMonado.Stub { ··· 45 44 46 45 public MonadoImpl(@NonNull SurfaceManager surfaceManager) { 47 46 this.surfaceManager = surfaceManager; 48 - this.surfaceManager.setCallback(new SurfaceHolder.Callback() { 49 - @Override 50 - public void surfaceCreated(@NonNull SurfaceHolder holder) { 51 - Log.i(TAG, "surfaceCreated"); 52 - passAppSurface(holder.getSurface()); 53 - } 47 + this.surfaceManager.setCallback( 48 + new SurfaceHolder.Callback() { 49 + @Override 50 + public void surfaceCreated(@NonNull SurfaceHolder holder) { 51 + Log.i(TAG, "surfaceCreated"); 52 + passAppSurface(holder.getSurface()); 53 + } 54 54 55 - @Override 56 - public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { 57 - } 55 + @Override 56 + public void surfaceChanged( 57 + @NonNull SurfaceHolder holder, int format, int width, int height) {} 58 58 59 - @Override 60 - public void surfaceDestroyed(@NonNull SurfaceHolder holder) { 61 - } 62 - }); 59 + @Override 60 + public void surfaceDestroyed(@NonNull SurfaceHolder holder) {} 61 + }); 63 62 } 64 63 65 64 @Override ··· 111 110 nativeShutdownServer(); 112 111 } 113 112 114 - /** 115 - * Native method that starts server. 116 - */ 113 + /** Native method that starts server. */ 117 114 @SuppressWarnings("JavaJniMissingFunction") 118 115 private native void nativeStartServer(); 119 116 120 117 /** 121 118 * Native handling of receiving a surface: should convert it to an ANativeWindow then do stuff 122 119 * with it. 123 - * <p> 124 - * Ignore warnings that this function is missing: it is not, it is just in a different module. 125 - * See `src/xrt/targets/service-lib/service_target.cpp` for the implementation. 120 + * 121 + * <p>Ignore warnings that this function is missing: it is not, it is just in a different 122 + * module. See `src/xrt/targets/service-lib/service_target.cpp` for the implementation. 126 123 * 127 124 * @param surface The surface to pass to native code 128 125 * @todo figure out a good way to have a client ID ··· 133 130 /** 134 131 * Native handling of receiving an FD for a new client: the FD should be used to start up the 135 132 * rest of the native IPC code on that socket. 136 - * <p> 137 - * This is essentially the entry point for the monado service on Android: if it's already 133 + * 134 + * <p>This is essentially the entry point for the monado service on Android: if it's already 138 135 * running, this will be called in it. If it's not already running, a process will be created, 139 136 * and this will be the first native code executed in that process. 140 - * <p> 141 - * Ignore warnings that this function is missing: it is not, it is just in a different module. 142 - * See `src/xrt/targets/service-lib/service_target.cpp` for the implementation. 137 + * 138 + * <p>Ignore warnings that this function is missing: it is not, it is just in a different 139 + * module. See `src/xrt/targets/service-lib/service_target.cpp` for the implementation. 143 140 * 144 141 * @param fd The incoming file descriptor: ownership is transferred to native code here. 145 142 * @return 0 on success, anything else means the fd wasn't sent and ownership not transferred.
+23 -24
src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/MonadoService.kt
··· 16 16 import android.os.IBinder 17 17 import android.util.Log 18 18 import dagger.hilt.android.AndroidEntryPoint 19 - import org.freedesktop.monado.auxiliary.IServiceNotification 20 19 import javax.inject.Inject 20 + import org.freedesktop.monado.auxiliary.IServiceNotification 21 21 22 22 /** 23 23 * Implementation of a Service that provides the Monado AIDL interface. ··· 30 30 31 31 private lateinit var watchdog: Watchdog 32 32 33 - @Inject 34 - lateinit var serviceNotification: IServiceNotification 33 + @Inject lateinit var serviceNotification: IServiceNotification 35 34 36 35 private lateinit var surfaceManager: SurfaceManager 37 36 ··· 40 39 41 40 surfaceManager = SurfaceManager(this) 42 41 binder = MonadoImpl(surfaceManager) 43 - watchdog = Watchdog( 44 - // If the surface comes from client, just stop the service when client disconnected 45 - // because the surface belongs to the client. 46 - if (surfaceManager.canDrawOverlays()) BuildConfig.WATCHDOG_TIMEOUT_MILLISECONDS else 0, 47 - this 48 - ) 42 + watchdog = 43 + Watchdog( 44 + // If the surface comes from client, just stop the service when client disconnected 45 + // because the surface belongs to the client. 46 + if (surfaceManager.canDrawOverlays()) BuildConfig.WATCHDOG_TIMEOUT_MILLISECONDS 47 + else 0, 48 + this 49 + ) 49 50 watchdog.startMonitor() 50 51 51 52 // start the service so it could be foregrounded ··· 58 59 super.onDestroy() 59 60 Log.d(TAG, "onDestroy") 60 61 61 - binder.shutdown(); 62 + binder.shutdown() 62 63 watchdog.stopMonitor() 63 64 surfaceManager.destroySurface() 64 65 } ··· 76 77 } 77 78 78 79 override fun onBind(intent: Intent): IBinder? { 79 - Log.d(TAG, "onBind"); 80 + Log.d(TAG, "onBind") 80 81 watchdog.onClientConnected() 81 82 return binder 82 83 } ··· 87 88 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { 88 89 flags = PendingIntent.FLAG_IMMUTABLE 89 90 } 90 - val pendingShutdownIntent = PendingIntent.getForegroundService( 91 - this, 92 - 0, 93 - Intent(BuildConfig.SHUTDOWN_ACTION).setPackage(packageName), 94 - flags 95 - ) 91 + val pendingShutdownIntent = 92 + PendingIntent.getForegroundService( 93 + this, 94 + 0, 95 + Intent(BuildConfig.SHUTDOWN_ACTION).setPackage(packageName), 96 + flags 97 + ) 96 98 97 99 val notification = serviceNotification.buildNotification(this, pendingShutdownIntent) 98 100 ··· 103 105 ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST 104 106 ) 105 107 } else { 106 - startForeground( 107 - serviceNotification.getNotificationId(), 108 - notification 109 - ) 108 + startForeground(serviceNotification.getNotificationId(), notification) 110 109 } 111 110 } 112 111 113 112 override fun onUnbind(intent: Intent?): Boolean { 114 - Log.d(TAG, "onUnbind"); 113 + Log.d(TAG, "onUnbind") 115 114 watchdog.onClientDisconnected() 116 - return true; 115 + return true 117 116 } 118 117 119 118 override fun onRebind(intent: Intent?) { 120 - Log.d(TAG, "onRebind"); 119 + Log.d(TAG, "onRebind") 121 120 watchdog.onClientConnected() 122 121 } 123 122
+8 -17
src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/SurfaceManager.kt
··· 24 24 import java.util.concurrent.locks.Condition 25 25 import java.util.concurrent.locks.ReentrantLock 26 26 27 - /** 28 - * Class that creates/manages surface on display. 29 - */ 27 + /** Class that creates/manages surface on display. */ 30 28 class SurfaceManager(context: Context) : SurfaceHolder.Callback { 31 29 private val appContext: Context = context.applicationContext 32 30 private val surfaceLock: ReentrantLock = ReentrantLock() ··· 109 107 /** 110 108 * Check if current process has the capability to draw over other applications. 111 109 * 112 - * Implementation of [Settings.canDrawOverlays] checks both context and UID, 113 - * therefore this cannot be done in client side. 110 + * Implementation of [Settings.canDrawOverlays] checks both context and UID, therefore this 111 + * cannot be done in client side. 114 112 * 115 113 * @return True if current process can draw over other applications; otherwise false. 116 114 */ ··· 118 116 return Settings.canDrawOverlays(appContext) 119 117 } 120 118 121 - /** 122 - * Destroy created surface. 123 - */ 119 + /** Destroy created surface. */ 124 120 fun destroySurface() { 125 121 viewHelper.removeView() 126 122 } 127 123 128 - /** 129 - * Helper class that manages surface view. 130 - */ 124 + /** Helper class that manages surface view. */ 131 125 private class ViewHelper(private val callback: SurfaceHolder.Callback) { 132 126 private var view: SurfaceView? = null 133 127 private var displayContext: Context? = null ··· 162 156 } 163 157 } 164 158 165 - /** 166 - * Check whether given display is the one being used right now. 167 - */ 159 + /** Check whether given display is the one being used right now. */ 168 160 @Suppress("DEPRECATION") 169 161 private fun isSameDisplay(context: Context, display: Display): Boolean { 170 162 val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager ··· 186 178 lp.flags = if (focusable) VIEW_FLAG_FOCUSABLE else VIEW_FLAG_NOT_FOCUSABLE 187 179 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 188 180 lp.layoutInDisplayCutoutMode = 189 - WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 181 + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 190 182 } 191 183 192 184 val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager ··· 212 204 @Suppress("DEPRECATION") 213 205 private const val VIEW_FLAG_NOT_FOCUSABLE = 214 206 WindowManager.LayoutParams.FLAG_FULLSCREEN or 215 - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 207 + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 216 208 } 217 209 } 218 210 219 211 companion object { 220 212 private const val TAG = "SurfaceManager" 221 213 } 222 - 223 214 }
+11 -15
src/xrt/ipc/android/src/main/java/org/freedesktop/monado/ipc/Watchdog.kt
··· 13 13 import android.os.Message 14 14 import java.util.concurrent.atomic.AtomicInteger 15 15 16 - /** 17 - * Client watchdog, to determine whether runtime service should be stopped. 18 - */ 16 + /** Client watchdog, to determine whether runtime service should be stopped. */ 19 17 class Watchdog( 20 18 private val shutdownDelayMilliseconds: Long, 21 19 private val shutdownListener: ShutdownListener ··· 25 23 * all the callbacks run on background thread. 26 24 */ 27 25 interface ShutdownListener { 28 - /** 29 - * Callback to be invoked when last client disconnected. 30 - */ 26 + /** Callback to be invoked when last client disconnected. */ 31 27 fun onPrepareShutdown() 32 28 33 - /** 34 - * Callback to be invoked when shutdown delay ended and there's no new client connected. 35 - */ 29 + /** Callback to be invoked when shutdown delay ended and there's no new client connected. */ 36 30 fun onShutdown() 37 31 } 38 32 ··· 45 39 fun startMonitor() { 46 40 shutdownThread = HandlerThread("monado-client-watchdog") 47 41 shutdownThread.start() 48 - shutdownHandler = object : Handler(shutdownThread.looper) { 49 - override fun handleMessage(msg: Message) { 50 - when (msg.what) { 51 - MSG_SHUTDOWN -> if (clientCount.get() == 0) { 52 - shutdownListener.onShutdown() 42 + shutdownHandler = 43 + object : Handler(shutdownThread.looper) { 44 + override fun handleMessage(msg: Message) { 45 + when (msg.what) { 46 + MSG_SHUTDOWN -> 47 + if (clientCount.get() == 0) { 48 + shutdownListener.onShutdown() 49 + } 53 50 } 54 51 } 55 52 } 56 - } 57 53 } 58 54 59 55 fun stopMonitor() {