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

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,123 @@
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
+ public boolean getFade() {
28
+ return mFade;
29
+ }
30
+
31
+ @Override
32
+ public void onBackPressed() {
33
+ Activity activity = getOwnerActivity();
34
+
35
+ if (activity != null) {
36
+ activity.moveTaskToBack(true);
37
+ }
38
+ }
39
+
40
+ @Override
41
+ public void dismiss() {
42
+ if (!isShowing()) {
43
+ return;
44
+ }
45
+
46
+ try {
47
+ super.dismiss();
48
+ } catch (Exception ignored) {}
49
+ }
50
+
51
+ public void dismiss(@NonNull final Runnable callback) {
52
+ if (!isShowing()) {
53
+ callback.run();
54
+ return;
55
+ }
56
+
57
+ setOnDismissListener(new OnDismissListener() {
58
+ @Override
59
+ public void onDismiss(DialogInterface dialog) {
60
+ callback.run();
61
+ }
62
+ });
63
+
64
+ try {
65
+ super.dismiss();
66
+ } catch (Exception ignored) {
67
+ callback.run();
68
+ }
69
+ }
70
+
71
+ @Override
72
+ public void show() {
73
+ if (isShowing()) {
74
+ return;
75
+ }
76
+
77
+ try {
78
+ super.show();
79
+ } catch (Exception ignored) {}
80
+ }
81
+
82
+ public void show(@NonNull final Runnable callback) {
83
+ if (isShowing()) {
84
+ callback.run();
85
+ return;
86
+ }
87
+
88
+ setOnShowListener(new DialogInterface.OnShowListener() {
89
+ @Override
90
+ public void onShow(DialogInterface dialog) {
91
+ callback.run();
92
+ }
93
+ });
94
+
95
+ try {
96
+ super.show();
97
+ } catch (Exception ignored) {
98
+ callback.run();
99
+ }
100
+ }
101
+
102
+ @Override
103
+ protected void onCreate(Bundle savedInstanceState) {
104
+ final Window window = getWindow();
105
+
106
+ if (window != null) {
107
+ window.setLayout(
108
+ WindowManager.LayoutParams.MATCH_PARENT,
109
+ WindowManager.LayoutParams.MATCH_PARENT
110
+ );
111
+
112
+ window.setWindowAnimations(mFade
113
+ ? R.style.BootSplashFadeOutAnimation
114
+ : R.style.BootSplashNoAnimation);
115
+
116
+ if (RNBootSplashModuleImpl.isSamsungOneUI4()) {
117
+ window.setBackgroundDrawableResource(R.drawable.compat_splash_screen_oneui_4);
118
+ }
119
+ }
120
+
121
+ super.onCreate(savedInstanceState);
122
+ }
123
+ }
@@ -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,8 @@ 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
-
59
- @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
- }
42
+ private static RNBootSplashDialog mDialog = null;
99
43
 
100
44
  protected static void init(
101
45
  @Nullable final Activity activity,
@@ -113,13 +57,6 @@ public class RNBootSplashModuleImpl {
113
57
  return;
114
58
  }
115
59
 
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
60
  // Apply postBootSplashTheme
124
61
  TypedValue typedValue = new TypedValue();
125
62
  Resources.Theme currentTheme = activity.getTheme();
@@ -133,28 +70,8 @@ public class RNBootSplashModuleImpl {
133
70
  }
134
71
  }
135
72
 
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);
73
+ // Keep the splash screen on-screen until Dialog is shown
74
+ final View contentView = activity.findViewById(android.R.id.content);
158
75
  mShouldKeepOnScreen = true;
159
76
 
160
77
  contentView
@@ -177,46 +94,57 @@ public class RNBootSplashModuleImpl {
177
94
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
178
95
  // This is not called on Android 12 when activity is started using intent
179
96
  // (Android studio / CLI / notification / widget…)
97
+ SplashScreen.OnExitAnimationListener listener = new SplashScreen.OnExitAnimationListener() {
98
+ @Override
99
+ public void onSplashScreenExit(@NonNull SplashScreenView view) {
100
+ view.remove(); // Remove it immediately, without animation
101
+
102
+ activity
103
+ .getSplashScreen()
104
+ .clearOnExitAnimationListener();
105
+ }
106
+ };
107
+
180
108
  activity
181
109
  .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
- });
110
+ .setOnExitAnimationListener(listener);
192
111
  }
193
112
 
194
- @LayoutRes int layout = isSamsungOneUI4()
195
- ? R.layout.splash_screen_view_samsung_oneui_4
196
- : R.layout.splash_screen_view;
113
+ mDialog = new RNBootSplashDialog(activity, mThemeResId, false);
197
114
 
198
- View splashScreenView = FrameLayout.inflate(activity, layout, null);
115
+ UiThreadUtil.runOnUiThread(new Runnable() {
116
+ @Override
117
+ public void run() {
118
+ mDialog.show(new Runnable() {
119
+ @Override
120
+ public void run() {
121
+ mShouldKeepOnScreen = false;
122
+ }
123
+ });
124
+ }
125
+ });
126
+ }
199
127
 
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());
128
+ public static void onHostResume() {
129
+ if (mDialog != null) {
130
+ mDialog.show();
206
131
  }
132
+ }
207
133
 
