Ver código fonte

Ensure appLaunched event is emitted only when app is resumed

Under certain conditions, app launched event was emitted when the Android Activity isn't in resumed state. In this case, setting root isn't possible since ReactContext doesn't have an instance of the Activity (it can even be destroyed).

This PR ensures the event is emitted only when the Activity is resumed and root can be set.
Guy Carmeli 5 anos atrás
pai
commit
21584fd4a5
Nenhuma conta vinculada ao e-mail do autor do commit

+ 13
- 7
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java Ver arquivo

38
 
38
 
39
 public class LayoutFactory {
39
 public class LayoutFactory {
40
 
40
 
41
-	private final Activity activity;
42
-    private final ChildControllersRegistry childRegistry;
41
+	private Activity activity;
42
+    private ChildControllersRegistry childRegistry;
43
 	private final ReactInstanceManager reactInstanceManager;
43
 	private final ReactInstanceManager reactInstanceManager;
44
     private EventEmitter eventEmitter;
44
     private EventEmitter eventEmitter;
45
     private Map<String, ExternalComponentCreator> externalComponentCreators;
45
     private Map<String, ExternalComponentCreator> externalComponentCreators;
46
     private Options defaultOptions;
46
     private Options defaultOptions;
47
-    private final TypefaceLoader typefaceManager;
47
+    private TypefaceLoader typefaceManager;
48
 
48
 
49
-    public LayoutFactory(Activity activity, ChildControllersRegistry childRegistry, final ReactInstanceManager reactInstanceManager, EventEmitter eventEmitter, Map<String, ExternalComponentCreator> externalComponentCreators, Options defaultOptions) {
50
-		this.activity = activity;
51
-        this.childRegistry = childRegistry;
49
+    public void setDefaultOptions(Options defaultOptions) {
50
+        this.defaultOptions = defaultOptions;
51
+    }
52
+
53
+    public LayoutFactory(final ReactInstanceManager reactInstanceManager) {
52
         this.reactInstanceManager = reactInstanceManager;
54
         this.reactInstanceManager = reactInstanceManager;
55
+    }
56
+
57
+    public void init(Activity activity, EventEmitter eventEmitter, ChildControllersRegistry childRegistry, Map<String, ExternalComponentCreator> externalComponentCreators) {
58
+        this.activity = activity;
53
         this.eventEmitter = eventEmitter;
59
         this.eventEmitter = eventEmitter;
60
+        this.childRegistry = childRegistry;
54
         this.externalComponentCreators = externalComponentCreators;
61
         this.externalComponentCreators = externalComponentCreators;
55
-        this.defaultOptions = defaultOptions;
56
         typefaceManager = new TypefaceLoader(activity);
62
         typefaceManager = new TypefaceLoader(activity);
57
     }
63
     }
58
 
64
 

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/parse/parsers/JSONParser.java Ver arquivo

9
 import org.json.JSONObject;
9
 import org.json.JSONObject;
10
 
10
 
11
 public class JSONParser {
11
 public class JSONParser {
12
-    public static JSONObject parse(ReadableMap map) {
12
+    public JSONObject parse(ReadableMap map) {
13
         try {
13
         try {
14
             ReadableMapKeySetIterator it = map.keySetIterator();
14
             ReadableMapKeySetIterator it = map.keySetIterator();
15
             JSONObject result = new JSONObject();
15
             JSONObject result = new JSONObject();
41
         }
41
         }
42
     }
42
     }
43
 
43
 
44
-    public static JSONArray parse(ReadableArray arr) {
44
+    public JSONArray parse(ReadableArray arr) {
45
         JSONArray result = new JSONArray();
45
         JSONArray result = new JSONArray();
46
         for (int i = 0; i < arr.size(); i++) {
46
         for (int i = 0; i < arr.size(); i++) {
47
             switch (arr.getType(i)) {
47
             switch (arr.getType(i)) {

+ 20
- 0
lib/android/app/src/main/java/com/reactnativenavigation/react/LifecycleEventListenerAdapter.java Ver arquivo

1
+package com.reactnativenavigation.react;
2
+
3
+import com.facebook.react.bridge.LifecycleEventListener;
4
+
5
+public class LifecycleEventListenerAdapter implements LifecycleEventListener {
6
+    @Override
7
+    public void onHostResume() {
8
+
9
+    }
10
+
11
+    @Override
12
+    public void onHostPause() {
13
+
14
+    }
15
+
16
+    @Override
17
+    public void onHostDestroy() {
18
+
19
+    }
20
+}

+ 103
- 95
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java Ver arquivo

25
 import com.reactnativenavigation.utils.UiThread;
25
 import com.reactnativenavigation.utils.UiThread;
26
 import com.reactnativenavigation.utils.UiUtils;
26
 import com.reactnativenavigation.utils.UiUtils;
27
 import com.reactnativenavigation.viewcontrollers.ViewController;
27
 import com.reactnativenavigation.viewcontrollers.ViewController;
28
-import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalComponentCreator;
29
 import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
28
 import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
30
 
29
 
31
 import java.util.ArrayList;
30
 import java.util.ArrayList;
32
-import java.util.Map;
33
 
31
 
34
 public class NavigationModule extends ReactContextBaseJavaModule {
32
 public class NavigationModule extends ReactContextBaseJavaModule {
35
-	private static final String NAME = "RNNBridgeModule";
33
+    private static final String NAME = "RNNBridgeModule";
36
 
34
 
37
     private final Now now = new Now();
35
     private final Now now = new Now();
38
-	private final ReactInstanceManager reactInstanceManager;
36
+    private final ReactInstanceManager reactInstanceManager;
37
+    private final JSONParser jsonParser;
38
+    private final LayoutFactory layoutFactory;
39
     private EventEmitter eventEmitter;
39
     private EventEmitter eventEmitter;
40
 
40
 
41
     @SuppressWarnings("WeakerAccess")
41
     @SuppressWarnings("WeakerAccess")
42
-    public NavigationModule(ReactApplicationContext reactContext, ReactInstanceManager reactInstanceManager) {
43
-		super(reactContext);
44
-		this.reactInstanceManager = reactInstanceManager;
45
-		reactInstanceManager.addReactInstanceEventListener(context -> eventEmitter = new EventEmitter(context));
42
+    public NavigationModule(ReactApplicationContext reactContext, ReactInstanceManager reactInstanceManager, LayoutFactory layoutFactory) {
43
+        this(reactContext, reactInstanceManager, new JSONParser(), layoutFactory);
46
     }
44
     }
47
 
45
 
48
-	@Override
49
-	public String getName() {
50
-		return NAME;
51
-	}
46
+    public NavigationModule(ReactApplicationContext reactContext, ReactInstanceManager reactInstanceManager, JSONParser jsonParser, LayoutFactory layoutFactory) {
47
+        super(reactContext);
48
+        this.reactInstanceManager = reactInstanceManager;
49
+        this.jsonParser = jsonParser;
50
+        this.layoutFactory = layoutFactory;
51
+        reactContext.addLifecycleEventListener(new LifecycleEventListenerAdapter() {
52
+            @Override
53
+            public void onHostResume() {
54
+                eventEmitter = new EventEmitter(reactContext);
55
+                navigator().setEventEmitter(eventEmitter);
56
+                layoutFactory.init(
57
+                        activity(),
58
+                        eventEmitter,
59
+                        navigator().getChildRegistry(),
60
+                        ((NavigationApplication) activity().getApplication()).getExternalComponents()
61
+                );
62
+            }
63
+        });
64
+    }
65
+
66
+    @NonNull
67
+    @Override
68
+    public String getName() {
69
+        return NAME;
70
+    }
52
 
71
 
53
-	@ReactMethod
72
+    @ReactMethod
54
     public void getConstants(Promise promise) {
73
     public void getConstants(Promise promise) {
55
         ReactApplicationContext ctx = getReactApplicationContext();
74
         ReactApplicationContext ctx = getReactApplicationContext();
56
         WritableMap constants = Arguments.createMap();
75
         WritableMap constants = Arguments.createMap();
57
-        constants.putString(Constants.BACK_BUTTON_JS_KEY,    Constants.BACK_BUTTON_ID);
58
-        constants.putDouble(Constants.BOTTOM_TABS_HEIGHT_KEY,    Constants.BOTTOM_TABS_HEIGHT);
76
+        constants.putString(Constants.BACK_BUTTON_JS_KEY, Constants.BACK_BUTTON_ID);
77
+        constants.putDouble(Constants.BOTTOM_TABS_HEIGHT_KEY, Constants.BOTTOM_TABS_HEIGHT);
59
         constants.putDouble(Constants.STATUS_BAR_HEIGHT_KEY, UiUtils.pxToDp(ctx, UiUtils.getStatusBarHeight(ctx)));
78
         constants.putDouble(Constants.STATUS_BAR_HEIGHT_KEY, UiUtils.pxToDp(ctx, UiUtils.getStatusBarHeight(ctx)));
60
-        constants.putDouble(Constants.TOP_BAR_HEIGHT_KEY,    UiUtils.pxToDp(ctx, UiUtils.getTopBarHeight(ctx)));
79
+        constants.putDouble(Constants.TOP_BAR_HEIGHT_KEY, UiUtils.pxToDp(ctx, UiUtils.getTopBarHeight(ctx)));
61
         promise.resolve(constants);
80
         promise.resolve(constants);
62
     }
81
     }
63
 
82
 
64
-	@ReactMethod
65
-	public void setRoot(String commandId, ReadableMap rawLayoutTree, Promise promise) {
66
-        final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree).optJSONObject("root"));
67
-		handle(() -> {
68
-            navigator().setEventEmitter(eventEmitter);
69
-            final ViewController viewController = newLayoutFactory().create(layoutTree);
83
+    @ReactMethod
84
+    public void setRoot(String commandId, ReadableMap rawLayoutTree, Promise promise) {
85
+        final LayoutNode layoutTree = LayoutNodeParser.parse(jsonParser.parse(rawLayoutTree).optJSONObject("root"));
86
+        handle(() -> {
87
+            final ViewController viewController = layoutFactory.create(layoutTree);
70
             navigator().setRoot(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now), reactInstanceManager);
88
             navigator().setRoot(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now), reactInstanceManager);
71
         });
89
         });
72
-	}
90
+    }
73
 
91
 
74
-	@ReactMethod
75
-	public void setDefaultOptions(ReadableMap options) {
76
-        handle(() -> navigator().setDefaultOptions(parse(options)));
92
+    @ReactMethod
93
+    public void setDefaultOptions(ReadableMap options) {
94
+        handle(() -> {
95
+            Options defaultOptions = parse(options);
96
+            layoutFactory.setDefaultOptions(defaultOptions);
97
+            navigator().setDefaultOptions(defaultOptions);
98
+        });
77
     }
99
     }
78
 
100
 
79
-	@ReactMethod
80
-	public void mergeOptions(String onComponentId, @Nullable ReadableMap options) {
81
-		handle(() -> navigator().mergeOptions(onComponentId, parse(options)));
82
-	}
101
+    @ReactMethod
102
+    public void mergeOptions(String onComponentId, @Nullable ReadableMap options) {
103
+        handle(() -> navigator().mergeOptions(onComponentId, parse(options)));
104
+    }
83
 
105
 
84
-	@ReactMethod
85
-	public void push(String commandId, String onComponentId, ReadableMap rawLayoutTree, Promise promise) {
86
-        final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree));
87
-		handle(() -> {
88
-            final ViewController viewController = newLayoutFactory().create(layoutTree);
106
+    @ReactMethod
107
+    public void push(String commandId, String onComponentId, ReadableMap rawLayoutTree, Promise promise) {
108
+        final LayoutNode layoutTree = LayoutNodeParser.parse(jsonParser.parse(rawLayoutTree));
109
+        handle(() -> {
110
+            final ViewController viewController = layoutFactory.create(layoutTree);
89
             navigator().push(onComponentId, viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
111
             navigator().push(onComponentId, viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
90
         });
112
         });
91
-	}
113
+    }
92
 
114
 
93
     @ReactMethod
115
     @ReactMethod
94
     public void setStackRoot(String commandId, String onComponentId, ReadableArray children, Promise promise) {
116
     public void setStackRoot(String commandId, String onComponentId, ReadableArray children, Promise promise) {
95
         handle(() -> {
117
         handle(() -> {
96
             ArrayList<ViewController> _children = new ArrayList();
118
             ArrayList<ViewController> _children = new ArrayList();
97
             for (int i = 0; i < children.size(); i++) {
119
             for (int i = 0; i < children.size(); i++) {
98
-                final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(children.getMap(i)));
99
-                _children.add(newLayoutFactory().create(layoutTree));
120
+                final LayoutNode layoutTree = LayoutNodeParser.parse(jsonParser.parse(children.getMap(i)));
121
+                _children.add(layoutFactory.create(layoutTree));
100
             }
122
             }
101
             navigator().setStackRoot(onComponentId, _children, new NativeCommandListener(commandId, promise, eventEmitter, now));
123
             navigator().setStackRoot(onComponentId, _children, new NativeCommandListener(commandId, promise, eventEmitter, now));
102
         });
124
         });
103
     }
125
     }
104
 
126
 
105
-	@ReactMethod
106
-	public void pop(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
107
-		handle(() -> navigator().pop(componentId, parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
108
-	}
127
+    @ReactMethod
128
+    public void pop(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
129
+        handle(() -> navigator().pop(componentId, parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
130
+    }
109
 
131
 
110
-	@ReactMethod
111
-	public void popTo(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
112
-		handle(() -> navigator().popTo(componentId, parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
113
-	}
132
+    @ReactMethod
133
+    public void popTo(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
134
+        handle(() -> navigator().popTo(componentId, parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
135
+    }
114
 
136
 
115
-	@ReactMethod
116
-	public void popToRoot(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
117
-		handle(() -> navigator().popToRoot(componentId, parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
118
-	}
137
+    @ReactMethod
138
+    public void popToRoot(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
139
+        handle(() -> navigator().popToRoot(componentId, parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
140
+    }
119
 
141
 
120
-	@ReactMethod
121
-	public void showModal(String commandId, ReadableMap rawLayoutTree, Promise promise) {
122
-		final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree));
123
-		handle(() -> {
124
-            final ViewController viewController = newLayoutFactory().create(layoutTree);
142
+    @ReactMethod
143
+    public void showModal(String commandId, ReadableMap rawLayoutTree, Promise promise) {
144
+        final LayoutNode layoutTree = LayoutNodeParser.parse(jsonParser.parse(rawLayoutTree));
145
+        handle(() -> {
146
+            final ViewController viewController = layoutFactory.create(layoutTree);
125
             navigator().showModal(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
147
             navigator().showModal(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
126
         });
148
         });
127
-	}
149
+    }
128
 
150
 
129
-	@ReactMethod
130
-	public void dismissModal(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
131
-		handle(() -> {
151
+    @ReactMethod
152
+    public void dismissModal(String commandId, String componentId, @Nullable ReadableMap mergeOptions, Promise promise) {
153
+        handle(() -> {
132
             navigator().mergeOptions(componentId, parse(mergeOptions));
154
             navigator().mergeOptions(componentId, parse(mergeOptions));
133
             navigator().dismissModal(componentId, new NativeCommandListener(commandId, promise, eventEmitter, now));
155
             navigator().dismissModal(componentId, new NativeCommandListener(commandId, promise, eventEmitter, now));
134
         });
156
         });
135
-	}
157
+    }
136
 
158
 
137
     @ReactMethod
159
     @ReactMethod
138
-	public void dismissAllModals(String commandId, @Nullable ReadableMap mergeOptions, Promise promise) {
139
-		handle(() -> navigator().dismissAllModals(parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
140
-	}
160
+    public void dismissAllModals(String commandId, @Nullable ReadableMap mergeOptions, Promise promise) {
161
+        handle(() -> navigator().dismissAllModals(parse(mergeOptions), new NativeCommandListener(commandId, promise, eventEmitter, now)));
162
+    }
141
 
163
 
142
-	@ReactMethod
143
-	public void showOverlay(String commandId, ReadableMap rawLayoutTree, Promise promise) {
144
-        final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree));
164
+    @ReactMethod
165
+    public void showOverlay(String commandId, ReadableMap rawLayoutTree, Promise promise) {
166
+        final LayoutNode layoutTree = LayoutNodeParser.parse(jsonParser.parse(rawLayoutTree));
145
         handle(() -> {
167
         handle(() -> {
146
-            final ViewController viewController = newLayoutFactory().create(layoutTree);
168
+            final ViewController viewController = layoutFactory.create(layoutTree);
147
             navigator().showOverlay(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
169
             navigator().showOverlay(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
148
         });
170
         });
149
-	}
150
-
151
-	@ReactMethod
152
-	public void dismissOverlay(String commandId, String componentId, Promise promise) {
153
-		handle(() -> navigator().dismissOverlay(componentId, new NativeCommandListener(commandId, promise, eventEmitter, now)));
154
-	}
155
-
156
-	private Navigator navigator() {
157
-		return activity().getNavigator();
158
-	}
171
+    }
159
 
172
 
160
-	@NonNull
161
-	private LayoutFactory newLayoutFactory() {
162
-		return new LayoutFactory(activity(),
163
-                navigator().getChildRegistry(),
164
-                reactInstanceManager,
165
-                eventEmitter,
166
-                externalComponentCreator(),
167
-                navigator().getDefaultOptions()
168
-        );
169
-	}
173
+    @ReactMethod
174
+    public void dismissOverlay(String commandId, String componentId, Promise promise) {
175
+        handle(() -> navigator().dismissOverlay(componentId, new NativeCommandListener(commandId, promise, eventEmitter, now)));
176
+    }
170
 
177
 
171
-    private  Options parse(@Nullable ReadableMap mergeOptions) {
172
-        return mergeOptions == null ? Options.EMPTY : Options.parse(new TypefaceLoader(activity()), JSONParser.parse(mergeOptions));
178
+    private Navigator navigator() {
179
+        return activity().getNavigator();
173
     }
180
     }
174
 
181
 
175
-	private Map<String, ExternalComponentCreator> externalComponentCreator() {
176
-        return ((NavigationApplication) activity().getApplication()).getExternalComponents();
182
+    private Options parse(@Nullable ReadableMap mergeOptions) {
183
+        return mergeOptions ==
184
+               null ? Options.EMPTY : Options.parse(new TypefaceLoader(activity()), jsonParser.parse(mergeOptions));
177
     }
185
     }
178
 
186
 
179
-	private void handle(Runnable task) {
180
-		if (activity() == null || activity().isFinishing()) return;
181
-		UiThread.post(task);
182
-	}
187
+    private void handle(Runnable task) {
188
+        if (activity() == null || activity().isFinishing()) return;
189
+        UiThread.post(task);
190
+    }
183
 
191
 
184
     private NavigationActivity activity() {
192
     private NavigationActivity activity() {
185
         return (NavigationActivity) getCurrentActivity();
193
         return (NavigationActivity) getCurrentActivity();

+ 20
- 10
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationPackage.java Ver arquivo

1
 package com.reactnativenavigation.react;
1
 package com.reactnativenavigation.react;
2
 
2
 
3
+import android.support.annotation.NonNull;
4
+
3
 import com.facebook.react.ReactNativeHost;
5
 import com.facebook.react.ReactNativeHost;
4
 import com.facebook.react.ReactPackage;
6
 import com.facebook.react.ReactPackage;
5
 import com.facebook.react.bridge.NativeModule;
7
 import com.facebook.react.bridge.NativeModule;
6
 import com.facebook.react.bridge.ReactApplicationContext;
8
 import com.facebook.react.bridge.ReactApplicationContext;
7
 import com.facebook.react.uimanager.ViewManager;
9
 import com.facebook.react.uimanager.ViewManager;
10
+import com.reactnativenavigation.parse.LayoutFactory;
8
 
11
 
9
 import java.util.Collections;
12
 import java.util.Collections;
10
 import java.util.List;
13
 import java.util.List;
11
 
14
 
12
 public class NavigationPackage implements ReactPackage {
15
 public class NavigationPackage implements ReactPackage {
13
 
16
 
14
-	private ReactNativeHost reactNativeHost;
17
+    private ReactNativeHost reactNativeHost;
15
 
18
 
16
-	@SuppressWarnings("WeakerAccess")
19
+    @SuppressWarnings("WeakerAccess")
17
     public NavigationPackage(final ReactNativeHost reactNativeHost) {
20
     public NavigationPackage(final ReactNativeHost reactNativeHost) {
18
-		this.reactNativeHost = reactNativeHost;
19
-	}
21
+        this.reactNativeHost = reactNativeHost;
22
+    }
20
 
23
 
21
-	@Override
22
-	public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
23
-		return Collections.singletonList(new NavigationModule(reactContext, reactNativeHost.getReactInstanceManager()));
24
-	}
24
+    @NonNull
25
+    @Override
26
+    public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
27
+        return Collections.singletonList(new NavigationModule(
28
+                        reactContext,
29
+                        reactNativeHost.getReactInstanceManager(),
30
+                        new LayoutFactory(reactNativeHost.getReactInstanceManager())
31
+                )
32
+        );
33
+    }
25
 
34
 
26
-	@Override
27
-	public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
35
+    @NonNull
36
+    @Override
37
+    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
28
         return Collections.singletonList(new ElementViewManager());
38
         return Collections.singletonList(new ElementViewManager());
29
     }
39
     }
30
 }
40
 }

+ 9
- 5
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationReactInitializer.java Ver arquivo

11
 	private final ReactInstanceManager reactInstanceManager;
11
 	private final ReactInstanceManager reactInstanceManager;
12
 	private final DevPermissionRequest devPermissionRequest;
12
 	private final DevPermissionRequest devPermissionRequest;
13
 	private boolean waitingForAppLaunchEvent = true;
13
 	private boolean waitingForAppLaunchEvent = true;
14
+	private boolean isActivityReadyForUi = false;
14
 
15
 
15
-	public NavigationReactInitializer(ReactInstanceManager reactInstanceManager, boolean isDebug) {
16
+	NavigationReactInitializer(ReactInstanceManager reactInstanceManager, boolean isDebug) {
16
 		this.reactInstanceManager = reactInstanceManager;
17
 		this.reactInstanceManager = reactInstanceManager;
17
 		this.devPermissionRequest = new DevPermissionRequest(isDebug);
18
 		this.devPermissionRequest = new DevPermissionRequest(isDebug);
18
 	}
19
 	}
19
 
20
 
20
-	public void onActivityCreated(final NavigationActivity activity) {
21
+	void onActivityCreated() {
21
 		reactInstanceManager.addReactInstanceEventListener(this);
22
 		reactInstanceManager.addReactInstanceEventListener(this);
22
 		waitingForAppLaunchEvent = true;
23
 		waitingForAppLaunchEvent = true;
23
 	}
24
 	}
24
 
25
 
25
-	public void onActivityResumed(NavigationActivity activity) {
26
+	void onActivityResumed(NavigationActivity activity) {
26
 		if (devPermissionRequest.shouldAskPermission(activity)) {
27
 		if (devPermissionRequest.shouldAskPermission(activity)) {
27
 			devPermissionRequest.askPermission(activity);
28
 			devPermissionRequest.askPermission(activity);
28
 		} else {
29
 		} else {
29
 			reactInstanceManager.onHostResume(activity, activity);
30
 			reactInstanceManager.onHostResume(activity, activity);
31
+            isActivityReadyForUi = true;
30
 			prepareReactApp();
32
 			prepareReactApp();
31
 		}
33
 		}
32
 	}
34
 	}
33
 
35
 
34
-	public void onActivityPaused(NavigationActivity activity) {
36
+	void onActivityPaused(NavigationActivity activity) {
37
+        isActivityReadyForUi = false;
35
 		if (reactInstanceManager.hasStartedCreatingInitialContext()) {
38
 		if (reactInstanceManager.hasStartedCreatingInitialContext()) {
36
 			reactInstanceManager.onHostPause(activity);
39
 			reactInstanceManager.onHostPause(activity);
37
 		}
40
 		}
38
 	}
41
 	}
39
 
42
 
40
-	public void onActivityDestroyed(NavigationActivity activity) {
43
+	void onActivityDestroyed(NavigationActivity activity) {
41
 		reactInstanceManager.removeReactInstanceEventListener(this);
44
 		reactInstanceManager.removeReactInstanceEventListener(this);
42
 		if (reactInstanceManager.hasStartedCreatingInitialContext()) {
45
 		if (reactInstanceManager.hasStartedCreatingInitialContext()) {
43
 			reactInstanceManager.onHostDestroy(activity);
46
 			reactInstanceManager.onHostDestroy(activity);
55
 	}
58
 	}
56
 
59
 
57
 	private void emitAppLaunched(@NonNull ReactContext context) {
60
 	private void emitAppLaunched(@NonNull ReactContext context) {
61
+	    if (!isActivityReadyForUi) return;
58
 		waitingForAppLaunchEvent = false;
62
 		waitingForAppLaunchEvent = false;
59
 		new EventEmitter(context).appLaunched();
63
 		new EventEmitter(context).appLaunched();
60
 	}
64
 	}

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/react/ReactGateway.java Ver arquivo

37
 	}
37
 	}
38
 
38
 
39
 	public void onActivityCreated(NavigationActivity activity) {
39
 	public void onActivityCreated(NavigationActivity activity) {
40
-		initializer.onActivityCreated(activity);
40
+		initializer.onActivityCreated();
41
         jsDevReloadHandler.setReloadListener(activity);
41
         jsDevReloadHandler.setReloadListener(activity);
42
 	}
42
 	}
43
 
43
 

+ 2
- 2
lib/android/app/src/test/java/com/reactnativenavigation/parse/parsers/JSONParserTest.java Ver arquivo

22
         input.putMap("keyMap", new JavaOnlyMap());
22
         input.putMap("keyMap", new JavaOnlyMap());
23
         input.putNull("bla");
23
         input.putNull("bla");
24
 
24
 
25
-        JSONObject result = JSONParser.parse(input);
25
+        JSONObject result = new JSONParser().parse(input);
26
 
26
 
27
 
27
 
28
         assertThat(result.keys()).containsOnly(
28
         assertThat(result.keys()).containsOnly(
52
         input.pushMap(new JavaOnlyMap());
52
         input.pushMap(new JavaOnlyMap());
53
         input.pushNull();
53
         input.pushNull();
54
 
54
 
55
-        JSONArray result = JSONParser.parse(input);
55
+        JSONArray result = new JSONParser().parse(input);
56
         assertThat(result.length()).isEqualTo(6);
56
         assertThat(result.length()).isEqualTo(6);
57
         assertThat(result.get(0)).isEqualTo("Hello");
57
         assertThat(result.get(0)).isEqualTo("Hello");
58
         assertThat(result.get(1)).isEqualTo(123);
58
         assertThat(result.get(1)).isEqualTo(123);

+ 81
- 0
lib/android/app/src/test/java/com/reactnativenavigation/react/NavigationModuleTest.java Ver arquivo

1
+package com.reactnativenavigation.react;
2
+
3
+import com.facebook.react.ReactInstanceManager;
4
+import com.facebook.react.bridge.Promise;
5
+import com.facebook.react.bridge.ReactApplicationContext;
6
+import com.facebook.react.bridge.ReadableMap;
7
+import com.reactnativenavigation.BaseTest;
8
+import com.reactnativenavigation.NavigationActivity;
9
+import com.reactnativenavigation.parse.LayoutFactory;
10
+import com.reactnativenavigation.parse.LayoutNode;
11
+import com.reactnativenavigation.parse.parsers.JSONParser;
12
+import com.reactnativenavigation.viewcontrollers.ViewController;
13
+import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
14
+
15
+import org.json.JSONException;
16
+import org.json.JSONObject;
17
+import org.junit.Test;
18
+
19
+import static org.mockito.ArgumentMatchers.any;
20
+import static org.mockito.ArgumentMatchers.eq;
21
+import static org.mockito.Mockito.mock;
22
+import static org.mockito.Mockito.spy;
23
+import static org.mockito.Mockito.verify;
24
+import static org.mockito.Mockito.when;
25
+
26
+public class NavigationModuleTest extends BaseTest {
27
+    private NavigationModule uut;
28
+    private Navigator navigator;
29
+    private JSONParser jsonParser;
30
+    private NavigationActivity activity;
31
+    private ReactApplicationContext reactApplicationContext;
32
+    private LayoutFactory layoutFactory;
33
+
34
+    @Override
35
+    public void beforeEach() {
36
+        jsonParser = mock(JSONParser.class);
37
+        navigator = mock(Navigator.class);
38
+        activity = mockActivity();
39
+        reactApplicationContext = mock(ReactApplicationContext.class);
40
+        layoutFactory = mock(LayoutFactory.class);
41
+
42
+        uut = spy(new NavigationModule(
43
+                reactApplicationContext,
44
+                mock(ReactInstanceManager.class),
45
+                jsonParser,
46
+                layoutFactory
47
+        ));
48
+    }
49
+
50
+    @Test
51
+    public void setRoot_delegatesToNavigator() throws JSONException {
52
+        when(reactApplicationContext.getCurrentActivity()).thenReturn(activity);
53
+        ReadableMap root = mock(ReadableMap.class);
54
+        when(jsonParser.parse(root)).thenReturn(rootJson());
55
+        ViewController rootViewController = mock(ViewController.class);
56
+        when(layoutFactory.create(any(LayoutNode.class))).thenReturn(rootViewController);
57
+
58
+        uut.setRoot("1", root, mock(Promise.class));
59
+        verify(navigator).setRoot(eq(rootViewController), any(), any());
60
+    }
61
+
62
+    private NavigationActivity mockActivity() {
63
+        NavigationActivity activity = mock(NavigationActivity.class);
64
+        when(activity.getNavigator()).thenReturn(navigator);
65
+        return activity;
66
+    }
67
+
68
+    private JSONObject rootJson() throws JSONException {
69
+        JSONObject root = new JSONObject();
70
+        root.put("root", componentJson());
71
+        return root;
72
+    }
73
+
74
+    private JSONObject componentJson() throws JSONException {
75
+        JSONObject component = new JSONObject();
76
+        component.put("id", "Component1");
77
+        component.put("type", "Component");
78
+        component.put("data", new JSONObject().put("name", "mockComponent"));
79
+        return component;
80
+    }
81
+}

+ 2
- 2
package.json Ver arquivo

155
         "binaryPath": "playground/android/app/build/outputs/apk/debug/app-debug.apk",
155
         "binaryPath": "playground/android/app/build/outputs/apk/debug/app-debug.apk",
156
         "build": "cd playground/android && ./gradlew app:assembleDebug app:assembleAndroidTest -DtestBuildType=debug",
156
         "build": "cd playground/android && ./gradlew app:assembleDebug app:assembleAndroidTest -DtestBuildType=debug",
157
         "type": "android.emulator",
157
         "type": "android.emulator",
158
-        "name": "Nexus_5_API_25"
158
+        "name": "Nexus_5X_API_23"
159
       },
159
       },
160
       "android.emu.release.locked": {
160
       "android.emu.release.locked": {
161
         "binaryPath": "playground/android/app/build/outputs/apk/release/app-release.apk",
161
         "binaryPath": "playground/android/app/build/outputs/apk/release/app-release.apk",
162
         "build": "cd playground/android && ./gradlew app:assembleRelease app:assembleAndroidTest -DtestBuildType=release",
162
         "build": "cd playground/android && ./gradlew app:assembleRelease app:assembleAndroidTest -DtestBuildType=release",
163
         "type": "android.emulator",
163
         "type": "android.emulator",
164
-        "name": "Nexus_5_API_25"
164
+        "name": "Nexus_5X_API_23"
165
       }
165
       }
166
     }
166
     }
167
   }
167
   }