Browse Source

Android implementation

Janic Duplessis 5 years ago
parent
commit
8c14a018f3

+ 2
- 2
android/build.gradle View File

@@ -11,11 +11,11 @@ buildscript {
11 11
 }
12 12
 
13 13
 def getExtOrDefault(name) {
14
-  return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactNativeNetInfo_' + name]
14
+  return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactNativeSafeAreaView_' + name]
15 15
 }
16 16
 
17 17
 def getExtOrIntegerDefault(name) {
18
-  return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['ReactNativeNetInfo_' + name]).toInteger()
18
+  return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['ReactNativeSafeAreaView_' + name]).toInteger()
19 19
 }
20 20
 
21 21
 apply plugin: 'com.android.library'

+ 4
- 4
android/gradle.properties View File

@@ -1,6 +1,6 @@
1
-ReactNativeNetInfo_compileSdkVersion=28
2
-ReactNativeNetInfo_buildToolsVersion=28.0.3
3
-ReactNativeNetInfo_targetSdkVersion=27
4
-ReactNativeNetInfo_minSdkVersion=16
1
+ReactNativeSafeAreaView_compileSdkVersion=28
2
+ReactNativeSafeAreaView_buildToolsVersion=28.0.3
3
+ReactNativeSafeAreaView_targetSdkVersion=27
4
+ReactNativeSafeAreaView_minSdkVersion=16
5 5
 android.useAndroidX=true
6 6
 android.enableJetifier=true

+ 0
- 6
android/licenseHeader.txt View File

@@ -1,6 +0,0 @@
1
-/**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */

+ 1
- 5
android/src/main/AndroidManifest.xml View File

@@ -1,10 +1,6 @@
1 1
 
2 2
 <manifest
3 3
 	xmlns:android="http://schemas.android.com/apk/res/android"
4
-	package="com.reactnativecommunity.netinfo">
5
-
6
-	<uses-permission
7
-		android:name="android.permission.ACCESS_NETWORK_STATE" />
4
+	package="com.th3rdwave.safeareaview">
8 5
 
9 6
 </manifest>
10
-  

+ 15
- 0
android/src/main/java/com/th3rdwave/safeareaview/EdgeInsets.java View File

@@ -0,0 +1,15 @@
1
+package com.th3rdwave.safeareaview;
2
+
3
+/* package */ class EdgeInsets {
4
+  public float top;
5
+  public float right;
6
+  public float bottom;
7
+  public float left;
8
+
9
+  public EdgeInsets(float top, float right, float bottom, float left) {
10
+    this.top = top;
11
+    this.right = right;
12
+    this.bottom = bottom;
13
+    this.left = left;
14
+  }
15
+}

+ 36
- 0
android/src/main/java/com/th3rdwave/safeareaview/InsetsChangeEvent.java View File

@@ -0,0 +1,36 @@
1
+package com.th3rdwave.safeareaview;
2
+
3
+import com.facebook.react.bridge.Arguments;
4
+import com.facebook.react.bridge.WritableMap;
5
+import com.facebook.react.uimanager.PixelUtil;
6
+import com.facebook.react.uimanager.events.Event;
7
+import com.facebook.react.uimanager.events.RCTEventEmitter;
8
+
9
+/* package */  class InsetsChangeEvent extends Event<InsetsChangeEvent> {
10
+  public static final String EVENT_NAME = "topInsetsChange";
11
+
12
+  private EdgeInsets mInsets;
13
+
14
+  protected InsetsChangeEvent(int viewTag, EdgeInsets insets) {
15
+    super(viewTag);
16
+
17
+    mInsets = insets;
18
+  }
19
+
20
+  @Override
21
+  public String getEventName() {
22
+    return EVENT_NAME;
23
+  }
24
+
25
+  @Override
26
+  public void dispatch(RCTEventEmitter rctEventEmitter) {
27
+    WritableMap insets = Arguments.createMap();
28
+    insets.putDouble("top", PixelUtil.toDIPFromPixel(mInsets.top));
29
+    insets.putDouble("right", PixelUtil.toDIPFromPixel(mInsets.right));
30
+    insets.putDouble("bottom", PixelUtil.toDIPFromPixel(mInsets.bottom));
31
+    insets.putDouble("left", PixelUtil.toDIPFromPixel(mInsets.left));
32
+    WritableMap event = Arguments.createMap();
33
+    event.putMap("insets", insets);
34
+    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event);
35
+  }
36
+}

