react-native-bootsplash 3.2.5 → 4.0.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.
@@ -4,44 +4,47 @@ import android.animation.Animator;
4
4
  import android.animation.AnimatorListenerAdapter;
5
5
  import android.app.Activity;
6
6
  import android.view.View;
7
- import android.view.ViewGroup;
8
7
  import android.view.animation.AccelerateInterpolator;
9
- import android.view.animation.DecelerateInterpolator;
10
- import android.widget.LinearLayout;
11
- import android.widget.LinearLayout.LayoutParams;
12
8
 
13
- import androidx.annotation.DrawableRes;
14
9
  import androidx.annotation.NonNull;
10
+ import androidx.annotation.Nullable;
11
+ import androidx.core.splashscreen.SplashScreen;
12
+ import androidx.core.splashscreen.SplashScreenViewProvider;
15
13
 
14
+ import com.facebook.common.logging.FLog;
16
15
  import com.facebook.react.bridge.LifecycleEventListener;
17
16
  import com.facebook.react.bridge.Promise;
18
17
  import com.facebook.react.bridge.ReactApplicationContext;
19
18
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
20
19
  import com.facebook.react.bridge.ReactMethod;
21
20
  import com.facebook.react.bridge.UiThreadUtil;
21
+ import com.facebook.react.common.ReactConstants;
22
22
  import com.facebook.react.module.annotations.ReactModule;
23
23
 
24
24
  import java.util.ArrayList;
25
25
  import java.util.Timer;
26
26
  import java.util.TimerTask;
27
27
 
28
- @ReactModule(name = RNBootSplashModule.MODULE_NAME)
28
+ @ReactModule(name = RNBootSplashModule.NAME)
29
29
  public class RNBootSplashModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
30
30
 
31
- public static final String MODULE_NAME = "RNBootSplash";
31
+ public static final String NAME = "RNBootSplash";
32
32
  private static final int ANIMATION_DURATION = 220;
33
33
 
34
34
  private enum Status {
35
35
  VISIBLE,
36
36
  HIDDEN,
37
- TRANSITIONING_TO_VISIBLE,
38
- TRANSITIONING_TO_HIDDEN
37
+ TRANSITIONING
39
38
  }
40
39
 
41
- private static int mDrawableResId = -1;
40
+ @Nullable
41
+ private static SplashScreen mSplashScreen = null;
42
+
42
43
  private static final ArrayList<RNBootSplashTask> mTaskQueue = new ArrayList<>();
43
44
  private static Status mStatus = Status.HIDDEN;
44
45
  private static boolean mIsAppInBackground = false;
46
+ private static boolean mShouldFade = false;
47
+ private static boolean mShouldKeepOnScreen = true;
45
48
 
