Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StatusBar Area Turns Black When Hidden Instead of Inheriting Background Color #46070

Closed
softgenicsShubham opened this issue Aug 16, 2024 · 16 comments
Labels
Component: StatusBar Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. Resolution: Fixed A PR that fixes this issue has been merged.

Comments

@softgenicsShubham
Copy link

Description

When hiding the StatusBar using StatusBar hidden, the area where the StatusBar was turns black instead of inheriting the background color of the parent View.

Steps to reproduce

  1. Create a new React Native app.
  2. Hide the StatusBar using <StatusBar hidden />.
  3. Observe that the StatusBar area turns black.
    WhatsApp Image 2024-08-15 at 12 43 43

React Native Version

0.75.1

Affected Platforms

Runtime - Android

Output of npx react-native info

System:
  OS: macOS 14.6.1
  CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
  Memory: 345.66 MB / 32.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.5.1
    path: /usr/local/bin/node
  Yarn:
    version: 3.6.4
    path: /usr/local/bin/yarn
  npm:
    version: 10.8.2
    path: /usr/local/bin/npm
  Watchman:
    version: 2024.07.15.00
    path: /usr/local/bin/watchman
Managers:
  CocoaPods:
    version: 1.15.2
    path: /Users/apple/.rbenv/shims/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 23.5
      - iOS 17.5
      - macOS 14.5
      - tvOS 17.5
      - visionOS 1.2
      - watchOS 10.5
  Android SDK: Not Found
IDEs:
  Android Studio: 2024.1 AI-241.18034.62.2411.12169540
  Xcode:
    version: 15.4/15F31d
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.11
    path: /usr/bin/javac
  Ruby:
    version: 3.0.0
    path: /Users/apple/.rbenv/shims/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.3.1
    wanted: 18.3.1
  react-native:
    installed: 0.75.1
    wanted: 0.75.1
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: true
  newArchEnabled: false

Stacktrace or Logs