+ 83
- 0
android/src/main/java/com/th3rdwave/safeareaview/SafeAreaView.java View File

@@ -0,0 +1,83 @@
1
+package com.th3rdwave.safeareaview;
2
+
3
+import android.content.Context;
4
+import android.os.Build;
5
+import android.util.DisplayMetrics;
6
+import android.view.Surface;
7
+import android.view.WindowInsets;
8
+import android.view.WindowManager;
9
+
10
+import com.facebook.infer.annotation.Assertions;
11
+import com.facebook.react.uimanager.DisplayMetricsHolder;
12
+import com.facebook.react.views.view.ReactViewGroup;
13
+
14
+import androidx.annotation.Nullable;
15
+
16
+public class SafeAreaView extends ReactViewGroup {
17
+  public interface OnInsetsChangeListener {
18
+    void onInsetsChange(SafeAreaView view, EdgeInsets insets);
19
+  }
20
+
21
+  private @Nullable OnInsetsChangeListener mInsetsChangeListener;
22
+  WindowManager mWindowManager;
23
+
24
+  public SafeAreaView(Context context) {
25
+    super(context);
26
+
27
+    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
28
+  }
29
+
30
+  private EdgeInsets getSafeAreaInsets() {
31
+    // Window insets are parts of the window that are covered by system views (status bar,
32
+    // navigation bar, notches). There are no apis the get these values for android < M so we
33
+    // do a best effort polyfill.
34
+    EdgeInsets windowInsets;
35
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
36
+      WindowInsets insets = getRootWindowInsets();
37
+      windowInsets = new EdgeInsets(
38
+          insets.getSystemWindowInsetTop(),
39
+          insets.getSystemWindowInsetRight(),
40
+          insets.getSystemWindowInsetBottom(),
41
+          insets.getSystemWindowInsetLeft());
42
+    } else {
43
+      int rotation = mWindowManager.getDefaultDisplay().getRotation();
44
+      int statusBarHeight = 0;
45
+      int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
46
+      if (resourceId > 0) {
47
+        statusBarHeight = getResources().getDimensionPixelSize(resourceId);
48
+      }
49
+      int navbarHeight = 0;
50
+      resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
51
+      if (resourceId > 0) {
52
+        navbarHeight = getResources().getDimensionPixelSize(resourceId);
53
+      }
54
+
55
+      windowInsets = new EdgeInsets(
56
+          statusBarHeight,
57
+          rotation == Surface.ROTATION_90 ? navbarHeight : 0,
58
+          rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ? navbarHeight : 0,
59
+          rotation == Surface.ROTATION_270 ? navbarHeight : 0);
60
+    }
61
+
62
+    // Calculate the part of the root view that overlaps with window insets.
63
+    int[] windowLocation = new int[2];
64
+    getLocationInWindow(windowLocation);
65
+    DisplayMetrics screenMetrics = DisplayMetricsHolder.getScreenDisplayMetrics();
66
+    windowInsets.top = Math.max(windowInsets.top - windowLocation[1], 0);
67
+    windowInsets.left = Math.max(windowInsets.left - windowLocation[0], 0);
68
+    windowInsets.bottom = Math.max(windowLocation[1] + getHeight() + windowInsets.bottom - screenMetrics.heightPixels, 0);
69
+    windowInsets.right = Math.max(windowLocation[0] + getWidth() + windowInsets.right - screenMetrics.widthPixels, 0);
70
+    return windowInsets;
71
+  }
72
+
73
+  @Override
74
+  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
75
+    super.onLayout(changed, left, top, right, bottom);
76
+
77
+    Assertions.assertNotNull(mInsetsChangeListener).onInsetsChange(this, getSafeAreaInsets());
78
+  }
79
+
80
+  public void setOnInsetsChangeListener(OnInsetsChangeListener listener) {
81
+    mInsetsChangeListener = listener;
82
+  }
83
+}

