Browse Source

android: splash, removed singleton, dependency injection, fixed e2e

Daniel Zlotin 7 years ago
parent
commit
93f49300c2

+ 11
- 6
android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java View File

11
 import com.facebook.react.bridge.ReactContext;
11
 import com.facebook.react.bridge.ReactContext;
12
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
12
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
13
 import com.facebook.react.shell.MainReactPackage;
13
 import com.facebook.react.shell.MainReactPackage;
14
-import com.reactnativenavigation.R;
15
 import com.reactnativenavigation.react.NavigationEventEmitter;
14
 import com.reactnativenavigation.react.NavigationEventEmitter;
16
 import com.reactnativenavigation.react.NavigationPackage;
15
 import com.reactnativenavigation.react.NavigationPackage;
17
 import com.reactnativenavigation.react.ReactDevPermission;
16
 import com.reactnativenavigation.react.ReactDevPermission;
17
+import com.reactnativenavigation.views.NavigationSplashView;
18
 
18
 
19
 import java.util.Arrays;
19
 import java.util.Arrays;
20
 import java.util.List;
20
 import java.util.List;
26
     @Override
26
     @Override
27
     public void onCreate(Bundle savedInstanceState) {
27
     public void onCreate(Bundle savedInstanceState) {
28
         super.onCreate(savedInstanceState);
28
         super.onCreate(savedInstanceState);
29
-        setContentView(R.layout.splash);
29
+        setContentView(new NavigationSplashView(this));
30
+
30
         host = new ReactNativeHost(getApplication()) {
31
         host = new ReactNativeHost(getApplication()) {
31
             @Override
32
             @Override
32
             protected boolean getUseDeveloperSupport() {
33
             protected boolean getUseDeveloperSupport() {
37
             protected List<ReactPackage> getPackages() {
38
             protected List<ReactPackage> getPackages() {
38
                 return Arrays.asList(
39
                 return Arrays.asList(
39
                         new MainReactPackage(),
40
                         new MainReactPackage(),
40
-                        new NavigationPackage()
41
+                        new NavigationPackage(NavigationActivity.this)
41
                 );
42
                 );
42
             }
43
             }
43
         };
44
         };
69
             ReactDevPermission.askPermission(this);
70
             ReactDevPermission.askPermission(this);
70
         } else {
71
         } else {
71
             host.getReactInstanceManager().createReactContextInBackground();
72
             host.getReactInstanceManager().createReactContextInBackground();
73
+            host.getReactInstanceManager().onHostResume(this, this);
72
         }
74
         }
73
-        host.getReactInstanceManager().onHostResume(this, this);
74
     }
75
     }
75
 
76
 
76
     @Override
77
     @Override
77
     protected void onPause() {
78
     protected void onPause() {
78
         super.onPause();
79
         super.onPause();
79
-        host.getReactInstanceManager().onHostPause(this);
80
+        if (host.getReactInstanceManager().hasStartedCreatingInitialContext()) {
81
+            host.getReactInstanceManager().onHostPause(this);
82
+        }
80
     }
83
     }
81
 
84
 
82
     @Override
85
     @Override
83
     protected void onDestroy() {
86
     protected void onDestroy() {
84
         super.onDestroy();
87
         super.onDestroy();
85
-        host.getReactInstanceManager().onHostDestroy(this);
88
+        if (host.getReactInstanceManager().hasStartedCreatingInitialContext()) {
89
+            host.getReactInstanceManager().onHostDestroy(this);
90
+        }
86
     }
91
     }
87
 
92
 
88
     @Override
93
     @Override

+ 8
- 0
android/app/src/main/java/com/reactnativenavigation/controllers/NavigationApplication.java View File

1
 package com.reactnativenavigation.controllers;
1
 package com.reactnativenavigation.controllers;
2
 
2
 
3
 import android.app.Application;
3
 import android.app.Application;
4
+import android.os.Handler;
5
+import android.os.Looper;
4
 
6
 