208
- if (logo != null) {
209
- ImageView logoView = splashScreenView.findViewById(R.id.bootsplash_logo);
210
- logoView.setImageDrawable(logo);
134
+ public static void onHostPause() {
135
+ if (mDialog != null) {
136
+ mDialog.dismiss();
211
137
  }
138
+ }
212
139
 
213
- if (brand != null) {
214
- ImageView brandView = splashScreenView.findViewById(R.id.bootsplash_brand);
215
- brandView.setImageDrawable(brand);
216
- }
140
+ private static void clearPromiseQueue() {
141
+ while (!mPromiseQueue.isEmpty()) {
142
+ Promise promise = mPromiseQueue.shift();
217
143
 
218
- rootView.addView(splashScreenView);
219
- mShouldKeepOnScreen = false; // unfreeze the system thread UI
144
+ if (promise != null) {
145
+ promise.resolve(true);
146
+ }
147
+ }
220
148
  }
221
149
 
222
150
  private static void hideAndClearPromiseQueue(
@@ -246,37 +174,70 @@ public class RNBootSplashModuleImpl {
246
174
  return;
247
175
  }
248
176
 
249
- View splashScreenView = getSplashScreenView(activity);
250
-
251
- if (splashScreenView == null) {
252
- clearPromiseQueue();
253
- return;
177
+ if (mDialog != null && mDialog.getFade()) {
178
+ return; // wait until fade out end for clearPromiseQueue
254
179
  }
255
180
 
256
- if (!fade) {
257
- removeSplashScreenView(activity);
181
+ if (mDialog == null) {
258
182
  clearPromiseQueue();
259
- return;
183
+ return; // both initial and fade out dialog are hidden
260
184
  }
261
185
 
262
- splashScreenView
263
- .animate()
264
- .setDuration(250)
265
- .alpha(0)
266
- .setInterpolator(new AccelerateInterpolator())
267
- .setListener(new AnimatorListenerAdapter() {
186
+ final RNBootSplashDialog[] tmp = {mDialog};
187
+
188
+ if (fade) {
189
+ // Create a new Dialog instance with fade out animation
190
+ mDialog = new RNBootSplashDialog(activity, mThemeResId, true);
191
+
192
+ mDialog.show(new Runnable() {
193
+
268
194
  @Override
269
- public void onAnimationEnd(Animator animation) {
270
- super.onAnimationEnd(animation);
195
+ public void run() {
196
+ tmp[0].dismiss(new Runnable() {
197
+
198
+ @Override
199
+ public void run() {
200
+ tmp[0] = null;
201
+
202
+ mDialog.dismiss(new Runnable() {
203
+ @Override
204
+ public void run() {
205
+ mDialog = null;
206
+ clearPromiseQueue();
207
+ }
208
+ });
209
+ }
210
+ });
211
+ }
212
+ });
213
+ } else {
214
+ mDialog = null;
271
215
 
272
- removeSplashScreenView(activity);
216
+ tmp[0].dismiss(new Runnable() {
217
+ @Override
218
+ public void run() {
219
+ tmp[0] = null;
273
220
  clearPromiseQueue();
274
221
  }
275
222
  });
223
+ }
276
224
  }
277
225
  });
278
226
  }
279
227
 
228
+ // From https://stackoverflow.com/a/61062773
229
+ public static boolean isSamsungOneUI4() {
230
+ String name = "SEM_PLATFORM_INT";
231
+
232
+ try {
233
+ Field field = Build.VERSION.class.getDeclaredField(name);
234
+ int version = (field.getInt(null) - 90000) / 10000;
235
+ return version == 4;
236
+ } catch (Exception ignored) {
237
+ return false;
238
+ }
239
+ }
240
+
280
241
  public static Map<String, Object> getConstants(final ReactApplicationContext reactContext) {
281
242
  final Resources resources = reactContext.getResources();
282
243
  HashMap<String, Object> constants = new HashMap<>();
@@ -291,7 +252,8 @@ public class RNBootSplashModuleImpl {
291
252
  ? PixelUtil.toDIPFromPixel(resources.getDimensionPixelSize(statusBarHeightResId))
292
253
  : 0;
293
254
 
294
- float navigationBarHeight = navigationBarHeightResId > 0 && !ViewConfiguration.get(reactContext).hasPermanentMenuKey()
255
+ float navigationBarHeight = navigationBarHeightResId > 0 &&
256
+ !ViewConfiguration.get(reactContext).hasPermanentMenuKey()
295
257
  ? PixelUtil.toDIPFromPixel(resources.getDimensionPixelSize(navigationBarHeightResId))
296
258
  : 0;
297
259
 
@@ -311,15 +273,7 @@ public class RNBootSplashModuleImpl {
311
273
  hideAndClearPromiseQueue(reactContext, fade);
312
274
  }
313
275
 
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
- }
276
+ public static void isVisible(final Promise promise) {
277
+ promise.resolve(mShouldKeepOnScreen || mDialog != null);
324
278
  }
325
279
  }
@@ -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
  }