From 8f6740bb01dc5fbdfbf2e6004fe8d42d1dafe846 Mon Sep 17 00:00:00 2001 From: Benjamin Elo Date: Fri, 16 Aug 2019 07:13:49 -0700 Subject: [PATCH] Open source version of Navigation Plugin Summary: Here I have an early version of the Navigation Plugin (Android) for Open Source. A lot of apps will be using there own Navigation framework for handling deep links. In order to keep things as simple as possible, recording navigation events is done through a single function that can be called from anywhere in the app. This will allow users to place this function in there own navigation frameworks and use there own logic with it. Seperately, I have shown how this can be used with our Android sample app. I use the built in Android intent-filters to provide a demo of how this can potentially be used, and to form the basis of the docs that I will write. Reviewed By: passy, danielbuechele Differential Revision: D16828049 fbshipit-source-id: 22765f63ca0c471689d2ec5865fdfc155b92697f --- android/sample/AndroidManifest.xml | 14 ++++ .../flipper/sample/DeepLinkActivity.java | 31 +++++++++ .../sample/FlipperSampleApplication.java | 2 + .../facebook/flipper/sample/MainActivity.java | 4 ++ .../flipper/sample/RootComponentSpec.java | 12 ++++ .../navigation/NavigationFlipperPlugin.java | 66 +++++++++++++++++++ .../NavigationFlipperPluginTest.java | 37 +++++++++++ 7 files changed, 166 insertions(+) create mode 100644 android/sample/src/main/java/com/facebook/flipper/sample/DeepLinkActivity.java create mode 100644 android/src/main/java/com/facebook/flipper/plugins/navigation/NavigationFlipperPlugin.java create mode 100644 android/src/test/java/com/facebook/flipper/plugins/navigation/NavigationFlipperPluginTest.java diff --git a/android/sample/AndroidManifest.xml b/android/sample/AndroidManifest.xml index 0b8514c4b..b23319b47 100644 --- a/android/sample/AndroidManifest.xml +++ b/android/sample/AndroidManifest.xml @@ -25,6 +25,20 @@ + + + + + + + + + + + + + + diff --git a/android/sample/src/main/java/com/facebook/flipper/sample/DeepLinkActivity.java b/android/sample/src/main/java/com/facebook/flipper/sample/DeepLinkActivity.java new file mode 100644 index 000000000..3b66a5efb --- /dev/null +++ b/android/sample/src/main/java/com/facebook/flipper/sample/DeepLinkActivity.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + */ +package com.facebook.flipper.sample; + +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import com.facebook.flipper.plugins.navigation.NavigationFlipperPlugin; +import com.facebook.litho.Component; +import com.facebook.litho.ComponentContext; +import com.facebook.litho.LithoView; +import com.facebook.litho.widget.Text; + +public class DeepLinkActivity extends AppCompatActivity { + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + NavigationFlipperPlugin.getInstance().sendNavigationEvent("flipper://deep_link_activity/"); + + final ComponentContext context = new ComponentContext(this); + + final Component component = + Text.create(context).text("Welcome to the Deep Link Activity!").textSizeDip(40).build(); + + setContentView(LithoView.create(context, component)); + } +} diff --git a/android/sample/src/main/java/com/facebook/flipper/sample/FlipperSampleApplication.java b/android/sample/src/main/java/com/facebook/flipper/sample/FlipperSampleApplication.java index 7744515fa..c00bcec8e 100644 --- a/android/sample/src/main/java/com/facebook/flipper/sample/FlipperSampleApplication.java +++ b/android/sample/src/main/java/com/facebook/flipper/sample/FlipperSampleApplication.java @@ -12,6 +12,7 @@ import android.database.DatabaseUtils; import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.flipper.android.AndroidFlipperClient; import com.facebook.flipper.core.FlipperClient; +import com.facebook.flipper.plugins.navigation.NavigationFlipperPlugin; import com.facebook.flipper.sample.network.NetworkClient; import com.facebook.soloader.SoLoader; @@ -23,6 +24,7 @@ public class FlipperSampleApplication extends Application { Fresco.initialize(this); final FlipperClient client = AndroidFlipperClient.getInstance(this); + client.addPlugin(NavigationFlipperPlugin.getInstance()); final FlipperInitializer.IntializationResult initializationResult = FlipperInitializer.initFlipperPlugins(this, client); diff --git a/android/sample/src/main/java/com/facebook/flipper/sample/MainActivity.java b/android/sample/src/main/java/com/facebook/flipper/sample/MainActivity.java index 52291330d..b360dd71d 100644 --- a/android/sample/src/main/java/com/facebook/flipper/sample/MainActivity.java +++ b/android/sample/src/main/java/com/facebook/flipper/sample/MainActivity.java @@ -11,6 +11,7 @@ import androidx.appcompat.app.AppCompatActivity; import com.facebook.flipper.android.AndroidFlipperClient; import com.facebook.flipper.core.FlipperClient; import com.facebook.flipper.plugins.example.ExampleFlipperPlugin; +import com.facebook.flipper.plugins.navigation.NavigationFlipperPlugin; import com.facebook.litho.ComponentContext; import com.facebook.litho.LithoView; @@ -19,6 +20,9 @@ public class MainActivity extends AppCompatActivity { @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + NavigationFlipperPlugin.getInstance().sendNavigationEvent("flipper://demo_page/"); + final ComponentContext c = new ComponentContext(this); setContentView(LithoView.create(c, RootComponent.create(c).build())); diff --git a/android/sample/src/main/java/com/facebook/flipper/sample/RootComponentSpec.java b/android/sample/src/main/java/com/facebook/flipper/sample/RootComponentSpec.java index da56034d9..76651b27a 100644 --- a/android/sample/src/main/java/com/facebook/flipper/sample/RootComponentSpec.java +++ b/android/sample/src/main/java/com/facebook/flipper/sample/RootComponentSpec.java @@ -62,6 +62,12 @@ public class RootComponentSpec { .key("5") .textSizeSp(20) .clickHandler(RootComponent.loadImage(c))) + .child( + Text.create(c) + .text("Navigate to another page") + .key("5") + .textSizeSp(20) + .clickHandler(RootComponent.openAlternateActivityOne(c))) .child(displayImage ? FrescoImage.create(c).controller(controller) : null) .build(); } @@ -87,6 +93,12 @@ public class RootComponentSpec { c.getAndroidContext().startActivity(intent); } + @OnEvent(ClickEvent.class) + static void openAlternateActivityOne(final ComponentContext c) { + final Intent intent = new Intent(c.getAndroidContext(), DeepLinkActivity.class); + c.getAndroidContext().startActivity(intent); + } + @OnUpdateState static void updateDisplayImage(StateValue displayImage) { displayImage.set(true); diff --git a/android/src/main/java/com/facebook/flipper/plugins/navigation/NavigationFlipperPlugin.java b/android/src/main/java/com/facebook/flipper/plugins/navigation/NavigationFlipperPlugin.java new file mode 100644 index 000000000..6d49a588a --- /dev/null +++ b/android/src/main/java/com/facebook/flipper/plugins/navigation/NavigationFlipperPlugin.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + */ +package com.facebook.flipper.plugins.navigation; + +import androidx.annotation.Nullable; +import com.facebook.flipper.core.FlipperConnection; +import com.facebook.flipper.core.FlipperObject; +import com.facebook.flipper.core.FlipperPlugin; +import com.facebook.flipper.core.FlipperReceiver; +import com.facebook.flipper.core.FlipperResponder; + +public class NavigationFlipperPlugin implements FlipperPlugin { + + private FlipperConnection mConnection = null; + + @Nullable private static NavigationFlipperPlugin instance = null; + + private NavigationFlipperPlugin() {} + + public void sendNavigationEvent(@Nullable String keyURI) { + if (mConnection != null) { + mConnection.send("nav_event", new FlipperObject.Builder().put("uri", keyURI).build()); + } + } + + @Override + public String getId() { + return "Navigation"; + } + + @Override + public void onConnect(FlipperConnection connection) throws Exception { + mConnection = connection; + connection.receive( + "greet", + new FlipperReceiver() { + @Override + public void onReceive(FlipperObject params, FlipperResponder responder) throws Exception { + responder.success(new FlipperObject.Builder().put("greeting", "Hello").build()); + } + }); + mConnection.send("nav_plugin_active", new FlipperObject.Builder().build()); + } + + @Override + public void onDisconnect() throws Exception {} + + @Override + public boolean runInBackground() { + return true; + } + + public static NavigationFlipperPlugin getInstance() { + if (instance == null) { + instance = new NavigationFlipperPlugin(); + } + return instance; + } +} + +/* @scarf-info: do not remove, more info: https://fburl.com/scarf */ +/* @scarf-generated: flipper-plugin android/Plugin.java 0bfa32e5-fb15-4705-81f8-86260a1f3f8e */ diff --git a/android/src/test/java/com/facebook/flipper/plugins/navigation/NavigationFlipperPluginTest.java b/android/src/test/java/com/facebook/flipper/plugins/navigation/NavigationFlipperPluginTest.java new file mode 100644 index 000000000..6198c06d4 --- /dev/null +++ b/android/src/test/java/com/facebook/flipper/plugins/navigation/NavigationFlipperPluginTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + * + */ +package com.facebook.flipper.plugins.navigation; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.facebook.flipper.core.FlipperObject; +import com.facebook.flipper.testing.FlipperConnectionMock; +import com.facebook.flipper.testing.FlipperResponderMock; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class NavigationFlipperPluginTest { + @Test + public void greetingTest() throws Exception { + final NavigationFlipperPlugin plugin = NavigationFlipperPlugin.getInstance(); + final FlipperConnectionMock connection = new FlipperConnectionMock(); + final FlipperResponderMock responder = new FlipperResponderMock(); + + plugin.onConnect(connection); + connection.receivers.get("greet").onReceive(null, responder); + + assertThat( + responder.successes, hasItem(new FlipperObject.Builder().put("greeting", "Hello").build())); + } +} + +/* @scarf-info: do not remove, more info: https://fburl.com/scarf */ +/* @scarf-generated: flipper-plugin android/test/PluginTest.java 0bfa32e5-fb15-4705-81f8-86260a1f3f8e */