react-native-bootsplash 5.1.0-beta.0 → 5.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,119 @@
1
+ package com.zoontek.rnbootsplash;
2
+
3
+ import android.app.Activity;
4
+ import android.app.Dialog;
5
+ import android.content.DialogInterface;
6
+ import android.os.Bundle;
7
+ import android.view.Window;
8
+ import android.view.WindowManager;
9
+
10
+ import androidx.annotation.NonNull;
11
+ import androidx.annotation.StyleRes;
12
+
13
+ public class RNBootSplashDialog extends Dialog {
14
+
15
+ private final boolean mFade;
16
+
17
+ public RNBootSplashDialog(@NonNull Activity activity, @StyleRes int themeResId, boolean fade) {
18
+ super(activity, themeResId);
19
+
20
+ mFade = fade;
21
+
22
+ setOwnerActivity(activity);
23
+ setCancelable(false);
24
+ setCanceledOnTouchOutside(false);
25
+ }
26
+
27
+ @Override
28
+ public void onBackPressed() {
29
+ Activity activity = getOwnerActivity();
30
+
31
+ if (activity != null) {
32
+ activity.moveTaskToBack(true);
33
+ }
34
+ }
35
+
36
+ @Override
37
+ public void dismiss() {
38
+ if (!isShowing()) {
39
+ return;
40
+ }
41
+
42
+ try {
43
+ super.dismiss();
44
+ } catch (Exception ignored) {}
45
+ }
46
+
47
+ public void dismiss(@NonNull final Runnable callback) {
48
+ if (!isShowing()) {
49
+ callback.run();
50
+ return;
51
+ }
52
+
53
+ setOnDismissListener(new OnDismissListener() {
54
+ @Override
55
+ public void onDismiss(DialogInterface dialog) {
56
+ callback.run();
57
+ }
58
+ });
59
+
60
+ try {
61
+ super.dismiss();
62
+ } catch (Exception ignored) {
63
+ callback.run();
64
+ }
65
+ }
66
+
67
+ @Override
68
+ public void show() {
69
+ if (isShowing()) {
70
+ return;
71
+ }
72
+
73
+ try {
74
+ super.show();
75
+ } catch (Exception ignored) {}
76
+ }
77
+
78
+ public void show(@NonNull final Runnable callback) {
79
+ if (isShowing()) {
80
+ callback.run();
81
+ return;
82
+ }
83
+
84
+ setOnShowListener(new DialogInterface.OnShowListener() {
85
+ @Override
86
+ public void onShow(DialogInterface dialog) {
87
+ callback.run();
88
+ }
89
+ });
90
+
91
+ try {
92
+ super.show();
93
+ } catch (Exception ignored) {
94
+ callback.run();
95
+ }
96
+ }
97
+
98
+ @Override
99
+ protected void onCreate(Bundle savedInstanceState) {
100
+ final Window window = getWindow();
101
+
102
+ if (window != null) {
103
+ window.setLayout(
104
+ WindowManager.LayoutParams.MATCH_PARENT,
105
+ WindowManager.LayoutParams.MATCH_PARENT
106
+ );
107
+
108
+ window.setWindowAnimations(mFade
109
+ ? R.style.BootSplashFadeOutAnimation
110
+ : R.style.BootSplashNoAnimation);
111
+
112
+ if (RNBootSplashModuleImpl.isSamsungOneUI4()) {
113
+ window.setBackgroundDrawableResource(R.drawable.compat_splash_screen_oneui_4);
114
+ }
115
+ }
116
+
117
+ super.onCreate(savedInstanceState);
118
+ }
119
+ }
@@ -1,24 +1,16 @@
1
1
  package com.zoontek.rnbootsplash;
2
2
 
3
- import android.animation.Animator;
4
- import android.animation.AnimatorListenerAdapter;
5
3
  import android.annotation.SuppressLint;
6
4
  import android.app.Activity;
7
5
  import android.content.res.Resources;
8
- import android.graphics.drawable.Drawable;
9
6
  import android.os.Build;
10
7
  import android.util.TypedValue;
11
8
  import android.view.View;
12
9
  import android.view.ViewConfiguration;
