@@ -325,17 +325,18 @@ public void onCodecChanged(boolean h265, AudioConfig audio) {
325325 FrameLayout .LayoutParams .MATCH_PARENT ));
326326
327327 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R ) {
328- WindowInsetsController ctrl = getWindow (). getInsetsController ();
329- if ( ctrl != null ) {
330- ctrl . hide ( WindowInsets . Type . navigationBars () );
331- ctrl . setSystemBarsBehavior (
332- WindowInsetsController . BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE );
333- }
334- } else {
335- //noinspection deprecation
336- getWindow (). getDecorView (). setSystemUiVisibility (
337- View . SYSTEM_UI_FLAG_HIDE_NAVIGATION );
328+ // Bars that stay shown while the video has the focus (not the transient ones after
329+ // a swipe, which the app does not see) go away again after a moment (#202)
330+ View decor = getWindow (). getDecorView ( );
331+ decor . setOnApplyWindowInsetsListener (( v , insets ) -> {
332+ v . removeCallbacks ( hideBarsRunnable );
333+ if ( hasWindowFocus () && insets . isVisible ( WindowInsets . Type . systemBars ())) {
334+ v . postDelayed ( hideBarsRunnable , BARS_REHIDE_MS );
335+ }
336+ return v . onApplyWindowInsets ( insets );
337+ } );
338338 }
339+ hideSystemBars ();
339340
340341 updateStatus ("disconnected" );
341342 DebugServer .get ().setSource (debugSource );
@@ -506,7 +507,11 @@ private boolean leaveUdpView() {
506507 }
507508
508509 @ Override
509- public void onExit () { finishAndRemoveTask (); }
510+ public void onExit () {
511+ // Not left showing over a finishing activity (#205)
512+ menuManager .dismissAll ();
513+ finishAndRemoveTask ();
514+ }
510515
511516 /**
512517 * Reset (#171): stops every stream, deletes the stored settings, the key of the encrypted
@@ -920,7 +925,7 @@ private void buildQuadGrid(int size) {
920925 /** Shown over the U cell until its first frame: where to send the stream. */
921926 private TextView udpHintCell () {
922927 TextView hint = new TextView (this );
923- hint .setText (udpHintText (NetInfo .addresses (), UDP_RTP_PORT ));
928+ hint .setText (udpHintText (NetInfo .udpAddresses (), UDP_RTP_PORT ));
924929 hint .setTextColor (Color .GRAY );
925930 hint .setTextSize (13 );
926931 hint .setGravity (Gravity .CENTER );
@@ -938,7 +943,7 @@ private void refreshUdpHint() {
938943 if (v == null ) return ;
939944 View overlay = ((View ) v .getParent ()).findViewWithTag ("quad_overlay_" + U_CELL );
940945 if (!(overlay instanceof TextView ) || overlay .getVisibility () != View .VISIBLE ) return ;
941- String text = udpHintText (NetInfo .addresses (), UDP_RTP_PORT );
946+ String text = udpHintText (NetInfo .udpAddresses (), UDP_RTP_PORT );
942947 TextView hint = (TextView ) overlay ;
943948 if (!text .contentEquals (hint .getText ())) hint .setText (text );
944949 }
@@ -1073,7 +1078,7 @@ private void showQuadOverlay(int i) {
10731078 overlay .setBackgroundColor (Color .BLACK );
10741079 cell .addView (overlay );
10751080 } else if (i == U_CELL ) {
1076- ((TextView ) overlay ).setText (udpHintText (NetInfo .addresses (), UDP_RTP_PORT ));
1081+ ((TextView ) overlay ).setText (udpHintText (NetInfo .udpAddresses (), UDP_RTP_PORT ));
10771082 }
10781083 overlay .setVisibility (View .VISIBLE );
10791084 overlay .bringToFront ();
@@ -1533,7 +1538,7 @@ private Map<String, Object> debugState() {
15331538 if (udpViewShown ) {
15341539 Map <String , Object > udp = new LinkedHashMap <>();
15351540 udp .put ("port" , UDP_RTP_PORT );
1536- udp .put ("addresses" , NetInfo .addresses ());
1541+ udp .put ("addresses" , NetInfo .udpAddresses ());
15371542 m .put ("udp" , udp );
15381543 } else if (!quadEnabled ) {
15391544 Map <String , Object > single = new LinkedHashMap <>();
@@ -2367,6 +2372,9 @@ private void stopExecutor() {
23672372
23682373 @ Override
23692374 protected void onDestroy () {
2375+ // The menu and the dialogs go with the activity, or Android logs them as leaked (#205)
2376+ if (menuManager != null ) menuManager .dismissAll ();
2377+ getWindow ().getDecorView ().removeCallbacks (hideBarsRunnable );
23702378 super .onDestroy ();
23712379 DebugServer .get ().clearSource (debugSource );
23722380 streamProbes .shutdown ();
@@ -2387,10 +2395,46 @@ protected void onNewIntent(Intent intent) {
23872395 }
23882396 }
23892397
2398+ /** How long bars that stay shown over the video are left before they are hidden (#202). */
2399+ private static final long BARS_REHIDE_MS = 3000 ;
2400+ private final Runnable hideBarsRunnable = this ::hideSystemBars ;
2401+
2402+ /**
2403+ * Full screen over the whole display in every viewing mode (single, grid, U), with no
2404+ * status or navigation bar (#202). A swipe from an edge shows them for a moment only.
2405+ * Android 15 draws apps edge to edge, so bars left shown cover the picture; some systems
2406+ * (an OPPO, #187) bring them back after another window had the focus, so this runs again
2407+ * whenever the activity resumes or gets the focus back: after the menu, a dialog or the
2408+ * WebUI, which keeps the bars and its insets padding (#169, #180).
2409+ */
2410+ private void hideSystemBars () {
2411+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R ) {
2412+ WindowInsetsController ctrl = getWindow ().getInsetsController ();
2413+ if (ctrl != null ) {
2414+ ctrl .setSystemBarsBehavior (
2415+ WindowInsetsController .BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE );
2416+ ctrl .hide (WindowInsets .Type .systemBars ());
2417+ }
2418+ } else {
2419+ //noinspection deprecation
2420+ getWindow ().getDecorView ().setSystemUiVisibility (
2421+ View .SYSTEM_UI_FLAG_IMMERSIVE_STICKY
2422+ | View .SYSTEM_UI_FLAG_HIDE_NAVIGATION
2423+ | View .SYSTEM_UI_FLAG_FULLSCREEN );
2424+ }
2425+ }
2426+
2427+ @ Override
2428+ public void onWindowFocusChanged (boolean hasFocus ) {
2429+ super .onWindowFocusChanged (hasFocus );
2430+ if (hasFocus ) hideSystemBars ();
2431+ }
2432+
23902433 @ Override
23912434 protected void onResume () {
23922435 super .onResume ();
23932436 mResumed = true ;
2437+ hideSystemBars ();
23942438 startStreams ();
23952439 updateDebugUrls ();
23962440 }
0 commit comments