Skip to content

Let the Android embedding adopt OnPreDrawListener #85292

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

Closed
xster opened this issue Jun 25, 2021 · 22 comments
Closed

Let the Android embedding adopt OnPreDrawListener #85292

xster opened this issue Jun 25, 2021 · 22 comments
Assignees
Labels
a: fidelity Matching the OEM platforms better c: new feature Nothing broken; request for a new capability c: performance Relates to speed or footprint issues (see "perf:" labels) customer: money (g3) engine flutter/engine repository. See also e: labels. P0 Critical issues such as a build break or regression platform-android Android applications specifically

Comments

@xster
Copy link
Member

xster commented Jun 25, 2021

Internal bugs: http://b/190767277, http://b/185423816

Using https://developer.android.com/reference/android/view/ViewTreeObserver.OnPreDrawListener to delay when Flutter's activity first draws can help solve

Things this might involve:

@xster xster added c: new feature Nothing broken; request for a new capability platform-android Android applications specifically engine flutter/engine repository. See also e: labels. c: performance Relates to speed or footprint issues (see "perf:" labels) a: fidelity Matching the OEM platforms better customer: money (g3) labels Jun 25, 2021
@blasten
Copy link

blasten commented Jun 25, 2021

@jiahaog any updates on this issue? Let me know if you want me to take a look, and go ahead with the PR.

@xster
Copy link
Member Author

xster commented Jun 25, 2021

One consideration to make though wrt #85139 is that it still can't make Android's first frame a correct measurement of Flutter's first frame, since Android's first frame will still be

[Flutter's first frame] + [time needed to jump from raster to main thread and get a next Android vsync] = [Android's first frame].

@jiahaog
Copy link
Member

jiahaog commented Jun 28, 2021

Yes, I've started looking at it, will follow up with a PR soon

@chinmaygarde chinmaygarde added the P3 Issues that are less important to the Flutter project label Jun 28, 2021
@xster xster added P2 and removed P3 Issues that are less important to the Flutter project labels Jun 28, 2021
@blasten
Copy link

blasten commented Jul 1, 2021

Support a compatibility mode with the old way. Likely by letting this be configurable via FlutterView constructor argument and letting there be intent builder flags defaulting to yes on FlutterActivity/FlutterFragment/FlutterFragmentActivity

What about if we check if the user has supplied a io.flutter.embedding.android.SplashScreenDrawable by calling https://github.com/flutter/engine/blob/40edba381e758e4abaaa4e59192748f12eb97895/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java#L432, if true, then we don't add OnPreDrawListener. Otherwise, we opt into this new mode?

Also, is there a valid use case for this custom splash screen API? could we deprecate it, and document that it's not longer needed?

@xster any thoughts?

@jiahaog
Copy link
Member

jiahaog commented Jul 1, 2021

@blasten we may still need a flag - users may still want to provide io.flutter.embedding.android.SplashScreenDrawable / provideSplashScreen for APIs < 31, while at the same time using the Android S splash screen. (unless we do option 2 below)

There are a few approaches I can think of:

Option 1: Support the Flutter-specific splash screen for APIs >= 31

There may be a jarring transition here depending on how users set up their Flutter splash screen. But in this case, we continue to show the provided drawable.

This will require a flag roughly named useLegacySplashScreenAboveAPI31 for this discussion, which will probably be read from the users' AndroidManifest.xml. The following table tries to enumerate possible use cases of how users may configure their app, and the behavior on the API versions.

Android S APIs used to configure the Android splash screen Users who do not provide io.flutter.embedding.android.SplashScreenDrawable or provideSplashScreen Users who provide io.flutter.embedding.android.SplashScreenDrawable or provideSplashScreen
API <31 Not supported Use preDraw; the Android embedding will not show any Flutter-specific splash screen Don't use preDraw; the Android embedding should use the provided drawable as the splash screen
API >=31 Android S default behavior Use preDraw; the Android embedding will not show any Flutter-specific splash screen Introduce a new flag useLegacySplashScreenAboveAPI31 defaulting to true.

- When enabled: preDraw will be disabled, the user provided drawable will be shown as the Flutter splash screen (possible jarring transition).
- When disabled (ideal state): predraw will be enabled, the user provided drawable will not be shown|Use preDraw; the Android embedding will not show any Flutter-specific splash screen

The guidance here is for users who want to show a splash screen to do the following, which are not mutually exclusive, and since the API 31 rollout may take a while:

  • For API < 31, continue to use io.flutter.embedding.android.SplashScreenDrawable or provideSplashScreen
  • For API >=31, set useLegacySplashScreenAboveAPI31 to false and use the Android S splash screen APIs

Option 2: Don't support the Flutter-specific splash screen for APIs >= 31

Another approach is to use preDraw unconditionally for APIs >= 31. This is probably breaking, since the provided splash screens through io.flutter.embedding.android.SplashScreenDrawable / provideSplashScreen will not be shown.


Do we need to worry about the V1 embedding? I also noticed the existence of the io.flutter.app.android.SplashScreenUntilFirstFrame option, but this appears to only be used for V1.

@jiahaog
Copy link
Member

jiahaog commented Jul 1, 2021

Jotting down my findings as well about how it works today on cold start.