+ 44
- 0
android/src/main/java/com/th3rdwave/safeareaview/SafeAreaViewManager.java View File

@@ -0,0 +1,44 @@
1
+package com.th3rdwave.safeareaview;
2
+
3
+import com.facebook.react.common.MapBuilder;
4
+import com.facebook.react.uimanager.ThemedReactContext;
5
+import com.facebook.react.uimanager.UIManagerModule;
6
+import com.facebook.react.uimanager.ViewGroupManager;
7
+import com.facebook.react.uimanager.events.EventDispatcher;
8
+
9
+import java.util.Map;
10
+
11
+import androidx.annotation.NonNull;
12
+
13
+public class SafeAreaViewManager extends ViewGroupManager<SafeAreaView> {
14
+  @Override
15
+  @NonNull
16
+  public String getName() {
17
+    return "RNCSafeAreaView";
18
+  }
19
+
20
+  @Override
21
+  @NonNull
22
+  public SafeAreaView createViewInstance(@NonNull ThemedReactContext context) {
23
+    return new SafeAreaView(context);
24
+  }
25
+
26
+  @Override
27
+  protected void addEventEmitters(@NonNull ThemedReactContext reactContext, @NonNull final SafeAreaView view) {
28
+    final EventDispatcher dispatcher =
29
+        reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
30
+    view.setOnInsetsChangeListener(new SafeAreaView.OnInsetsChangeListener() {
31
+      @Override
32
+      public void onInsetsChange(SafeAreaView view, EdgeInsets insets) {
33
+        dispatcher.dispatchEvent(new InsetsChangeEvent(view.getId(), insets));
34
+      }
35
+    });
36
+  }
37
+
38
+  @Override
39
+  public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
40
+    return MapBuilder.<String, Object>builder()
41
+        .put(InsetsChangeEvent.EVENT_NAME, MapBuilder.of("registrationName", "onInsetsChange"))
42
+        .build();
43
+  }
44
+}

+ 26
- 0
android/src/main/java/com/th3rdwave/safeareaview/SafeAreaViewPackage.java View File

@@ -0,0 +1,26 @@
1
+package com.th3rdwave.safeareaview;
2
+
3
+import com.facebook.react.ReactPackage;
4
+import com.facebook.react.bridge.NativeModule;
5
+import com.facebook.react.bridge.ReactApplicationContext;
6
+import com.facebook.react.uimanager.ViewManager;
7
+
8
+import java.util.Collections;
9
+import java.util.List;
10
+
11
+import javax.annotation.Nonnull;
12
+
13
+public class SafeAreaViewPackage implements ReactPackage {
14
+
15
+  @Nonnull
16
+  @Override
17
+  public List<NativeModule> createNativeModules(@Nonnull ReactApplicationContext reactContext) {
18
+    return Collections.emptyList();
19
+  }
20
+
21
+  @Nonnull
22
+  @Override
23
+  public List<ViewManager> createViewManagers(@Nonnull ReactApplicationContext reactContext) {
24
+    return Collections.<ViewManager>singletonList(new SafeAreaViewManager());
25
+  }
26
+}

+ 5
- 1
example/App.tsx View File