wu1s0sJhIXF823pi3g==/split_config.arm64_v8a.apk!/lib/arm64-v8a:/data/app/~~l0IulceH14dbm2z6KPDTow==/com.linkedin.android-K2drwu1s0sJhIXF823pi3g==/split_config.en.apk!/lib/arm64-v8a:/data/app/~~l0IulceH14dbm2z6KPDTow==/com.linkedin.android-K2drwu1s0sJhIXF823pi3g==
08-16 22:10:25.061 17150 17150 V GraphicsEnvironment: ANGLE Developer option for 'com.linkedin.android' set to: 'default'
08-16 22:10:25.061 17150 17150 V GraphicsEnvironment: Neither updatable production driver nor prerelease driver is supported.
08-16 22:10:25.065 17150 17150 D NetworkSecurityConfig: Using Network Security Config from resource network_security_config debugBuild: false
08-16 22:10:25.069 17150 17150 D NetworkSecurityConfig: Using Network Security Config from resource network_security_config debugBuild: false
08-16 22:10:25.260 17150 17150 I EKGCrashLoopDetector: Last crash time: 0
08-16 22:10:25.261 17150 17150 D EKGCrashLoopDetector: Didn't crash at startup last launch
08-16 22:10:25.329 17150 17177 D ExceptionHandler: [EKG-BackgroundExecutor] Uploading pending java crashes
08-16 22:10:25.334 17150 17177 D ExceptionHandler: [EKG-BackgroundExecutor] Number of crash files to process: 0
08-16 22:10:25.356 17150 17150 D EKGNDKCrashReporter: miniDumpFilePath: /data/user/0/com.linkedin.android/files/ekg_ndk_crashes_v1/1.47.57/4fa0fd59-6b98-4ad2-c0f956b0-ad8464a7.dmp
08-16 22:10:25.357 17150 17150 D EKGNDKCrashReporter: metadataFilePath: /data/user/0/com.linkedin.android/files/ekg_ndk_crashes_v1/1.47.57/4fa0fd59-6b98-4ad2-c0f956b0-ad8464a7.metadata
08-16 22:10:25.360 17150 17177 D ExceptionHandler: [EKG-BackgroundExecutor] Uploading native crashes
08-16 22:10:25.361 17150 17177 D ExceptionHandler: [EKG-BackgroundExecutor] Number of crash files to process: 0
08-16 22:10:25.362 17150 17150 D CrashReporter: [main] logBreadcrumb: app_launch
08-16 22:10:25.377 17150 17150 I FlagshipApplication: [main] Granular phase APP_ATTACH with pillar PAI completed.
08-16 22:10:25.381 17150 17150 I FlagshipApplication: [main] Granular phase APP_ATTACH completed. Interval(startNanos=1723826425166000000ns, durationNanos=212000000ns)
08-16 22:10:25.444 17150 17150 I FirebaseApp: Device unlocked: initializing all Firebase APIs for app [DEFAULT]
08-16 22:10:25.464 17150 17150 I FirebaseInitProvider: FirebaseApp initialization successful
08-16 22:10:25.509 17150 17150 W libc    : Access denied finding property "ro.vendor.perf.scroll_opt.heavy_app"
08-16 22:10:25.523 17150 17150 E FlagshipApplication: [main] FlagshipApplication#onCreate() called for process id 17150
08-16 22:10:25.685 17150 17150 I FlagshipApplication: [main] Granular phase APP_DEPENDENCY_INJECTION completed. Interval(startNanos=1723826425536000000ns, durationNanos=149000000ns)
08-16 22:10:25.761 17150 17150 D WM-PackageManagerHelper: Skipping component enablement for androidx.work.impl.background.systemjob.SystemJobService
08-16 22:10:25.762 17150 17150 D WM-Schedulers: Created SystemJobScheduler and enabled SystemJobService
08-16 22:10:25.822 17150 17192 D CompatibilityChangeReporter: Compat change id reported: 160794467; UID 10355; state: ENABLED
08-16 22:10:25.847 17150 17191 I cr_CronetLibraryLoader: Cronet version: 102.0.5005.125, arch: aarch64
08-16 22:10:25.916 17150 17150 W DaggerInfraApplicationD: [main] Cannot set the application tracking stack multiple times. Skipping assignment.
08-16 22:10:25.916 17150 17150 D GlobalSequence: Global Sequence already initialized. Ignoring
08-16 22:10:25.944 17150 17215 W ThreadPoolExecutor: [ConnectionMonitor-1] ConnectionStateChangedListener added to ConnectionMonitor, but ConnectionMonitor has not been started.
08-16 22:10:25.951 17150 17150 D LixManagerImpl: [main] Triggering sync for lix lixType 0
08-16 22:10:25.952 17150 17150 D LixNetworkManager: [main] Batch Fetch Lix url:/lix/lixFrontendTreatmentsV2?action=batchGet
08-16 22:10:25.989 17150 17150 D AppLaunchRateLimiter: [main] shouldLimitAppLaunchNetworkCalls: S600
08-16 22:10:25.989 17150 17150 D InfraAppLaunchOnAppProc: [main] onAppProcessStarted(): shouldLimitNetworkCalls=false
08-16 22:10:26.385 17150 17150 D EventBus: No subscribers registered for event class com.linkedin.android.infra.events.VideoAutoPlaySettingChangedEvent
08-16 22:10:26.386 17150 17150 D EventBus: No subscribers registered for event class org.greenrobot.eventbus.NoSubscriberEvent
08-16 22:10:26.441 17150 17150 I Choreographer: Skipped 55 frames!  The application may be doing too much work on its main thread.
08-16 22:10:26.832 17150 17234 I WM-WorkerWrapper: Worker result SUCCESS for Work [ id=18d6f5b6-467e-4055-94ef-d45d55d69a7d, tags={ com.linkedin.android.litrackinglib.network.SendTrackingEventWorker, period_sync_work } ]
08-16 22:10:26.871 17150 17208 I LMDBLRUCache: Entry init duration: 957ms
08-16 22:10:26.900 17150 17236 I WM-WorkerWrapper: Worker result SUCCESS for Work [ id=715a731f-b8bc-4b8f-acde-b5c83c9e3ff4, tags={ com.linkedin.android.segment.ChameleonPeriodicWork } ]
08-16 22:10:27.342 17150 17234 I WM-WorkerWrapper: Worker result SUCCESS for Work [ id=e10f1dce-8389-4084-a7ae-dc4efa900ecb, tags={ com.linkedin.android.litrackinglib.network.SendTrackingEventWorker, send_one_batch_events_work } 
0

Reproducer

https://github.com/softgenicsShubham/react-native-issues.git

Screenshots and Videos

No response

@cortinico cortinico added Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. and removed Needs: Triage 🔍 labels Aug 16, 2024
@shubhamguptadream11
Copy link
Collaborator

@softgenicsShubham Is this happening on iOS as well?

@softgenicsShubham
Copy link
Author

No

@shubhamguptadream11
Copy link
Collaborator

Screenshot_20240817_094949
@softgenicsShubham I tried with reproducer you provided. Its not happening at my end.
I am using Pixel 7 Pro API 33 as an emulator to run it.
Can anyone else check this?

@softgenicsShubham
Copy link
Author

@shubhamguptadream11, you are right, but this will only happen on physical devices. On the emulator, it works fine on my side as well.

@shubhamguptadream11
Copy link
Collaborator

@softgenicsShubham Let me try on physical device.

@shubhamguptadream11
Copy link
Collaborator

@softgenicsShubham You are right. On physical device it is reproducible.
One work around you can try is
<StatusBar backgroundColor={'transparent'} translucent/>.

@softgenicsShubham
Copy link
Author

@shubhamguptadream11 that's correct, but i want to keep it hidden.

@shubhamguptadream11
Copy link
Collaborator

It seems that API's used here in setHidden function is deprecated now.

May be we need to try out this new APIs: https://developer.android.com/training/system-ui/status
But strange thing is How it's working in emulator though 🤔 .

@shubhamguptadream11
Copy link
Collaborator

#39362
expo/expo#15244
It seems to be widely known issue.

I tried with sample android app(Without react native), there also it's not working. I tried new flags as well. Nothing works as of now.

@shubhamguptadream11
Copy link
Collaborator

shubhamguptadream11 commented Aug 18, 2024

After debugging this, I found a way to solve this issue.
setHidden function is responsible for toggling view of status bar.

What real issue is? For android devices with camera area on top a black strip is coming after hidding status bar.

Previous Implementation:

  override fun setHidden(hidden: Boolean) {
    val activity = currentActivity
    if (activity == null) {
      FLog.w(
          ReactConstants.TAG,
          "StatusBarModule: Ignored status bar change, current activity is null.")
      return
    }
    UiThreadUtil.runOnUiThread(
        Runnable {
          val window = activity.window ?: return@Runnable
          if (hidden) {
            window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
            window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
          } else {
            window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
            window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
          }
        })
  }

It seems that FLAG_FULLSCREEN flag are not enough to draw content in camera area.

Solution:
In order to tackle this android exposes 2 flags:

By adding this flag we are now able to hide status bar properly.

  override fun setHidden(hidden: Boolean) {
    val activity = currentActivity
    if (activity == null) {
      FLog.w(
          ReactConstants.TAG,
          "StatusBarModule: Ignored status bar change, current activity is null.")
      return
    }
    UiThreadUtil.runOnUiThread(
        Runnable {
          val window = activity.window ?: return@Runnable
          if (hidden) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
              // Ensure the content extends into the cutout area
              window.attributes.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
              window.setDecorFitsSystemWindows(false)
            }
            window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
            window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
          } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
              window.attributes.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
              window.setDecorFitsSystemWindows(true)
            }
            window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
            window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
          }
        })
  }

