2016-11-18 16:49:51 +02:00
package im.status.ethereum ;
2016-03-23 16:48:26 +02:00
2017-08-07 14:21:07 +02:00
import android.content.Context ;
2018-03-14 12:49:41 +03:00
import android.annotation.TargetApi ;
2019-08-07 15:08:22 +02:00
import androidx.annotation.Nullable ;
2016-06-08 12:43:02 +02:00
import android.app.AlertDialog ;
2017-08-06 23:46:43 +02:00
import android.app.ActivityManager ;
2016-06-08 12:43:02 +02:00
import android.content.DialogInterface ;
import android.content.DialogInterface.OnCancelListener ;
2016-07-20 12:03:05 +03:00
import android.content.DialogInterface.OnClickListener ;
2018-02-17 13:05:03 +08:00
import android.content.pm.PackageManager ;
2018-03-01 15:02:21 +01:00
import android.net.Uri ;
import android.os.Build ;
2017-08-07 14:21:07 +02:00
import android.os.Looper ;
2019-05-08 18:11:39 +05:45
import android.preference.PreferenceManager ;
2019-08-07 15:08:22 +02:00
import androidx.core.app.ActivityCompat ;
2017-08-07 14:21:07 +02:00
import android.util.Log ;
2019-05-08 18:11:39 +05:45
import android.view.WindowManager ;
2016-06-16 07:23:11 +03:00
import android.content.Intent ;
2017-11-12 19:50:42 +02:00
import android.content.SharedPreferences ;
2016-06-21 12:03:39 +03:00
import android.content.res.Configuration ;
2018-03-01 15:02:21 +01:00
import android.provider.Settings ;
2016-07-20 12:03:05 +03:00
import android.os.Bundle ;
2019-06-12 09:25:18 +03:00
import com.facebook.react.ReactActivityDelegate ;
import com.facebook.react.ReactRootView ;
2021-08-04 15:27:25 +02:00
import com.facebook.react.modules.core.DeviceEventManagerModule ;
import com.facebook.react.bridge.Arguments ;
import com.facebook.react.bridge.WritableMap ;
2019-06-12 09:25:18 +03:00
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView ;
2017-11-12 19:50:42 +02:00
2019-06-20 19:14:56 +03:00
import com.facebook.react.ReactFragmentActivity ;
2021-05-24 16:25:05 +02:00
import com.reactnativenavigation.NavigationActivity ;
2018-03-14 12:49:41 +03:00
import com.facebook.react.modules.core.PermissionListener ;
2017-10-19 06:38:20 +02:00
import org.devio.rn.splashscreen.SplashScreen ;
2016-06-01 11:41:50 +03:00
2016-07-20 12:03:05 +03:00
import java.util.Properties ;
2018-04-16 17:06:46 +01:00
import im.status.ethereum.module.StatusThreadPoolExecutor ;
2021-08-04 15:27:25 +02:00
import im.status.ethereum.MainApplication ;
2016-07-18 19:29:51 +03:00
2021-05-24 16:25:05 +02:00
public class MainActivity extends NavigationActivity
2018-02-17 13:05:03 +08:00
implements ActivityCompat . OnRequestPermissionsResultCallback {
2017-08-06 23:46:43 +02:00
2018-03-14 12:49:41 +03:00
@Nullable private PermissionListener mPermissionListener ;
2017-08-07 14:21:07 +02:00
private static void registerUncaughtExceptionHandler ( final Context context ) {
2017-08-06 23:46:43 +02:00
final Thread . UncaughtExceptionHandler defaultUncaughtExceptionHandler = Thread . getDefaultUncaughtExceptionHandler ();
Thread . setDefaultUncaughtExceptionHandler ( new Thread . UncaughtExceptionHandler () {
@Override
public void uncaughtException ( final Thread thread , final Throwable t ) {
2018-04-16 17:06:46 +01:00
// High priority, so don't use StatusThreadPoolExecutor
2017-08-06 23:46:43 +02:00
new Thread () {
@Override
public void run () {
Looper . prepare ();
2017-08-07 14:21:07 +02:00
new AlertDialog . Builder ( context )
2017-08-06 23:46:43 +02:00
. setTitle ( "Error" )
. setMessage ( t . toString ())
. setNegativeButton ( "Exit" , new DialogInterface . OnClickListener () {
public void onClick ( final DialogInterface dialog , final int id ) {
dialog . dismiss ();
defaultUncaughtExceptionHandler . uncaughtException ( thread , t );
}
}). show ();
Looper . loop ();
}
}. start ();
}
});
}
2017-08-07 14:21:07 +02:00
private ActivityManager getActivityManager () {
return ( ActivityManager ) this . getSystemService ( ACTIVITY_SERVICE );
}
private ActivityManager . MemoryInfo getAvailableMemory ( final ActivityManager activityManager ) {
final ActivityManager . MemoryInfo memoryInfo = new ActivityManager . MemoryInfo ();
2017-08-06 23:46:43 +02:00
activityManager . getMemoryInfo ( memoryInfo );
return memoryInfo ;
}
2016-09-07 20:35:04 +03:00
protected void configureStatus () {
2016-06-08 12:43:02 +02:00
// Required because of crazy APN settings redirecting localhost (found in GB)
2016-03-23 17:02:53 +02:00
Properties properties = System . getProperties ();
properties . setProperty ( "http.nonProxyHosts" , "localhost|127.0.0.1" );
properties . setProperty ( "https.nonProxyHosts" , "localhost|127.0.0.1" );
}
2018-03-01 15:02:21 +01:00
private Intent createNotificationSettingsIntent () {
final Intent intent = new Intent ();
if ( Build . VERSION . SDK_INT >= Build . VERSION_CODES . O ) {
intent . setAction ( Settings . ACTION_APP_NOTIFICATION_SETTINGS );
2018-03-29 15:48:20 +01:00
intent . putExtra ( Settings . EXTRA_APP_PACKAGE , getPackageName ());
2018-03-01 15:02:21 +01:00
} else {
intent . setAction ( Settings . ACTION_APPLICATION_DETAILS_SETTINGS );
intent . addCategory ( Intent . CATEGORY_DEFAULT );
intent . setData ( Uri . parse ( "package:" + getPackageName ()));
}
return intent ;
}
2021-08-04 15:27:25 +02:00
private void tryToEmit ( String eventName , WritableMap event ) {
try {
(( MainApplication ) getApplication ()). getReactNativeHost ()
. getReactInstanceManager ()
. getCurrentReactContext ()
. getJSModule ( DeviceEventManagerModule . RCTDeviceEventEmitter . class )
. emit ( "url" , event );
} catch ( Exception e ) { /* we expect NPE on first start, which is OK because we have a fallback */ }
}
2018-03-01 15:02:21 +01:00
@Override
public void onNewIntent ( final Intent intent ) {
2018-06-27 15:09:48 +02:00
super . onNewIntent ( intent );
2018-03-27 06:20:29 +01:00
if ( intent . getDataString () != null && intent . getData (). getScheme (). startsWith ( "app-settings" )) {
startActivity ( createNotificationSettingsIntent ());
2018-03-01 15:02:21 +01:00
}
}
2016-06-08 12:43:02 +02:00
@Override
protected void onCreate ( Bundle savedInstanceState ) {
2018-03-01 15:02:21 +01:00
2020-03-24 16:39:52 +01:00
switch ( getResources (). getConfiguration (). uiMode & Configuration . UI_MODE_NIGHT_MASK ) {
case Configuration . UI_MODE_NIGHT_YES :
setTheme ( R . style . DarkTheme );
break ;
case Configuration . UI_MODE_NIGHT_NO :
setTheme ( R . style . LightTheme );
break ;
default :
setTheme ( R . style . LightTheme );
}
2017-08-07 14:21:07 +02:00
// Make sure we get an Alert for every uncaught exceptions
registerUncaughtExceptionHandler ( MainActivity . this );
// Report memory details for this application
final ActivityManager activityManager = getActivityManager ();
Log . v ( "RNBootstrap" , "Available system memory " + getAvailableMemory ( activityManager ). availMem + ", maximum usable application memory " + activityManager . getLargeMemoryClass () + "M" );
2019-05-08 18:11:39 +05:45
setSecureFlag ();
2020-06-08 18:00:19 +03:00
SplashScreen . show ( this , true );
2020-03-17 12:15:02 +03:00
// NOTE: Try to not restore the state https://github.com/software-mansion/react-native-screens/issues/17
super . onCreate ( null );
2017-08-09 18:30:08 +03:00
2017-11-12 19:50:42 +02:00
if ( ! shouldShowRootedNotification ()) {
2016-09-07 20:35:04 +03:00
configureStatus ();
2016-06-08 12:43:02 +02:00
} else {
2016-07-20 12:03:05 +03:00
AlertDialog dialog = new AlertDialog . Builder ( MainActivity . this )
. setMessage ( getResources (). getString ( R . string . root_warning ))
2016-06-08 12:43:02 +02:00
. setPositiveButton ( getResources (). getString ( R . string . root_okay ), new OnClickListener () {
@Override
public void onClick ( DialogInterface dialog , int which ) {
2017-11-12 19:50:42 +02:00
rejectRootedNotification ();
2016-06-08 12:43:02 +02:00
dialog . dismiss ();
2016-09-07 20:35:04 +03:00
configureStatus ();
2016-06-08 12:43:02 +02:00
}
2016-07-20 12:03:05 +03:00
})
. setNegativeButton ( getResources (). getString ( R . string . root_cancel ), new OnClickListener () {
2016-06-08 12:43:02 +02:00
@Override
public void onClick ( DialogInterface dialog , int which ) {
dialog . dismiss ();
MainActivity . this . finishAffinity ();
}
2016-07-20 12:03:05 +03:00
})
. setOnCancelListener ( new OnCancelListener () {
2016-06-08 12:43:02 +02:00
@Override
public void onCancel ( DialogInterface dialog ) {
dialog . dismiss ();
MainActivity . this . finishAffinity ();
}
2016-07-20 12:03:05 +03:00
})
. create ();
2016-06-08 12:43:02 +02:00
dialog . show ();
}
2017-10-12 21:49:48 +02:00
2018-04-16 17:06:46 +01:00
Runnable r = new Runnable () {
2017-10-12 21:49:48 +02:00
@Override
public void run () {
System . loadLibrary ( "status-logs" );
2021-08-04 15:27:25 +02:00
// when app is started but the Activity has been destroyed, the deep linking url event is
// not emitted when coming back to foreground. This is a workaround. If the problem is
// resolved in react-native this code should be removed
if ( getIntent (). getData () != null ) {
WritableMap event = Arguments . createMap ();
event . putString ( "url" , getIntent (). getDataString ());
// on first start emit will (silently) fail, but the regular deep linking handler will work
tryToEmit ( "url" , event );
}
2017-10-12 21:49:48 +02:00
}
};
2018-04-16 17:06:46 +01:00
StatusThreadPoolExecutor . getInstance (). execute ( r );
2016-03-23 17:02:53 +02:00
}
2016-06-16 07:23:11 +03:00
@Override
protected void onDestroy () {
super . onDestroy ();
}
2021-08-04 15:27:25 +02:00
2016-03-23 16:48:26 +02:00
2016-06-21 12:03:39 +03:00
@Override
public void onConfigurationChanged ( Configuration newConfig ) {
super . onConfigurationChanged ( newConfig );
Intent intent = new Intent ( "onConfigurationChanged" );
intent . putExtra ( "newConfig" , newConfig );
this . sendBroadcast ( intent );
}
2017-11-12 19:50:42 +02:00
private static final String REJECTED_ROOTED_NOTIFICATION = "rejectedRootedNotification" ;
private static final Integer FREQUENCY_OF_REMINDER_IN_PERCENT = 5 ;
private boolean shouldShowRootedNotification () {
2020-05-19 13:40:39 +03:00
if ( RootUtil . isDeviceRooted () && BuildConfig . ENABLE_ROOT_ALERT == "1" ) {
2017-11-12 19:50:42 +02:00
if ( userRejectedRootedNotification ()) {
return (( Math . random () * 100 ) < FREQUENCY_OF_REMINDER_IN_PERCENT );
} else return true ;
} else {
return false ;
}
}
private boolean userRejectedRootedNotification () {
SharedPreferences preferences = getPreferences ( 0 );
return preferences . getBoolean ( REJECTED_ROOTED_NOTIFICATION , false );
}
private void rejectRootedNotification () {
SharedPreferences preferences = getPreferences ( 0 );
SharedPreferences . Editor editor = preferences . edit ();
editor . putBoolean ( REJECTED_ROOTED_NOTIFICATION , true );
editor . commit ();
}
2018-02-17 13:05:03 +08:00
2019-05-08 18:11:39 +05:45
private void setSecureFlag () {
final SharedPreferences sharedPrefs = PreferenceManager . getDefaultSharedPreferences ( this );
final boolean setSecure = sharedPrefs . getBoolean ( "BLANK_PREVIEW" , false );
if ( Build . VERSION . SDK_INT >= Build . VERSION_CODES . ICE_CREAM_SANDWICH && setSecure ) {
getWindow (). addFlags ( WindowManager . LayoutParams . FLAG_SECURE );
} else {
getWindow (). clearFlags ( WindowManager . LayoutParams . FLAG_SECURE );
}
}
2018-03-14 12:49:41 +03:00
@TargetApi ( Build . VERSION_CODES . M )
public void requestPermissions ( String [] permissions , int requestCode , PermissionListener listener ) {
mPermissionListener = listener ;
requestPermissions ( permissions , requestCode );
}
2018-02-17 13:05:03 +08:00
@Override
public void onRequestPermissionsResult ( int requestCode , String [] permissions , int [] grantResults ) {
2018-03-14 12:49:41 +03:00
if ( mPermissionListener != null && mPermissionListener . onRequestPermissionsResult ( requestCode , permissions , grantResults )) {
mPermissionListener = null ;
}
2018-02-17 13:05:03 +08:00
}
2016-03-23 16:48:26 +02:00
}