diff --git a/native/android/app/src/main/java/app/comm/android/MainActivity.java b/native/android/app/src/main/java/app/comm/android/MainActivity.java
deleted file mode 100644
--- a/native/android/app/src/main/java/app/comm/android/MainActivity.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package app.comm.android;
-
-import android.Manifest;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-import androidx.core.app.ActivityCompat;
-import app.comm.android.notifications.CommAndroidNotifications;
-import com.facebook.react.ReactActivity;
-import com.facebook.react.ReactActivityDelegate;
-import com.facebook.react.ReactRootView;
-import expo.modules.ReactActivityDelegateWrapper;
-
-public class MainActivity extends ReactActivity
- implements ActivityCompat.OnRequestPermissionsResultCallback {
-
- /**
- * Returns the name of the main component registered from JavaScript.
- * This is used to schedule rendering of the component.
- */
- @Override
- protected String getMainComponentName() {
- return "Comm";
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(null);
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- setIntent(intent);
- }
-
- /**
- * Returns the instance of the {@link ReactActivityDelegate}. There the
- * RootView is created and you can specify the renderer you wish to use - the
- * new renderer (Fabric) or the old renderer (Paper).
- */
- @Override
- protected ReactActivityDelegate createReactActivityDelegate() {
- return new ReactActivityDelegateWrapper(
- this, new MainActivityDelegate(this, getMainComponentName()));
- }
- public static class MainActivityDelegate extends ReactActivityDelegate {
- public MainActivityDelegate(
- ReactActivity activity,
- String mainComponentName) {
- super(activity, mainComponentName);
- }
- @Override
- protected ReactRootView createRootView() {
- ReactRootView reactRootView = new ReactRootView(getContext());
- // If you opted-in for the New Architecture, we enable the Fabric
- // Renderer.
- reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
- return reactRootView;
- }
- @Override
- protected boolean isConcurrentRootEnabled() {
- // If you opted-in for the New Architecture, we enable Concurrent Root
- // (i.e. React 18). More on this on
- // https://reactjs.org/blog/2022/03/29/react-v18.html
- return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
- }
- }
-
- @Override
- public void invokeDefaultOnBackPressed() {
- moveTaskToBack(true);
- }
-
- @Override
- public void onRequestPermissionsResult(
- int requestCode,
- String[] permissions,
- int[] grantResults) {
-
- for (int permissionIndex = 0; permissionIndex < grantResults.length;
- permissionIndex++) {
- String permissionName = permissions[permissionIndex];
- if (requestCode ==
- CommAndroidNotifications
- .COMM_ANDROID_NOTIFICATIONS_REQUEST_CODE &&
- permissionName.equals(Manifest.permission.POST_NOTIFICATIONS)) {
- CommAndroidNotifications.resolveNotificationsPermissionRequestPromise(
- this,
- grantResults[permissionIndex] == PackageManager.PERMISSION_GRANTED);
- }
- }
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- }
-}
diff --git a/native/android/app/src/main/java/app/comm/android/MainActivity.kt b/native/android/app/src/main/java/app/comm/android/MainActivity.kt
new file mode 100644
--- /dev/null
+++ b/native/android/app/src/main/java/app/comm/android/MainActivity.kt
@@ -0,0 +1,86 @@
+package app.comm.android
+
+import android.Manifest
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import app.comm.android.notifications.CommAndroidNotifications
+
+import com.facebook.react.ReactActivity
+import com.facebook.react.ReactActivityDelegate
+import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
+import com.facebook.react.defaults.DefaultReactActivityDelegate
+
+import expo.modules.splashscreen.SplashScreenManager
+import expo.modules.ReactActivityDelegateWrapper
+
+class MainActivity : ReactActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ // Set the theme to AppTheme BEFORE onCreate to support
+ // coloring the background, status bar, and navigation bar.
+ // This is required for expo-splash-screen.
+ setTheme(R.style.AppTheme);
+ super.onCreate(null)
+ }
+
+ /**
+ * Returns the name of the main component registered from JavaScript. This is used to schedule
+ * rendering of the component.
+ */
+ override fun getMainComponentName(): String = "Comm"
+
+ /**
+ * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
+ * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
+ */
+ override fun createReactActivityDelegate(): ReactActivityDelegate {
+ return ReactActivityDelegateWrapper(
+ this,
+ BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
+ object : DefaultReactActivityDelegate(
+ this,
+ mainComponentName,
+ fabricEnabled
+ ){})
+ }
+
+ /**
+ * Align the back button behavior with Android S
+ * where moving root activities to background instead of finishing activities.
+ * @see onBackPressed
+ */
+ override fun invokeDefaultOnBackPressed() {
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
+ if (!moveTaskToBack(false)) {
+ // For non-root activities, use the default implementation to finish them.
+ super.invokeDefaultOnBackPressed()
+ }
+ return
+ }
+
+ // Use the default back button implementation on Android S
+ // because it's doing more than [Activity.moveTaskToBack] in fact.
+ super.invokeDefaultOnBackPressed()
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ for (permissionIndex in grantResults.indices) {
+ val permissionName = permissions[permissionIndex]
+ if (requestCode ==
+ CommAndroidNotifications
+ .COMM_ANDROID_NOTIFICATIONS_REQUEST_CODE &&
+ permissionName == Manifest.permission.POST_NOTIFICATIONS
+ ) {
+ CommAndroidNotifications.resolveNotificationsPermissionRequestPromise(
+ this,
+ grantResults[permissionIndex] == PackageManager.PERMISSION_GRANTED
+ )
+ }
+ }
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ }
+}
\ No newline at end of file
diff --git a/native/android/app/src/main/java/app/comm/android/MainApplication.java b/native/android/app/src/main/java/app/comm/android/MainApplication.java
deleted file mode 100644
--- a/native/android/app/src/main/java/app/comm/android/MainApplication.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package app.comm.android;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.database.CursorWindow;
-import android.os.Build;
-import androidx.annotation.NonNull;
-import androidx.multidex.MultiDexApplication;
-import app.comm.android.commservices.CommServicesPackage;
-import app.comm.android.newarchitecture.MainApplicationReactNativeHost;
-import app.comm.android.notifications.CommAndroidNotificationsPackage;
-import com.facebook.react.PackageList;
-import com.facebook.react.ReactApplication;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.ReactNativeHost;
-import com.facebook.react.ReactPackage;
-import com.facebook.react.bridge.JSIModulePackage;
-import com.facebook.react.config.ReactFeatureFlags;
-import com.facebook.soloader.SoLoader;
-import com.wix.reactnativekeyboardinput.KeyboardInputPackage;
-import expo.modules.ApplicationLifecycleDispatcher;
-import expo.modules.ReactNativeHostWrapper;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.security.Security;
-import java.util.List;
-import org.jetbrains.annotations.Nullable;
-
-public class MainApplication
- extends MultiDexApplication implements ReactApplication {
-
- static {
- System.loadLibrary("fbjni");
- System.loadLibrary("comm_jni_module");
- }
-
- private static Context context;
-
- private final ReactNativeHost mReactNativeHost =
- new ReactNativeHostWrapper(this, new ReactNativeHost(this) {
- @Override
- public boolean getUseDeveloperSupport() {
- return BuildConfig.DEBUG;
- }
-
- @Override
- protected List getPackages() {
- @SuppressWarnings("UnnecessaryLocalVariable")
- List packages = new PackageList(this).getPackages();
- packages.add(new KeyboardInputPackage(this.getApplication()));
- packages.add(new CommAndroidNotificationsPackage());
- packages.add(new CommServicesPackage());
- return packages;
- }
-
- @Override
- protected String getJSMainModuleName() {
- return "index";
- }
-
- @Override
- protected JSIModulePackage getJSIModulePackage() {
- return new CommCoreJSIModulePackage();
- }
- });
-
- private final ReactNativeHost mNewArchitectureNativeHost =
- new ReactNativeHostWrapper(
- this,
- new MainApplicationReactNativeHost(this));
-
- @Override
- public ReactNativeHost getReactNativeHost() {
- if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
- return mNewArchitectureNativeHost;
- } else {
- return mReactNativeHost;
- }
- }
-
- @Override
- public Intent
- registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {
- if (Build.VERSION.SDK_INT >= 34 &&
- getApplicationInfo().targetSdkVersion >= 34) {
- return super.registerReceiver(
- receiver, filter, Context.RECEIVER_EXPORTED);
- } else {
- return super.registerReceiver(receiver, filter);
- }
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- // If you opted-in for the New Architecture, we enable the TurboModule
- // system
- MainApplication.context = this.getApplicationContext();
- ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
-
- Security.insertProviderAt(new org.conscrypt.OpenSSLProvider(), 1);
-
- SoLoader.init(this, /* native exopackage */ false);
- ApplicationLifecycleDispatcher.onApplicationCreate(this);
- try {
- Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
- field.setAccessible(true);
- field.set(null, 100 * 1024 * 1024); // 100 MiB
- } catch (Exception e) {
- if (BuildConfig.DEBUG) {
- e.printStackTrace();
- }
- }
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig);
- }
-
- public static Context getMainApplicationContext() {
- return MainApplication.context;
- }
-}
diff --git a/native/android/app/src/main/java/app/comm/android/MainApplication.kt b/native/android/app/src/main/java/app/comm/android/MainApplication.kt
new file mode 100644
--- /dev/null
+++ b/native/android/app/src/main/java/app/comm/android/MainApplication.kt
@@ -0,0 +1,107 @@
+package app.comm.android
+
+import android.app.Application
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.res.Configuration
+import android.database.CursorWindow
+import android.os.Build
+import app.comm.android.commservices.CommServicesPackage
+import app.comm.android.notifications.CommAndroidNotificationsPackage
+import com.facebook.react.PackageList
+import com.facebook.react.ReactApplication
+import com.facebook.react.ReactHost
+import com.facebook.react.ReactNativeHost
+import com.facebook.react.ReactPackage
+import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
+import com.facebook.react.defaults.DefaultReactNativeHost
+import com.facebook.react.soloader.OpenSourceMergedSoMapping
+import com.facebook.soloader.SoLoader
+import com.wix.reactnativekeyboardinput.KeyboardInputPackage
+import expo.modules.ApplicationLifecycleDispatcher
+import expo.modules.ReactNativeHostWrapper
+import org.conscrypt.OpenSSLProvider
+import java.lang.reflect.Field
+import java.security.Security
+
+
+class MainApplication : Application(), ReactApplication {
+ override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
+ this,
+ object : DefaultReactNativeHost(this) {
+ override fun getPackages(): List {
+ val packages = PackageList(this).packages
+ packages.add(KeyboardInputPackage(this.application))
+ packages.add(CommAndroidNotificationsPackage())
+ packages.add(CommServicesPackage())
+ return packages
+ }
+
+ override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
+
+ override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
+
+ override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
+ override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
+ }
+ )
+
+ companion object {
+ init {
+ System.loadLibrary("fbjni");
+ System.loadLibrary("comm_jni_module");
+ }
+ var context: Context? = null
+
+ fun getMainApplicationContext(): Context? {
+ return context
+ }
+ }
+
+ override val reactHost: ReactHost
+ get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)
+
+ override fun registerReceiver(
+ receiver: BroadcastReceiver?,
+ filter: IntentFilter?
+ ): Intent? {
+ return if (Build.VERSION.SDK_INT >= 34 &&
+ applicationInfo.targetSdkVersion >= 34
+ ) {
+ super.registerReceiver(
+ receiver, filter, RECEIVER_EXPORTED
+ )
+ } else {
+ super.registerReceiver(receiver, filter)
+ }
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ Security.insertProviderAt(OpenSSLProvider(), 1)
+
+ SoLoader.init(this, OpenSourceMergedSoMapping)
+ if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
+ // If you opted-in for the New Architecture, we load the native entry point for this app.
+ load()
+ }
+ ApplicationLifecycleDispatcher.onApplicationCreate(this)
+ try {
+ val field: Field = CursorWindow::class.java.getDeclaredField("sCursorWindowSize")
+ field.setAccessible(true)
+ field.set(null, 100 * 1024 * 1024) // 100 MiB
+ } catch (e: Exception) {
+ if (BuildConfig.DEBUG) {
+ e.printStackTrace()
+ }
+ }
+ context = applicationContext
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
+ }
+}
\ No newline at end of file
diff --git a/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java b/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java
--- a/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java
+++ b/native/android/app/src/main/java/app/comm/android/fbjni/CommMMKV.java
@@ -73,7 +73,7 @@
mmkvIdentifier = identifier;
}
- MMKV.initialize(MainApplication.getMainApplicationContext());
+ MMKV.initialize(MainApplication.Companion.getMainApplicationContext());
getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey);
}
}
@@ -96,7 +96,7 @@
throw new RuntimeException("Failed to remove MMKV storage.");
}
assignInitializationData();
- MMKV.initialize(MainApplication.getMainApplicationContext());
+ MMKV.initialize(MainApplication.Companion.getMainApplicationContext());
getMMKVInstance(mmkvIdentifier, mmkvEncryptionKey);
}
}
diff --git a/native/android/app/src/main/java/app/comm/android/fbjni/PlatformSpecificTools.java b/native/android/app/src/main/java/app/comm/android/fbjni/PlatformSpecificTools.java
--- a/native/android/app/src/main/java/app/comm/android/fbjni/PlatformSpecificTools.java
+++ b/native/android/app/src/main/java/app/comm/android/fbjni/PlatformSpecificTools.java
@@ -20,7 +20,7 @@
public static String getNotificationsCryptoAccountPath() {
Context mainApplicationContext =
- MainApplication.getMainApplicationContext();
+ MainApplication.Companion.getMainApplicationContext();
if (mainApplicationContext == null) {
throw new RuntimeException(
"Failed to resolve notifications crypto account path - main application context not initialized.");
@@ -32,7 +32,7 @@
public static String getBackupDirectoryPath() {
Context mainApplicationContext =
- MainApplication.getMainApplicationContext();
+ MainApplication.Companion.getMainApplicationContext();
if (mainApplicationContext == null) {
throw new RuntimeException(
"Failed to resolve backup path - main application context not initialized.");