46
49
  public RNBootSplashModule(ReactApplicationContext reactContext) {
47
50
  super(reactContext);
@@ -50,38 +53,46 @@ public class RNBootSplashModule extends ReactContextBaseJavaModule implements Li
50
53
 
51
54
  @Override
52
55
  public String getName() {
53
- return MODULE_NAME;
56
+ return NAME;
54
57
  }
55
58
 
56
- private static LinearLayout getLayout(@NonNull Activity activity, LayoutParams params) {
57
- LinearLayout layout = new LinearLayout(activity);
58
- View view = new View(activity);
59
-
60
- view.setBackgroundResource(mDrawableResId);
61
- layout.setId(R.id.bootsplash_layout_id);
62
- layout.setLayoutTransition(null);
63
- layout.setOrientation(LinearLayout.VERTICAL);
64
- layout.addView(view, params);
59
+ protected static void init(@Nullable final Activity activity) {
60
+ if (activity == null) {
61
+ FLog.w(
62
+ ReactConstants.TAG,
63
+ NAME + ": Ignored initialization, current activity is null.");
64
+ return;
65
+ }
65
66
 
66
- return layout;
67
- }
67
+ mSplashScreen = SplashScreen.installSplashScreen(activity);
68
+ mStatus = Status.VISIBLE;
68
69
 
69
- protected static void init(final @DrawableRes int drawableResId, final Activity activity) {
70
- UiThreadUtil.runOnUiThread(new Runnable() {
70
+ mSplashScreen.setKeepVisibleCondition(new SplashScreen.KeepOnScreenCondition() {
71
71
  @Override
72
- public void run() {
73
- if (activity == null
74
- || activity.isFinishing()
75
- || activity.findViewById(R.id.bootsplash_layout_id) != null) {
76
- return;
77
- }
78
-
79
- mDrawableResId = drawableResId;
80
- mStatus = Status.VISIBLE;
72
+ public boolean shouldKeepOnScreen() {
73
+ return mShouldKeepOnScreen;
74
+ }
75
+ });
81
76
 
82
- LayoutParams params = new LayoutParams(
83
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
84
- activity.addContentView(getLayout(activity, params), params);
77
+ mSplashScreen.setOnExitAnimationListener(new SplashScreen.OnExitAnimationListener() {
78
+ @Override
79
+ public void onSplashScreenExit(@NonNull SplashScreenViewProvider splashScreenViewProvider) {
80
+ View splashScreenView = splashScreenViewProvider.getView();
81
+
82
+ splashScreenView
83
+ .animate()
84
+ // Crappy hack to avoid automatic layout transitions
85
+ .setDuration(mShouldFade ? ANIMATION_DURATION: 0)
86
+ .setStartDelay(mShouldFade ? 0 : ANIMATION_DURATION)
87
+ .alpha(0.0f)
88
+ .setInterpolator(new AccelerateInterpolator())
89
+ .setListener(new AnimatorListenerAdapter() {
90
+ @Override
91
+ public void onAnimationEnd(Animator animation) {
92
+ super.onAnimationEnd(animation);
93
+ splashScreenViewProvider.remove();
94
+ }
95
+ }).start();
85
96
  }
86
97
  });
87
98
  }
@@ -103,27 +114,17 @@ public class RNBootSplashModule extends ReactContextBaseJavaModule implements Li
103
114
  }
104
115
 
105
116
  private void shiftNextTask() {
106
- boolean shouldSkipTick = mDrawableResId == -1
107
- || mStatus == Status.TRANSITIONING_TO_VISIBLE
108
- || mStatus == Status.TRANSITIONING_TO_HIDDEN
117
+ boolean shouldSkipTick = mStatus == Status.TRANSITIONING
109
118
  || mIsAppInBackground
110
119
  || mTaskQueue.isEmpty();
111
120
 
112
121
  if (shouldSkipTick) return;
113
122
 
114
123
  RNBootSplashTask task = mTaskQueue.remove(0);
115
-
116
- switch (task.getType()) {
117
- case SHOW:
118
- show(task);
119
- break;
120
- case HIDE:
121
- hide(task);
122
- break;
123
- }
124
+ hideWithTask(task);
124
125
  }
125
126
 
126
- private void waitAndShiftNextTask() {
127
+ private void waitAndRetry() {
127
128
  final Timer timer = new Timer();
128
129
 
129
130
  timer.schedule(new TimerTask() {
@@ -135,128 +136,55 @@ public class RNBootSplashModule extends ReactContextBaseJavaModule implements Li
135
136
  }, 250);
136
137
  }
137
138
 
138
- private void show(final RNBootSplashTask task) {
139
- UiThreadUtil.runOnUiThread(new Runnable() {
140
- @Override
141
- public void run() {
142
- final Activity activity = getReactApplicationContext().getCurrentActivity();
143
- final Promise promise = task.getPromise();
144
-
145
- if (activity == null || activity.isFinishing()) {
146
- waitAndShiftNextTask();
147
- return;
148
- }
149
-
150
- if (activity.findViewById(R.id.bootsplash_layout_id) != null) {
151
- promise.resolve(true); // splash screen is already visible
152
- shiftNextTask();
153
- return;
154
- }
139
+ private void hideWithTask(final RNBootSplashTask task) {
140
+ final Activity activity = getReactApplicationContext().getCurrentActivity();
141
+ final boolean fade = task.getFade();
142
+ final Promise promise = task.getPromise();
155
143
 
156
- mStatus = Status.TRANSITIONING_TO_VISIBLE;
157
-
158
- LayoutParams params = new LayoutParams(
159
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
160
- LinearLayout layout = getLayout(activity, params);
161
-
162
- if (task.getFade()) {
163
- layout.setAlpha(0.0f);
164
- activity.addContentView(layout, params);
165
-
166
- layout
167
- .animate()
168
- .setDuration(ANIMATION_DURATION)
169
- .alpha(1.0f)
170
- .setInterpolator(new DecelerateInterpolator())
171
- .setListener(new AnimatorListenerAdapter() {
172
- @Override
173
- public void onAnimationEnd(Animator animation) {
174
- super.onAnimationEnd(animation);
175
- mStatus = Status.VISIBLE;
176
- promise.resolve(true);
177
- shiftNextTask();
178
- }
179
- })
180
- .start();
181
- } else {
182
- activity.addContentView(layout, params);
183
- mStatus = Status.VISIBLE;
184
- promise.resolve(true);
185
- shiftNextTask();
186
- }
187
- }
188
- });
189
- }
144
+ if (mSplashScreen == null || mStatus == Status.HIDDEN) {
145
+ promise.resolve(true);
146
+ shiftNextTask();
147
+ return;
148
+ }
190
149
 
191
- private void hide(final RNBootSplashTask task) {
192
150
  UiThreadUtil.runOnUiThread(new Runnable() {
193
151
  @Override
194
152
  public void run() {
195
- final Activity activity = getReactApplicationContext().getCurrentActivity();
196
- final Promise promise = task.getPromise();
197
-
198
153
  if (activity == null || activity.isFinishing()) {
199
- waitAndShiftNextTask();
154
+ waitAndRetry(); // Wait for activity to be ready
200
155
  return;
201
156
  }
202
157
 
203
- final LinearLayout layout = activity.findViewById(R.id.bootsplash_layout_id);
204
-
205
- if (layout == null) {
206
- promise.resolve(true); // splash screen is already hidden
207
- shiftNextTask();
208
- return;
158
+ if (fade) {
159
+ mStatus = Status.TRANSITIONING;
209
160
  }
210
161
 
211
- mStatus = Status.TRANSITIONING_TO_HIDDEN;
212
-
213
- final ViewGroup parent = (ViewGroup) layout.getParent();
214
-
215
- if (task.getFade()) {
216
- layout
217
- .animate()
218
- .setDuration(ANIMATION_DURATION)
219
- .alpha(0.0f)
220
- .setInterpolator(new AccelerateInterpolator())
221
- .setListener(new AnimatorListenerAdapter() {
222
- @Override
223
- public void onAnimationEnd(Animator animation) {
224
- super.onAnimationEnd(animation);
225
-
226
- if (parent != null)
227
- parent.removeView(layout);
228
-
229
- mStatus = Status.HIDDEN;
230
- promise.resolve(true);
231
- shiftNextTask();
232
- }
233
- }).start();
234
- } else {
235
- parent.removeView(layout);
236
- mStatus = Status.HIDDEN;
237
- promise.resolve(true);
238
- shiftNextTask();
239
- }
162
+ mShouldFade = fade;
163
+ mShouldKeepOnScreen = false;
164
+
165
+ final Timer timer = new Timer();
166
+
167
+ // We cannot rely on setOnExitAnimationListener
168
+ // See https://issuetracker.google.com/issues/197906327
169
+ timer.schedule(new TimerTask() {
170
+ @Override
171
+ public void run() {
172
+ mStatus = Status.HIDDEN;
173
+ promise.resolve(true);
174
+ timer.cancel();
175
+ shiftNextTask();
176
+ }
177
+ }, ANIMATION_DURATION);
240
178
  }
241
179
  });
242
180
  }
243
181
 
244
- @ReactMethod
245
- public void show(final boolean fade, final Promise promise) {
246
- if (mDrawableResId == -1) {
247
- promise.reject("uninitialized_module", "react-native-bootsplash has not been initialized");
248
- } else {
249
- mTaskQueue.add(new RNBootSplashTask(RNBootSplashTask.Type.SHOW, fade, promise));
250
- shiftNextTask();
251
- }
252
- }
253
-
254
182
  @ReactMethod
255
183
  public void hide(final boolean fade, final Promise promise) {
256
- if (mDrawableResId == -1) {
257
- promise.reject("uninitialized_module", "react-native-bootsplash has not been initialized");
184
+ if (mSplashScreen == null || mStatus == Status.HIDDEN) {
185
+ promise.resolve(true);
258
186
  } else {
259
- mTaskQueue.add(new RNBootSplashTask(RNBootSplashTask.Type.HIDE, fade, promise));
187
+ mTaskQueue.add(new RNBootSplashTask(fade, promise));
260
188
  shiftNextTask();
261
189
  }
262
190
  }
@@ -270,8 +198,7 @@ public class RNBootSplashModule extends ReactContextBaseJavaModule implements Li
270
198
  case HIDDEN:
271
199
  promise.resolve("hidden");
272
200
  break;
273
- case TRANSITIONING_TO_VISIBLE:
274
- case TRANSITIONING_TO_HIDDEN:
201
+ case TRANSITIONING:
275
202
  promise.resolve("transitioning");
276
203
  break;
277
204
  }
@@ -1,5 +1,7 @@
1
1
  package com.zoontek.rnbootsplash;
2
2
 
3
+ import androidx.annotation.NonNull;
4
+
3
5
  import com.facebook.react.ReactPackage;
4
6
  import com.facebook.react.bridge.NativeModule;
5
7
  import com.facebook.react.bridge.ReactApplicationContext;
@@ -11,13 +13,15 @@ import java.util.List;
11
13
 
12
14
  public class RNBootSplashPackage implements ReactPackage {
13
15
 
16
+ @NonNull
14
17
  @Override
15
- public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
18
+ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
16
19
  return Arrays.<NativeModule>asList(new RNBootSplashModule(reactContext));
17
20
  }
18
21
 
22
+ @NonNull
19
23
  @Override
20
- public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
24
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
21
25
  return Collections.emptyList();
22
26
  }
23
27
  }
@@ -6,19 +6,10 @@ import com.facebook.react.bridge.Promise;
6
6
 
7
7
  public class RNBootSplashTask {
8
8
 
9
- public enum Type {
10
- SHOW,
11
- HIDE
12
- }
13
-
14
9
  private final boolean mFade;
15
10
  @NonNull private final Promise mPromise;
16
- @NonNull private final Type mType;
17
11
 
18
- public RNBootSplashTask(@NonNull Type type,
19
- boolean fade,
20
- @NonNull Promise promise) {
21
- mType = type;
12
+ public RNBootSplashTask(final boolean fade, @NonNull final Promise promise) {
22
13
  mFade = fade;
23
14
  mPromise = promise;
24
15
  }
@@ -27,11 +18,6 @@ public class RNBootSplashTask {
27
18
  return mFade;
28
19
  }
29
20
 
30
- @NonNull
31
- public Type getType() {
32
- return mType;
33
- }
34
-
35
21
  @NonNull
36
22
  public Promise getPromise() {
37
23
  return mPromise;