13
- import android.view.ViewGroup;
14
10
  import android.view.ViewTreeObserver;
15
- import android.view.animation.AccelerateInterpolator;
16
- import android.widget.FrameLayout;
17
- import android.widget.ImageView;
18
11
  import android.window.SplashScreen;
19
12
  import android.window.SplashScreenView;
20
13
 
21
- import androidx.annotation.LayoutRes;
22
14
  import androidx.annotation.NonNull;
23
15
  import androidx.annotation.Nullable;
24
16
  import androidx.annotation.StyleRes;
@@ -46,56 +38,10 @@ public class RNBootSplashModuleImpl {
46
38
  @StyleRes
47
39
  private static int mThemeResId = -1;
48
40
 
49
- @NonNull
50
- private static View getContentView(@NonNull Activity activity) {
51
- return activity.findViewById(android.R.id.content);
52
- }
53
-
54
41
  @Nullable
55
- private static ViewGroup getRootView(@NonNull Activity activity) {
56
- return (ViewGroup) getContentView(activity).getRootView();
57
- }
58
-
42
+ private static RNBootSplashDialog mInitialDialog = null;
59
43
  @Nullable
60
- private static View getSplashScreenView(@NonNull Activity activity) {
61
- final ViewGroup rootView = getRootView(activity);
62
-
63
- return rootView != null
64
- ? rootView.findViewById(R.id.bootsplash_layout)
65
- : null;
66
- }
67
-
68
- private static void removeSplashScreenView(@NonNull Activity activity) {
69
- final ViewGroup rootView = getRootView(activity);
70
- final View splashScreenView = getSplashScreenView(activity);
71
-
72
- if (rootView != null && splashScreenView != null) {
73
- rootView.removeView(splashScreenView);
74
- }
75
- }
76
-
77
- private static void clearPromiseQueue() {
78
- while (!mPromiseQueue.isEmpty()) {
79
- Promise promise = mPromiseQueue.shift();
80
-
81
- if (promise != null) {
82
- promise.resolve(true);
83
- }
84
- }
85
- }
86
-
87
- // From https://stackoverflow.com/a/61062773
88
- public static boolean isSamsungOneUI4() {
89
- String name = "SEM_PLATFORM_INT";
90
-
91
- try {
92
- Field field = Build.VERSION.class.getDeclaredField(name);
93
- int version = (field.getInt(null) - 90000) / 10000;
94
- return version == 4;
95
- } catch (Exception ignored) {
96
- return false;
97
- }
98
- }
44
+ private static RNBootSplashDialog mFadeOutDialog = null;
99
45
 
100
46
  protected static void init(
101
47
  @Nullable final Activity activity,
@@ -113,13 +59,6 @@ public class RNBootSplashModuleImpl {
113
59
  return;
114
60
  }
115
61
 
116
- ViewGroup rootView = getRootView(activity);
117
-
118
- if (rootView == null) {
119
- FLog.w(ReactConstants.TAG, NAME + ": Ignored initialization, current activity rootView is null.");
120
- return;
121
- }
122
-
123
62
  // Apply postBootSplashTheme
124
63
  TypedValue typedValue = new TypedValue();
125
64
  Resources.Theme currentTheme = activity.getTheme();
@@ -133,28 +72,8 @@ public class RNBootSplashModuleImpl {
133
72
  }
134
73
  }
135
74
 
136
- @Nullable Integer backgroundResId = null;
137
- @Nullable Integer backgroundColor = null;
138
- @Nullable Drawable logo = null;
139
- @Nullable Drawable brand = null;
140
-
141
- if (currentTheme.resolveAttribute(R.attr.bootSplashBackground, typedValue, true)) {
142
- backgroundResId = typedValue.resourceId;
143
- backgroundColor = typedValue.data;
144
- }
145
-
146
- if (currentTheme.resolveAttribute(R.attr.bootSplashLogo, typedValue, true)
147
- && typedValue.resourceId != Resources.ID_NULL) {
148
- logo = currentTheme.getDrawable(typedValue.resourceId);
149
- }
150
-
151
- if (currentTheme.resolveAttribute(R.attr.bootSplashBrand, typedValue, true)
152
- && typedValue.resourceId != Resources.ID_NULL) {
153
- brand = currentTheme.getDrawable(typedValue.resourceId);
154
- }
155
-
156
- // Keep the splash screen on-screen until View is added
157
- final View contentView = getContentView(activity);
75
+ // Keep the splash screen on-screen until Dialog is shown
76
+ final View contentView = activity.findViewById(android.R.id.content);
158
77
  mShouldKeepOnScreen = true;
159
78
 
160
79
  contentView
@@ -177,46 +96,63 @@ public class RNBootSplashModuleImpl {
177
96
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
178
97
  // This is not called on Android 12 when activity is started using intent
179
98
  // (Android studio / CLI / notification / widget…)
99
+ SplashScreen.OnExitAnimationListener listener = new SplashScreen.OnExitAnimationListener() {
100
+ @Override
101
+ public void onSplashScreenExit(@NonNull SplashScreenView view) {
102
+ view.remove(); // Remove it immediately, without animation
103
+
104
+ activity
105
+ .getSplashScreen()
106
+ .clearOnExitAnimationListener();
107
+ }
108
+ };
109
+
180
110
  activity
181
111
  .getSplashScreen()
182
- .setOnExitAnimationListener(new SplashScreen.OnExitAnimationListener() {
183
- @Override
184
- public void onSplashScreenExit(@NonNull SplashScreenView splashScreenView) {
185
- splashScreenView.remove(); // Remove it immediately, without animation
186
-
187
- activity
188
- .getSplashScreen()
189
- .clearOnExitAnimationListener();
190
- }
191
- });
112
+ .setOnExitAnimationListener(listener);
192
113
  }
193
114
 
194
- @LayoutRes int layout = isSamsungOneUI4()
195
- ? R.layout.splash_screen_view_samsung_oneui_4
196
- : R.layout.splash_screen_view;
115
+ mInitialDialog = new RNBootSplashDialog(activity, mThemeResId, false);
197
116
 
198
- View splashScreenView = FrameLayout.inflate(activity, layout, null);
117
+ UiThreadUtil.runOnUiThread(new Runnable() {
118
+ @Override
119
+ public void run() {
120
+ mInitialDialog.show(new Runnable() {
121
+ @Override
122
+ public void run() {
123
+ mShouldKeepOnScreen = false;
124
+ }
125
+ });
126
+ }
127
+ });
128
+ }
199
129
 
