Repository navigation
Custom splash replacement with post-load STU attribution #25
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
Changes from all commits
d89cff2
b3ebc7c
0337b4d
b2e6195
e8a1cef
3b1aa20
7005eab
cf39fdf
4bc400b
a5b8570
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| package de.starlightunit.wrapper.launch; | ||
|
|
||
| import android.app.Activity; | ||
| import android.os.Handler; | ||
| import android.os.Looper; | ||
| import android.view.View; | ||
| import android.widget.FrameLayout; | ||
| import android.widget.ImageView; | ||
|
|
||
| public final class AttributionBannerController { | ||
| private static final long FADE_IN_MS = 180L; | ||
| private static final long FADE_OUT_MS = 220L; | ||
|
|
||
| private final Activity activity; | ||
| private final ImageView banner; | ||
| private final boolean enabled; | ||
| private final long durationMs; | ||
| private final Handler handler = new Handler(Looper.getMainLooper()); | ||
|
|
||
| private boolean introFinished; | ||
| private boolean customSplashUsed; | ||
| private boolean firstPageReady; | ||
| private boolean shown; | ||
| private boolean cancelled; | ||
|
|
||
| public AttributionBannerController( | ||
| Activity activity, | ||
| ImageView banner, | ||
| boolean enabled, | ||
| int durationMs, | ||
| int bottomInsetDp | ||
| ) { | ||
| this.activity = activity; | ||
| this.banner = banner; | ||
| this.enabled = enabled; | ||
| this.durationMs = SplashAttributionPolicy.clampDurationMs(durationMs); | ||
| applyBottomInset(bottomInsetDp); | ||
| banner.setVisibility(View.GONE); | ||
| banner.setAlpha(0f); | ||
| } | ||
|
|
||
| public void onIntroFinished(boolean customSplashUsed) { | ||
| this.introFinished = true; | ||
| this.customSplashUsed = customSplashUsed; | ||
| maybeShow(); | ||
| } | ||
|
|
||
| public void onFirstPageReady() { | ||
| if (firstPageReady) { | ||
| return; | ||
| } | ||
| firstPageReady = true; | ||
| maybeShow(); | ||
| } | ||
|
|
||
| public void cancel() { | ||
| cancelled = true; | ||
| handler.removeCallbacksAndMessages(null); | ||
| banner.animate().cancel(); | ||
| banner.setVisibility(View.GONE); | ||
| } | ||
|
|
||
| private void maybeShow() { | ||
| if (!SplashAttributionPolicy.shouldShow( | ||
| enabled, | ||
| introFinished, | ||
| customSplashUsed, | ||
| firstPageReady, | ||
| shown, | ||
| cancelled | ||
| )) { | ||
| return; | ||
| } | ||
|
|
||
| int resource = activity.getResources().getIdentifier( | ||
| "quantum_studio_attribution_banner", | ||
| "drawable", | ||
| activity.getPackageName() | ||
| ); | ||
| if (resource == 0) { | ||
| return; | ||
|
Comment on lines
+75
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
A repo-wide search of the reviewed tree and its resource history finds no drawable named Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| shown = true; | ||
| banner.setImageResource(resource); | ||
| banner.setVisibility(View.VISIBLE); | ||
| banner.setAlpha(0f); | ||
| banner.setTranslationY(dp(12)); | ||
| banner.bringToFront(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
During the banner's display window, Useful? React with 👍 / 👎. |
||
| banner.animate() | ||
| .alpha(1f) | ||
| .translationY(0f) | ||
| .setDuration(FADE_IN_MS) | ||
| .withEndAction(() -> handler.postDelayed(this::hide, durationMs)) | ||
|
Comment on lines
+93
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
| .start(); | ||
| } | ||
|
|
||
| private void hide() { | ||
| if (cancelled) { | ||
| return; | ||
| } | ||
| banner.animate().cancel(); | ||
| banner.animate() | ||
| .alpha(0f) | ||
| .translationY(dp(8)) | ||
| .setDuration(FADE_OUT_MS) | ||
| .withEndAction(() -> { | ||
| if (!cancelled) { | ||
| banner.setVisibility(View.GONE); | ||
| } | ||
| }) | ||
| .start(); | ||
| } | ||
|
|
||
| private void applyBottomInset(int bottomInsetDp) { | ||
| FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) banner.getLayoutParams(); | ||
| params.bottomMargin = dp(Math.max(16, bottomInsetDp)); | ||
| banner.setLayoutParams(params); | ||
| } | ||
|
|
||
| private int dp(int value) { | ||
| return Math.round(value * activity.getResources().getDisplayMetrics().density); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the initial main-frame request returns a 4xx response such as 401, 403, or 404,
GameWebViewClient.onReceivedHttpError()does not setmainFrameFailedbecause it only treats statuses of 500 or higher as errors;onPageFinished()then reaches this call and permanently marks the first page as ready. A custom-splash build will therefore show the attribution banner after a failed first-page load, contrary to the documented behavior. Track main-frame 4xx responses as unsuccessful for this coordination path, or pass an explicit successful-load signal.Useful? React with 👍 / 👎.