5
 public abstract class NavigationApplication extends Application {
7
 public abstract class NavigationApplication extends Application {
6
     public static NavigationApplication instance;
8
     public static NavigationApplication instance;
9
+    private Handler handler;
7
 
10
 
8
     @Override
11
     @Override
9
     public void onCreate() {
12
     public void onCreate() {
10
         super.onCreate();
13
         super.onCreate();
11
         instance = this;
14
         instance = this;
15
+        handler = new Handler(Looper.getMainLooper());
16
+    }
17
+
18
+    public void runOnUiThread(Runnable runnable) {
19
+        handler.post(runnable);
12
     }
20
     }
13
 
21
 
14
     public abstract boolean isDebug();
22
     public abstract boolean isDebug();

+ 28
- 20
android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java View File

11
 import com.facebook.react.bridge.ReadableMap;
11
 import com.facebook.react.bridge.ReadableMap;
12
 import com.facebook.react.bridge.ReadableMapKeySetIterator;
12
 import com.facebook.react.bridge.ReadableMapKeySetIterator;
13
 import com.reactnativenavigation.controllers.NavigationActivity;
13
 import com.reactnativenavigation.controllers.NavigationActivity;
14
+import com.reactnativenavigation.controllers.NavigationApplication;
14
 import com.reactnativenavigation.layout.LayoutFactory;
15
 import com.reactnativenavigation.layout.LayoutFactory;
15
 import com.reactnativenavigation.layout.LayoutNode;
16
 import com.reactnativenavigation.layout.LayoutNode;
16
 import com.reactnativenavigation.layout.StackLayout;
17
 import com.reactnativenavigation.layout.StackLayout;
21
 import java.util.Map;
22
 import java.util.Map;
22
 
23
 
23
 public class NavigationModule extends ReactContextBaseJavaModule {
24
 public class NavigationModule extends ReactContextBaseJavaModule {
24
-    public static final String NAME = "RNNBridgeModule";
25
+    private static final String NAME = "RNNBridgeModule";
26
+    private final NavigationActivity activity;
25
 
27
 
26
-    public NavigationModule(ReactApplicationContext reactContext) {
27
-        super(reactContext);
28
+    public NavigationModule(ReactApplicationContext context, NavigationActivity activity) {
29
+        super(context);
30
+        this.activity = activity;
28
     }
31
     }
29
 
32
 
30
     @Override
33
     @Override
34
 
37
 
35
     @ReactMethod
38
     @ReactMethod
36
     public void setRoot(final ReadableMap layoutTree) {
39
     public void setRoot(final ReadableMap layoutTree) {
37
-        getActivity().runOnUiThread(new Runnable() {
40
+        NavigationApplication.instance.runOnUiThread(new Runnable() {
38
             @Override
41
             @Override
39
             public void run() {
42
             public void run() {
40
-                LayoutFactory factory =
41
-                        new LayoutFactory(getActivity(), new LayoutFactory.ReactRootViewCreator() {
42
-                            @Override
43
-                            public View create(String id, String name) {
44
-                                ReactRootView rootView = new ReactRootView(getActivity());
45
-                                Bundle opts = new Bundle();
46
-                                opts.putString("id", id);
47
-                                rootView.startReactApplication(getActivity().getHost().getReactInstanceManager(), name, opts);
48
-                                return rootView;
49
-                            }
50
-                        }, new BottomTabsCreator());
51
-
52
-                final LayoutNode layoutTreeRoot = readableMapToLayoutNode(layoutTree);
53
-                final View rootView = factory.create(layoutTreeRoot);
54
-                getActivity().setContentView(rootView);
43
+                getActivity().runOnUiThread(new Runnable() {
44
+                    @Override
45
+                    public void run() {
46
+                        LayoutFactory factory =
47
+                                new LayoutFactory(getActivity(), new LayoutFactory.ReactRootViewCreator() {
48
+                                    @Override
49
+                                    public View create(String id, String name) {
50
+                                        ReactRootView rootView = new ReactRootView(getActivity());
51
+                                        Bundle opts = new Bundle();
52
+                                        opts.putString("id", id);
53
+                                        rootView.startReactApplication(getActivity().getHost().getReactInstanceManager(), name, opts);
54
+                                        return rootView;
55
+                                    }
56
+                                }, new BottomTabsCreator());
57
+
58
+                        final LayoutNode layoutTreeRoot = readableMapToLayoutNode(layoutTree);
59
+                        final View rootView = factory.create(layoutTreeRoot);
60
+                        getActivity().setContentView(rootView);
61
+                    }
62
+                });
55
             }
63
             }
56
         });
64
         });
57
     }
65
     }
58
 
66
 
59
     private NavigationActivity getActivity() {
67
     private NavigationActivity getActivity() {
60
-        return (NavigationActivity) getCurrentActivity();
68
+        return activity;
61
     }
69
     }
62
 
70
 
63
     @ReactMethod
71
     @ReactMethod

+ 8
- 1
android/app/src/main/java/com/reactnativenavigation/react/NavigationPackage.java View File

5
 import com.facebook.react.bridge.NativeModule;
5
 import com.facebook.react.bridge.NativeModule;
6
 import com.facebook.react.bridge.ReactApplicationContext;
6
 import com.facebook.react.bridge.ReactApplicationContext;
7
 import com.facebook.react.uimanager.ViewManager;
7
 import com.facebook.react.uimanager.ViewManager;
8
+import com.reactnativenavigation.controllers.NavigationActivity;
8
 
9
 
9
 import java.util.Arrays;
10
 import java.util.Arrays;
10
 import java.util.Collections;
11
 import java.util.Collections;
12
 
13
 
13
 public class NavigationPackage implements ReactPackage {
14
 public class NavigationPackage implements ReactPackage {
14
 
15
 
16
+    private final NavigationActivity activity;
17
+
18
+    public NavigationPackage(NavigationActivity activity) {
19
+        this.activity = activity;
20
+    }
21
+
15
     @Override
22
     @Override
16
     public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
23
     public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
17
         return Arrays.<NativeModule>asList(
24
         return Arrays.<NativeModule>asList(
18
-                new NavigationModule(reactContext)
25
+                new NavigationModule(reactContext, activity)
19
         );
26
         );
20
     }
27
     }
21
 
28
 

+ 4
- 1
android/app/src/main/java/com/reactnativenavigation/react/ReactDevPermission.java View File

13
 
13
 
14
 public class ReactDevPermission {
14
 public class ReactDevPermission {
15
 
15
 
16
+    private static boolean hasRequestedPermissions = false;
17
+
16
     public static boolean shouldAskPermission() {
18
     public static boolean shouldAskPermission() {
17
-        return NavigationApplication.instance.isDebug() &&
19
+        return !hasRequestedPermissions && NavigationApplication.instance.isDebug() &&
18
                 Build.VERSION.SDK_INT >= 23 &&
20
                 Build.VERSION.SDK_INT >= 23 &&
19
                 !Settings.canDrawOverlays(NavigationApplication.instance);
21
                 !Settings.canDrawOverlays(NavigationApplication.instance);
20
     }
22
     }
22
     @TargetApi(23)
24
     @TargetApi(23)
23
     public static void askPermission(Context context) {
25
     public static void askPermission(Context context) {
24
         if (shouldAskPermission()) {
26
         if (shouldAskPermission()) {
27
+            hasRequestedPermissions = true;
25
             Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
28
             Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
26
             context.startActivity(serviceIntent);
29
             context.startActivity(serviceIntent);
27
             String msg = "Overlay permissions needs to be granted in order for react native apps to run in dev mode";
30
             String msg = "Overlay permissions needs to be granted in order for react native apps to run in dev mode";

+ 16
- 0
android/app/src/main/java/com/reactnativenavigation/views/NavigationSplashView.java View File

1
+package com.reactnativenavigation.views;
2
+
3
+import android.content.Context;
4
+import android.widget.FrameLayout;
5
+import android.widget.ImageView;
6
+
7
+import com.reactnativenavigation.R;
8
+
9
+public class NavigationSplashView extends FrameLayout {
10
+    public NavigationSplashView(Context context) {
11
+        super(context);
12
+        ImageView image = new ImageView(context);
13
+        image.setImageResource(R.drawable.logo);
14
+        addView(image);
15
+    }
16
+}

BIN
android/app/src/main/res/drawable-xxhdpi/logo.png View File


+ 1
- 0
playground/android/app/build.gradle View File

24
     compile project(':react-native-navigation')
24
     compile project(':react-native-navigation')
25
 
25
 
26
     // native e2e
26
     // native e2e
27
+    androidTestCompile 'org.assertj:assertj-core:2.5.0'
27
     androidTestCompile 'com.android.support:support-annotations:25.1.1'
28
     androidTestCompile 'com.android.support:support-annotations:25.1.1'
28
     androidTestCompile 'com.android.support.test:runner:0.5'
29
     androidTestCompile 'com.android.support.test:runner:0.5'
29
     androidTestCompile 'com.android.support.test:rules:0.5'
30
     androidTestCompile 'com.android.support.test:rules:0.5'

+ 9
- 5
playground/android/app/src/androidTest/java/com/reactnativenavigation/playground/ApplicationLifecycleTest.java View File

12
 
12
 
13
 import com.facebook.react.ReactNativeHost;
13
 import com.facebook.react.ReactNativeHost;
14
 import com.reactnativenavigation.controllers.NavigationActivity;
14
 import com.reactnativenavigation.controllers.NavigationActivity;
15
+import com.reactnativenavigation.views.NavigationSplashView;
15
 
16
 
16
 import org.junit.Rule;
17
 import org.junit.Rule;
17
 import org.junit.Test;
18
 import org.junit.Test;
22
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
23
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
23
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
24
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
24
 import static android.support.test.espresso.matcher.ViewMatchers.withText;
25
 import static android.support.test.espresso.matcher.ViewMatchers.withText;
26
+import static org.assertj.core.api.Java6Assertions.assertThat;
25
 import static org.junit.Assume.assumeFalse;
27
 import static org.junit.Assume.assumeFalse;
26
 import static org.junit.Assume.assumeTrue;
28
 import static org.junit.Assume.assumeTrue;
27
 
29
 
78
         rule.launchActivity(null);
80
         rule.launchActivity(null);
79
     }
81
     }
80
 
82
 
81
-    private void acceptPermissionIfNeeded() throws Exception {
83
+    private void acceptOverlayPermissionIfNeeded() throws Exception {
82
         if (Settings.canDrawOverlays(getInstrumentation().getContext())) {
84
         if (Settings.canDrawOverlays(getInstrumentation().getContext())) {
83
             return;
85
             return;
84
         }
86
         }
88
         UiDevice.getInstance(getInstrumentation()).pressBack();
90
         UiDevice.getInstance(getInstrumentation()).pressBack();
89
     }
91
     }
90
 
92
 
91
-
92
     @Test
93
     @Test
93
-    public void startApp_HandleOverlayPermissions_LoadsBridge_ThenShowsWelcomeScreen() throws Exception {
94
+    public void startApp_RequiredOverlayPermissions_LoadsBridge_ThenShowsWelcomeScreen() throws Exception {
94
         assumeFalse(Settings.canDrawOverlays(getInstrumentation().getContext()));
95
         assumeFalse(Settings.canDrawOverlays(getInstrumentation().getContext()));
95
         launchActivity();
96
         launchActivity();
96
-        acceptPermissionIfNeeded();
97
+        acceptOverlayPermissionIfNeeded();
97
         onView(withText("React Native Navigation!")).check(matches(isDisplayed()));
98
         onView(withText("React Native Navigation!")).check(matches(isDisplayed()));
98
     }
99
     }
99
 
100
 
105
     }
106
     }
106
 
107
 
107
     @Test
108
     @Test
108
-    public void () {
109
+    public void showsSplashOnStartup() throws Exception {
110
+        launchActivity();
111
+        assertThat(rule.getActivity().getContentView()).isNotNull().isInstanceOf(NavigationSplashView.class);
112
+        acceptOverlayPermissionIfNeeded();
109
     }
113
     }
110
 }
114
 }