@@ -21,7 +21,11 @@ import {
21 21
 const App = () => {
22 22
   return (
23 23
     <>
24
-      <StatusBar barStyle="dark-content" />
24
+      <StatusBar
25
+        barStyle="dark-content"
26
+        translucent
27
+        backgroundColor="rgba(0, 0, 0, 0.3)"
28
+      />
25 29
       <SafeAreaView>
26 30
         {insets => (
27 31
           <ScrollView

+ 4
- 4
example/android/app/build.gradle View File

@@ -80,7 +80,7 @@ project.ext.react = [
80 80
     enableHermes: false,  // clean and rebuild if changing
81 81
 ]
82 82
 
83
-apply from: "../../node_modules/react-native/react.gradle"
83
+apply from: "../../../node_modules/react-native/react.gradle"
84 84
 
85 85
 /**
86 86
  * Set this to true to create two separate APKs instead of one:
@@ -192,12 +192,14 @@ dependencies {
192 192
     implementation "com.facebook.react:react-native:+"  // From node_modules
193 193
 
194 194
     if (enableHermes) {
195
-      def hermesPath = "../../node_modules/hermesvm/android/";
195
+      def hermesPath = "../../../node_modules/hermesvm/android/";
196 196
       debugImplementation files(hermesPath + "hermes-debug.aar")
197 197
       releaseImplementation files(hermesPath + "hermes-release.aar")
198 198
     } else {
199 199
       implementation jscFlavor
200 200
     }
201
+
202
+    implementation project(":th3rdwave-safe-area-view")
201 203
 }
202 204
 
203 205
 // Run this once to be able to run the application with BUCK
@@ -206,5 +208,3 @@ task copyDownloadableDepsToLibs(type: Copy) {
206 208
     from configurations.compile
207 209
     into 'libs'
208 210
 }
209
-
210
-apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

+ 7
- 10
example/android/app/src/main/java/com/safeareaviewexample/MainApplication.java View File

@@ -1,16 +1,15 @@
1 1
 package com.safeareaviewexample;
2 2
 
3 3
 import android.app.Application;
4
-import android.util.Log;
5 4
 
6
-import com.facebook.react.PackageList;
7
-import com.facebook.hermes.reactexecutor.HermesExecutorFactory;
8
-import com.facebook.react.bridge.JavaScriptExecutorFactory;
9 5
 import com.facebook.react.ReactApplication;
10 6
 import com.facebook.react.ReactNativeHost;
11 7
 import com.facebook.react.ReactPackage;
8
+import com.facebook.react.shell.MainReactPackage;
12 9
 import com.facebook.soloader.SoLoader;
10
+import com.th3rdwave.safeareaview.SafeAreaViewPackage;
13 11
 
12
+import java.util.Arrays;
14 13
 import java.util.List;
15 14
 
16 15
 public class MainApplication extends Application implements ReactApplication {
@@ -23,16 +22,14 @@ public class MainApplication extends Application implements ReactApplication {
23 22
 
24 23
     @Override
25 24
     protected List<ReactPackage> getPackages() {
26
-      @SuppressWarnings("UnnecessaryLocalVariable")
27
-      List<ReactPackage> packages = new PackageList(this).getPackages();
28
-      // Packages that cannot be autolinked yet can be added manually here, for example:
29
-      // packages.add(new MyReactNativePackage());
30
-      return packages;
25
+      return Arrays.asList(
26
+          new MainReactPackage(),
27
+          new SafeAreaViewPackage());
31 28
     }
32 29
 
33 30
     @Override
34 31
     protected String getJSMainModuleName() {
35
-      return "index";
32
+      return "example/index";
36 33
     }
37 34
   };
38 35
 

+ 2
- 2
example/android/build.gradle View File

@@ -25,11 +25,11 @@ allprojects {
25 25
         mavenLocal()
26 26
         maven {
27 27
             // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
28
-            url("$rootDir/../node_modules/react-native/android")
28
+            url("$rootDir/../../node_modules/react-native/android")
29 29
         }
30 30
         maven {
31 31
             // Android JSC is installed from npm
32
-            url("$rootDir/../node_modules/jsc-android/dist")
32
+            url("$rootDir/../../node_modules/jsc-android/dist")
33 33
         }
34 34
 
35 35
         google()

+ 3
- 1
example/android/settings.gradle View File

@@ -1,3 +1,5 @@
1 1
 rootProject.name = 'SafeAreaViewExample'
2
-apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
3 2
 include ':app'
3
+
4
+include ':th3rdwave-safe-area-view'
5
+project(':th3rdwave-safe-area-view').projectDir = new File(rootProject.projectDir, '../../android')

+ 2
- 0
src/index.tsx View File

@@ -29,6 +29,8 @@ export default function SafeAreaView({ children, style }: SafeAreaViewProps) {
29 29
     [],
30 30
   );
31 31
 
32
+  console.warn(insets);
33
+
32 34
   return (
33 35
     <NativeSafeAreaView
34 36
       style={[styles.fill, style]}