@softgenicsShubham Please try by replacing setHidden function with this new one. Test it either by using a patch or build from source. Let me know whether it is fixing it or not?

Note: This will work above Android 11 and above

@shubhamguptadream11
Copy link
Collaborator

@softgenicsShubham
Copy link
Author

@shubhamguptadream11 The fix is working well. Thanks for the help!

@shubhamguptadream11
Copy link
Collaborator

@softgenicsShubham Thanks for testing it out. I am raising a PR then.

@shubhamguptadream11
Copy link
Collaborator

@softgenicsShubham We can close this issue after merging the PR in main repo. Currently you are using it as patch right?

@softgenicsShubham
Copy link
Author

Apologies for the confusion, I’ve reopened the issue. Yes, I’m currently using it as a patch. I’ll wait for the PR to be merged into the main repo before officially closing the issue. Thanks for the clarification @shubhamguptadream11 !

facebook-github-bot pushed a commit that referenced this issue Aug 20, 2024
Summary:
Fixes these issues:
- #46070
- #39362

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[ANDROID] [FIXED] - Fixed black strip coming when hiding status bar

`setHidden` function is responsible for hiding status bar

https://github.com/facebook/react-native/blob/25d6a152cc720e0d5f860dab228ac2e43321d9e4/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt#L122