200
- if (backgroundResId != null && backgroundResId != Resources.ID_NULL) {
201
- splashScreenView.setBackgroundResource(backgroundResId);
202
- } else if (backgroundColor != null) {
203
- splashScreenView.setBackgroundColor(backgroundColor);
204
- } else {
205
- splashScreenView.setBackground(activity.getWindow().getDecorView().getBackground());
130
+ public static void onHostResume() {
131
+ if (mInitialDialog != null) {
132
+ mInitialDialog.show();
206
133
  }
207
-
208
- if (logo != null) {
209
- ImageView logoView = splashScreenView.findViewById(R.id.bootsplash_logo);
210
- logoView.setImageDrawable(logo);
134
+ if (mFadeOutDialog != null) {
135
+ mFadeOutDialog.show();
211
136
  }
137
+ }
212
138
 
213
- if (brand != null) {
214
- ImageView brandView = splashScreenView.findViewById(R.id.bootsplash_brand);
215
- brandView.setImageDrawable(brand);
139
+ public static void onHostPause() {
140
+ if (mInitialDialog != null) {
141
+ mInitialDialog.dismiss();
142
+ }
143
+ if (mFadeOutDialog != null) {
144
+ mFadeOutDialog.dismiss();
216
145
  }
146
+ }
217
147
 
218
- rootView.addView(splashScreenView);
219
- mShouldKeepOnScreen = false; // unfreeze the system thread UI
148
+ private static void clearPromiseQueue() {
149
+ while (!mPromiseQueue.isEmpty()) {
150
+ Promise promise = mPromiseQueue.shift();
151
+
152
+ if (promise != null) {
153
+ promise.resolve(true);
154
+ }
155
+ }
220
156
  }
221
157
 
222
158
  private static void hideAndClearPromiseQueue(
@@ -246,37 +182,67 @@ public class RNBootSplashModuleImpl {
246
182
  return;
247
183
  }
248
184
 
249
- View splashScreenView = getSplashScreenView(activity);
250
-
251
- if (splashScreenView == null) {
252
- clearPromiseQueue();
253
- return;
185
+ if (mFadeOutDialog != null) {
186
+ return; // wait until fade out end for clearPromiseQueue
254
187
  }
255
188
 
256
- if (!fade) {
257
- removeSplashScreenView(activity);
189
+ if (mInitialDialog == null) {
258
190
  clearPromiseQueue();
259
- return;
191
+ return; // both initial and fade out dialog are hidden
260
192
  }
261
193
 
262
- splashScreenView
263
- .animate()
264
- .setDuration(250)
265
- .alpha(0)
266
- .setInterpolator(new AccelerateInterpolator())
267
- .setListener(new AnimatorListenerAdapter() {
194
+ if (!fade) {
195
+ mInitialDialog.dismiss(new Runnable() {
268
196
  @Override
269
- public void onAnimationEnd(Animator animation) {
270
- super.onAnimationEnd(animation);
271
-
272
- removeSplashScreenView(activity);
197
+ public void run() {
198
+ mInitialDialog = null;
273
199
  clearPromiseQueue();
274
200
  }
275
201
  });
202
+
203
+ return;
204
+ }
205
+
206
+ // Create a new Dialog instance with fade out animation
207
+ mFadeOutDialog = new RNBootSplashDialog(activity, mThemeResId, true);
208
+
209
+ mFadeOutDialog.show(new Runnable() {
210
+ @Override
211
+ public void run() {
212
+
213
+ mInitialDialog.dismiss(new Runnable() {
214
+ @Override
215
+ public void run() {
216
+ mInitialDialog = null;
217
+
218
+ mFadeOutDialog.dismiss(new Runnable() {
219
+ @Override
220
+ public void run() {
221
+ mFadeOutDialog = null;
222
+ clearPromiseQueue();
223
+ }
224
+ });
225
+ }
226
+ });
227
+ }
228
+ });
276
229
  }
277
230
  });
278
231
  }
279
232
 
233
+ // From https://stackoverflow.com/a/61062773
234
+ public static boolean isSamsungOneUI4() {
235
+ String name = "SEM_PLATFORM_INT";
236
+
237
+ try {
238
+ Field field = Build.VERSION.class.getDeclaredField(name);
239
+ int version = (field.getInt(null) - 90000) / 10000;
240
+ return version == 4;
241
+ } catch (Exception ignored) {
242
+ return false;
243
+ }
244
+ }
245
+
280
246
  public static Map<String, Object> getConstants(final ReactApplicationContext reactContext) {
281
247
  final Resources resources = reactContext.getResources();
282
248
  HashMap<String, Object> constants = new HashMap<>();
@@ -291,7 +257,8 @@ public class RNBootSplashModuleImpl {
291
257
  ? PixelUtil.toDIPFromPixel(resources.getDimensionPixelSize(statusBarHeightResId))
292
258
  : 0;
293
259
 
294
- float navigationBarHeight = navigationBarHeightResId > 0 && !ViewConfiguration.get(reactContext).hasPermanentMenuKey()
260
+ float navigationBarHeight = navigationBarHeightResId > 0 &&
261
+ !ViewConfiguration.get(reactContext).hasPermanentMenuKey()
295
262
  ? PixelUtil.toDIPFromPixel(resources.getDimensionPixelSize(navigationBarHeightResId))
296
263
  : 0;
297
264
 
@@ -311,15 +278,7 @@ public class RNBootSplashModuleImpl {
311
278
  hideAndClearPromiseQueue(reactContext, fade);
312
279
  }
313
280
 
314
- public static void isVisible(
315
- final ReactApplicationContext reactContext,
316
- final Promise promise
317
- ) {
318
- if (mShouldKeepOnScreen) {
319
- promise.resolve(true);
320
- } else {
321
- final Activity activity = reactContext.getCurrentActivity();
322
- promise.resolve(activity != null && getSplashScreenView(activity) != null);
323
- }
281
+ public static void isVisible(final Promise promise) {
282
+ promise.resolve(mShouldKeepOnScreen || mInitialDialog != null || mFadeOutDialog != null);
324
283
  }
325
284
  }
@@ -6,14 +6,10 @@
6
6
  </item>
7
7
 
8
8
  <item android:gravity="fill">
9
- <bitmap
10
- android:src="?bootSplashLogo"
11
- android:gravity="center" />
9
+ <bitmap android:src="?bootSplashLogo" android:gravity="center" />
12
10
  </item>
13
11
 
14
12
  <item android:gravity="fill" android:bottom="60dp">
15
- <bitmap
16
- android:src="?bootSplashBrand"
17
- android:gravity="center_horizontal|bottom" />
13
+ <bitmap android:src="?bootSplashBrand" android:gravity="bottom|center_horizontal" />
18
14
  </item>
19
15
  </layer-list>
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+
3
+ <layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
4
+ <item android:gravity="fill">
5
+ <color android:color="?attr/bootSplashBackground" />
6
+ </item>
7
+
8
+ <item android:gravity="fill">
9
+ <bitmap android:src="?bootSplashLogo" android:gravity="center" />
10
+ </item>
11
+
12
+ <item android:gravity="fill" android:bottom="60dp">
13
+ <bitmap android:src="?bootSplashBrand" android:gravity="bottom|center_horizontal" />
14
+ </item>
15
+ </layer-list>
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+
3
+ <layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
4
+ <item android:gravity="fill">
5
+ <color android:color="?attr/bootSplashBackground" />
6
+ </item>
7
+
8
+ <item
9
+ android:drawable="?bootSplashLogo"
10
+ android:gravity="center"
11
+ android:width="288dp"
12
+ android:height="288dp" />
13
+
14
+ <item
15
+ android:drawable="?bootSplashBrand"
16
+ android:gravity="bottom|center_horizontal"
17
+ android:width="200dp"
18
+ android:height="80dp"
19
+ android:bottom="60dp" />
20
+ </layer-list>
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+
3
+ <layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
4
+ <item android:gravity="fill">
5
+ <color android:color="?attr/bootSplashBackground" />
6
+ </item>
7
+
8
+ <!-- There's an issue with logo size on Samsung OneUI v4
9
+ We need to render it 2 times smaller (288 / 2 = 144) -->
10
+ <item
11
+ android:drawable="?bootSplashLogo"
12
+ android:gravity="center"
13
+ android:width="144dp"
14
+ android:height="144dp" />
15
+
16
+ <item
17
+ android:drawable="?bootSplashBrand"
18
+ android:gravity="bottom|center_horizontal"
19
+ android:width="200dp"
20
+ android:height="80dp"
21
+ android:bottom="60dp" />
22
+ </layer-list>
@@ -1,6 +1,16 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
 
3
3
  <resources>
4
+ <style name="BootSplashNoAnimation">
5
+ <item name="android:windowEnterAnimation">@null</item>
6
+ <item name="android:windowExitAnimation">@null</item>
7
+ </style>
8
+
9
+ <style name="BootSplashFadeOutAnimation">
10
+ <item name="android:windowEnterAnimation">@null</item>
11
+ <item name="android:windowExitAnimation">@anim/bootsplash_fade_out</item>
12
+ </style>
13
+
4
14
  <style name="Theme.BootSplash.Common" parent="Theme.AppCompat.DayNight.NoActionBar">
5
15
  <item name="android:opacity">opaque</item>
6
16
  <item name="android:windowBackground">@drawable/compat_splash_screen</item>
@@ -2,6 +2,7 @@ package com.zoontek.rnbootsplash;
2
2
 
3
3
  import androidx.annotation.NonNull;
4
4
 
5
+ import com.facebook.react.bridge.LifecycleEventListener;
5
6
  import com.facebook.react.bridge.Promise;
6
7
  import com.facebook.react.bridge.ReactApplicationContext;
7
8
  import com.facebook.react.module.annotations.ReactModule;
@@ -9,10 +10,11 @@ import com.facebook.react.module.annotations.ReactModule;
9
10
  import java.util.Map;
10
11
 
11
12
  @ReactModule(name = RNBootSplashModuleImpl.NAME)
12
- public class RNBootSplashModule extends NativeRNBootSplashSpec {
13
+ public class RNBootSplashModule extends NativeRNBootSplashSpec implements LifecycleEventListener {
13
14
 
14
15
  public RNBootSplashModule(ReactApplicationContext reactContext) {
15
16
  super(reactContext);
17
+ reactContext.addLifecycleEventListener(this);
16
18
  }
17
19
 
18
20
  @Override
@@ -26,6 +28,19 @@ public class RNBootSplashModule extends NativeRNBootSplashSpec {
26
28
  return RNBootSplashModuleImpl.getConstants(getReactApplicationContext());
27
29
  }
28
30
 
31
+ @Override
32
+ public void onHostDestroy() {}
33
+
34
+ @Override
35
+ public void onHostResume() {
36
+ RNBootSplashModuleImpl.onHostResume();
37
+ }
38
+
39
+ @Override
40
+ public void onHostPause() {
41
+ RNBootSplashModuleImpl.onHostPause();
42
+ }
43
+
29
44
  @Override
30
45
  public void hide(boolean fade, Promise promise) {
31
46
  RNBootSplashModuleImpl.hide(getReactApplicationContext(), fade, promise);
@@ -33,6 +48,6 @@ public class RNBootSplashModule extends NativeRNBootSplashSpec {
33
48
 
34
49
  @Override
35
50
  public void isVisible(Promise promise) {
36
- RNBootSplashModuleImpl.isVisible(getReactApplicationContext(), promise);
51
+ RNBootSplashModuleImpl.isVisible(promise);
37
52
  }
38
53
  }
@@ -3,6 +3,7 @@ package com.zoontek.rnbootsplash;
3
3
  import androidx.annotation.NonNull;
4
4
  import androidx.annotation.Nullable;
5
5
 
6
+ import com.facebook.react.bridge.LifecycleEventListener;
6
7
  import com.facebook.react.bridge.Promise;
7
8
  import com.facebook.react.bridge.ReactApplicationContext;
8
9
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
@@ -12,10 +13,11 @@ import com.facebook.react.module.annotations.ReactModule;
12
13
  import java.util.Map;
13
14
 
14
15
  @ReactModule(name = RNBootSplashModuleImpl.NAME)
15
- public class RNBootSplashModule extends ReactContextBaseJavaModule {
16
+ public class RNBootSplashModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
16
17
 
17
18
  public RNBootSplashModule(ReactApplicationContext reactContext) {
18
19
  super(reactContext);
20
+ reactContext.addLifecycleEventListener(this);
19
21
  }
20
22
 
21
23
  @NonNull
@@ -30,6 +32,19 @@ public class RNBootSplashModule extends ReactContextBaseJavaModule {
30
32
  return RNBootSplashModuleImpl.getConstants(getReactApplicationContext());
31
33
  }
32
34
 
35
+ @Override
36
+ public void onHostDestroy() {}
37
+
38
+ @Override
39
+ public void onHostResume() {
40
+ RNBootSplashModuleImpl.onHostResume();
41
+ }
42
+
43
+ @Override
44
+ public void onHostPause() {
45
+ RNBootSplashModuleImpl.onHostPause();
46
+ }
47
+
33
48
  @ReactMethod
34
49
  public void hide(boolean fade, Promise promise) {
35
50
  RNBootSplashModuleImpl.hide(getReactApplicationContext(), fade, promise);
@@ -37,6 +52,6 @@ public class RNBootSplashModule extends ReactContextBaseJavaModule {
37
52
 
38
53
  @ReactMethod
39
54
  public void isVisible(Promise promise) {
40
- RNBootSplashModuleImpl.isVisible(getReactApplicationContext(), promise);
55
+ RNBootSplashModuleImpl.isVisible(promise);
41
56
  }
42
57
  }