API < 31

  1. android:theme on activity is shown
  2. Show io.flutter.embedding.android.SplashScreenDrawable / provideSplashScreen if present
  3. Crossfade to Flutter

API 31

  1. Android S splash is shown
    <possible jarring transition because Android S splash is not nessarily aligned with 2 or 3>
  2. Show io.flutter.embedding.android.SplashScreenDrawable / provideSplashScreen if present
  3. Crossfade to flutter

@blasten
Copy link

blasten commented Jul 1, 2021

Thanks Jia.

I was under the impression that the custom Flutter splash screen was added because we didn’t know that we could delay showing the Android view hierarchy until Flutter painted the first frame. If this is true, then this feature is not longer necessary.

I’d like to see a real world use case where a secondary splash screen is needed because the oficial Android splash screen isn’t sufficient. have you seen this case internally?

@blasten
Copy link

blasten commented Jul 1, 2021

Note that onPreDraw() has been available since API level 1.

@jiahaog
Copy link
Member

jiahaog commented Jul 1, 2021

From what I can see, most use cases internally point their io.flutter.embedding.android.SplashScreenDrawable to @drawable/launch_background.xml. The same @drawable/launch_background.xml is also referenced by the android:theme of the Activity, as the android:windowBackground. There is one instance where the app uses provideSplashScreen to offset the same @drawable/launch_background.xml by the status bar height. I'm not really sure why, but I reached out to the author.

@blasten
Copy link

blasten commented Jul 2, 2021

Thanks Jia. Do we still need the flag useLegacySplashScreenAboveAPI31 or could we still use the same check from https://github.com/flutter/engine/blob/40edba381e758e4abaaa4e59192748f12eb97895/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java#L432?

@jiahaog
Copy link
Member

jiahaog commented Jul 2, 2021

Not sure if we should reuse it - the linked check comes from the io.flutter.app.android.SplashScreenUntilFirstFrame option which users can set in their manifest, but it appears to be deprecated since it's only part of the V1 embedding. The naming also doesn't really match the semantics of what we're trying to do here as well.

I do like the simplicity of not having a flag though as you've mentioned. Do you know if there are other valid external use cases of manually providing a splash screen?

@blasten
Copy link

blasten commented Jul 6, 2021

@jiahaog
Copy link
Member

jiahaog commented Jul 8, 2021

Right, I think we were both referring to that flag (io.flutter.embedding.android.SplashScreenDrawable) above. I set up a meeting to align on our approach to this offline 🙂

@jiahaog
Copy link
Member

jiahaog commented Jul 13, 2021

We synced up, next steps:

  • Verify if using preDraw and not using io.flutter.embedding.android.SplashScreenDrawable / provideSplashScreen causes a white flash on pre-Android S
  • If the white flash isn't an issue, make using preDraw the default, and add a manifest flag that controls the behavior on all API versions to allow users to opt-out
    • if users use io.flutter.embedding.android.SplashScreenDrawable / provideSplashScreen, print logs to direct them to documentation / migration guide
    • Then deprecate the io.flutter.embedding.android.SplashScreenDrawable / provideSplashScreen APIs
  • Verify that the proposed behavior doesn't do anything weird on add-to-app

@blasten
Copy link

blasten commented Jul 14, 2021

Verify if using preDraw and not using io.flutter.embedding.android.SplashScreenDrawable / provideSplashScreen causes a white flash on pre-Android S

@jiahaog I just tested it on Android 30/ Moto G7. No white splash. However, I do see the fade-out transition.

I changed the custom drawable bg color to purple, and I see a fade-out purple background that gets blended with the color I set in the initial Android splash screen.

@blasten
Copy link

blasten commented Jul 14, 2021

Here's the code I added to FlutterView.java:

private void init() {
    // ... current code ... //
    this.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
      @Override
      public boolean onPreDraw() {
        return isFlutterUiDisplayed;
      }
    });
}

@jiahaog
Copy link
Member

jiahaog commented Jul 14, 2021

Yeah, I can reproduce that as well. I must have remembered something wrongly, apologies for the confusion. As discussed, I'll work on a PR for the following then:

  • if the white flash isn't an issue, make using preDraw the default, and add a manifest flag that controls the behavior on all API versions to allow users to opt-out
    • if users use io.flutter.embedding.android.SplashScreenDrawable / provideSplashScreen, print logs to direct them to documentation / migration guide
    • Then deprecate the io.flutter.embedding.android.SplashScreenDrawable / provideSplashScreen APIs

@jiahaog
Copy link
Member

jiahaog commented Jul 20, 2021

Update: Working on a PR for what was discussed above

@jiahaog
Copy link
Member

jiahaog commented Jul 30, 2021

@chinmaygarde
Copy link
Member

@jiahaog flutter/engine#27811 seems to have landed. Can we close this issue?

@blasten
Copy link

blasten commented Aug 2, 2021

I think so

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 16, 2021
@flutter-triage-bot flutter-triage-bot bot added P0 Critical issues such as a build break or regression and removed P2 labels Jun 28, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: fidelity Matching the OEM platforms better c: new feature Nothing broken; request for a new capability c: performance Relates to speed or footprint issues (see "perf:" labels) customer: money (g3) engine flutter/engine repository. See also e: labels. P0 Critical issues such as a build break or regression platform-android Android applications specifically
Projects
None yet
Development

No branches or pull requests

6 participants