**What real issue is?** **_For android devices with camera area on top a black strip is coming after hidding status bar._**

Previous Implementation:
```
  override fun setHidden(hidden: Boolean) {
    val activity = currentActivity
    if (activity == null) {
      Log.w(
          ReactConstants.TAG,
          "StatusBarModule: Ignored status bar change, current activity is null.")
      return
    }
    UiThreadUtil.runOnUiThread(
        Runnable {
          val window = activity.window ?: return@Runnable
          if (hidden) {
            window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
            window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
          } else {
            window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
            window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
          }
        })
  }
```
It seems that FLAG_FULLSCREEN flag are not enough to draw content in camera area.

**Solution:**
In order to tackle this, android exposes 2 flags:
- [layoutInDisplayCutOutMode](https://developer.android.com/reference/android/view/WindowManager.LayoutParams#layoutInDisplayCutoutMode):  The window is always allowed to extend into the [DisplayCutout](https://developer.android.com/reference/android/view/DisplayCutout) areas on the short edges of the screen. [Android 9.0 and above]
- [setDecorFitsSystemWindows](https://developer.android.com/reference/android/view/Window#setDecorFitsSystemWindows(boolean)):  allows content to be able to extend into the cutout area. [Android 10.0 and above]

By adding this flag we are now able to hide status bar properly.
```
  override fun setHidden(hidden: Boolean) {
    val activity = currentActivity
    if (activity == null) {
      FLog.w(
          ReactConstants.TAG,
          "StatusBarModule: Ignored status bar change, current activity is null.")
      return
    }
    UiThreadUtil.runOnUiThread(
        Runnable {
          val window = activity.window ?: return@Runnable
          if (hidden) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
              // Ensure the content extends into the cutout area
              window.attributes.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
              window.setDecorFitsSystemWindows(false)
            }
            window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
            window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
          } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
              window.attributes.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
              window.setDecorFitsSystemWindows(true)
            }
            window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
            window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
          }
        })
  }
```

**_Note: This will work above Android 11 and above_**

Pull Request resolved: #46086

Test Plan:
- Tested by author of this issue
- Sharing here the videos of before and after fix

Device Detail:
Oneplus9 5G OS 11
**Before fix:**
https://github.com/user-attachments/assets/589098ff-a3fa-4962-a15b-ceacbfd03d2d

**After fix:**
https://github.com/user-attachments/assets/a87dd8e4-3624-4e09-99da-a14f9e19fcc6

Reviewed By: cipolleschi

Differential Revision: D61509889

Pulled By: alanleedev

fbshipit-source-id: 733962a3bed2efba71588a4d2fdf7c9c386bc3b4
@shubhamguptadream11
Copy link
Collaborator

Fixed PR is merged now.

@cortinico cortinico added the Resolution: Fixed A PR that fixes this issue has been merged. label Aug 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: StatusBar Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. Resolution: Fixed A PR that fixes this issue has been merged.
Projects
None yet
Development

No branches or pull requests

4 participants