diff --git a/.gitignore b/.gitignore index e79c41e..fd1f9dc 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ build *.iml *.local *.jks +*.tmp diff --git a/README.md b/README.md index fdec169..5abc3ab 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ This repository contains Android application sources of i2pd ### Install g++, OpenJDK 11+, gradle 5.1+ + * Note: openjdk 17 has also been tested okay. + ```bash sudo apt-get install g++ openjdk-11-jdk gradle ``` @@ -58,7 +60,7 @@ pushd binary/jni ./build.sh -d popd -gradle clean assembleDebug +./gradlew clean assembleDebug ``` You will find APKs in `app/build/outputs/apk` diff --git a/app/build.gradle b/app/build.gradle index 0178977..53505f3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,16 +17,12 @@ dependencies { } android { - lintOptions { - // Not so a good way - disable 'DuplicatePlatformClasses' - } - - compileSdkVersion 33 + // do not remove, it is deprecated & nevertheless required + compileSdkVersion 35 defaultConfig { applicationId "org.purplei2p.i2pd" - targetSdkVersion 33 + targetSdkVersion 35 // TODO: 24? minSdkVersion 16 versionCode 2550000 @@ -89,6 +85,12 @@ android { targetCompatibility = JavaVersion.VERSION_1_8 } namespace 'org.purplei2p.i2pd' + lint { + disable 'DuplicatePlatformClasses' + } + buildFeatures { + buildConfig = true + } } ext.abiCodes = ['armeabi-v7a': 1, 'x86': 2, 'arm64-v8a': 3, 'x86_64': 4] diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e7c2d76..23bec2e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,7 +24,7 @@ android:usesCleartextTraffic="true"> @@ -62,7 +62,7 @@ @@ -80,12 +80,12 @@ android:enabled="true" /> + android:parentActivityName=".I2PDPermissionsAskerActivity"> + android:value="org.purplei2p.i2pd.I2PDPermissionsAskerActivity" /> updateStatusText(); private void updateStatusText() { runOnUiThread(() -> { @@ -67,15 +54,15 @@ private void updateStatusText() { if (textView == null) return; - Throwable tr = daemon.getLastThrowable(); + Throwable tr = getDaemon().getLastThrowable(); if (tr != null) { textView.setText(throwableToString(tr)); return; } - DaemonWrapper.State state = daemon.getState(); + DaemonWrapper.State state = getDaemon().getState(); - if (daemon.isStartedOkay()) { + if (getDaemon().isStartedOkay()) { HTTPProxyState.setChecked(I2PD_JNI.getHTTPProxyState()); SOCKSProxyState.setChecked(I2PD_JNI.getSOCKSProxyState()); BOBState.setChecked(I2PD_JNI.getBOBState()); @@ -83,8 +70,8 @@ private void updateStatusText() { I2CPState.setChecked(I2PD_JNI.getI2CPState()); } - String startResultStr = DaemonWrapper.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : ""; - String graceStr = DaemonWrapper.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : ""; + String startResultStr = DaemonWrapper.State.startFailed.equals(state) ? String.format(": %s", getDaemon().getDaemonStartResult()) : ""; + String graceStr = DaemonWrapper.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", I2PDApplication.formatGraceTimeRemaining(), getText(R.string.remaining)) : ""; textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr)); } catch (Throwable tr) { Log.e(TAG,"error ignored",tr); @@ -92,41 +79,25 @@ private void updateStatusText() { }); } - private static volatile long graceStartedMillis; - private static final Object graceStartedMillis_LOCK = new Object(); - private Menu optionsMenu; - - private static String formatGraceTimeRemaining() { - long remainingSeconds; - synchronized (graceStartedMillis_LOCK) { - remainingSeconds = Math.round(Math.max(0, graceStartedMillis + GRACEFUL_DELAY_MILLIS - System.currentTimeMillis()) / 1000.0D); - } - long remainingMinutes = (long) Math.floor(remainingSeconds / 60.0D); - long remSec = remainingSeconds - remainingMinutes * 60; - return remainingMinutes + ":" + (remSec / 10) + remSec % 10; + private DaemonWrapper getDaemon() { + return I2PDApplication.getDaemonWrapper(); } + private Menu optionsMenu; + @Override public void onCreate(Bundle savedInstanceState) { Log.d(TAG, "onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - startService(new Intent(this, ForegroundService.class)); - textView = (TextView) findViewById(R.id.appStatusText); - HTTPProxyState = (CheckBox) findViewById(R.id.service_httpproxy_box); - SOCKSProxyState = (CheckBox) findViewById(R.id.service_socksproxy_box); - BOBState = (CheckBox) findViewById(R.id.service_bob_box); - SAMState = (CheckBox) findViewById(R.id.service_sam_box); - I2CPState = (CheckBox) findViewById(R.id.service_i2cp_box); - - if (daemon == null) { - ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - daemon = new DaemonWrapper(getAssets(), connectivityManager); - } - ForegroundService.init(daemon); + textView = findViewById(R.id.appStatusText); + HTTPProxyState = findViewById(R.id.service_httpproxy_box); + SOCKSProxyState = findViewById(R.id.service_socksproxy_box); + BOBState = findViewById(R.id.service_bob_box); + SAMState = findViewById(R.id.service_sam_box); + I2CPState = findViewById(R.id.service_i2cp_box); - daemon.addStateChangeListener(daemonStateUpdatedListener); - daemonStateUpdatedListener.daemonStateUpdate(DaemonWrapper.State.uninitialized, daemon.getState()); + getDaemon().addStateChangeListener(daemonStateUpdatedListener); // request permissions if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { @@ -142,13 +113,11 @@ public void onCreate(Bundle savedInstanceState) { } } - doBindService(); - - final Timer gracefulQuitTimer = getGracefulQuitTimer(); + final Timer gracefulQuitTimer = I2PDApplication.getGracefulQuitTimer(); if (gracefulQuitTimer != null) { long gracefulStopAtMillis; - synchronized (graceStartedMillis_LOCK) { - gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; + synchronized (I2PDApplication.graceStartedMillis_LOCK) { + gracefulStopAtMillis = I2PDApplication.graceStartedMillis + I2PDApplication.GRACEFUL_DELAY_MILLIS; } rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis); } @@ -160,19 +129,7 @@ public void onCreate(Bundle savedInstanceState) { protected void onDestroy() { super.onDestroy(); textView = null; - ForegroundService.deinit(); - daemon.removeStateChangeListener(daemonStateUpdatedListener); - //cancelGracefulStop0(); - try { - doUnbindService(); - } catch (IllegalArgumentException ex) { - Log.e(TAG, "throwable caught and ignored", ex); - if (ex.getMessage().startsWith("Service not registered: " + org.purplei2p.i2pd.I2PDActivity.class.getName())) { - Log.i(TAG, "Service not registered exception seems to be normal, not a bug it seems."); - } - } catch (Throwable tr) { - Log.e(TAG, "throwable caught and ignored", tr); - } + getDaemon().removeStateChangeListener(daemonStateUpdatedListener); } @Override @@ -189,7 +146,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis } private void cancelGracefulStop0() { - Timer gracefulQuitTimer = getGracefulQuitTimer(); + Timer gracefulQuitTimer = I2PDApplication.getGracefulQuitTimer(); if (gracefulQuitTimer != null) { gracefulQuitTimer.cancel(); setGracefulQuitTimer(null); @@ -204,58 +161,6 @@ private CharSequence throwableToString(Throwable tr) { return sw.toString(); } - // private LocalService mBoundService; - - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - /* This is called when the connection with the service has been - established, giving us the service object we can use to - interact with the service. Because we have bound to a explicit - service that we know is running in our own process, we can - cast its IBinder to a concrete class and directly access it. */ - // mBoundService = ((LocalService.LocalBinder)service).getService(); - - /* Tell the user about this for our demo. */ - // Toast.makeText(Binding.this, R.string.local_service_connected, - // Toast.LENGTH_SHORT).show(); - } - - public void onServiceDisconnected(ComponentName className) { - /* This is called when the connection with the service has been - unexpectedly disconnected -- that is, its process crashed. - Because it is running in our same process, we should never - see this happen. */ - // mBoundService = null; - // Toast.makeText(Binding.this, R.string.local_service_disconnected, - // Toast.LENGTH_SHORT).show(); - } - }; - - private static volatile boolean mIsBound; - - private void doBindService() { - synchronized (I2PDActivity.class) { - if (mIsBound) - return; - // Establish a connection with the service. We use an explicit - // class name because we want a specific service implementation that - // we know will be running in our own process (and thus won't be - // supporting component replacement by other applications). - bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); - mIsBound = true; - } - } - - private void doUnbindService() { - synchronized (I2PDActivity.class) { - if (mIsBound) { - // Detach our existing connection. - unbindService(mConnection); - mIsBound = false; - } - } - } - @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. @@ -282,8 +187,8 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) { return true; case R.id.action_graceful_stop: - synchronized (graceStartedMillis_LOCK) { - if (getGracefulQuitTimer() != null) + synchronized (I2PDApplication.graceStartedMillis_LOCK) { + if (I2PDApplication.getGracefulQuitTimer() != null) cancelGracefulStop(); else i2pdGracefulStop(); @@ -299,7 +204,7 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) { return true; case R.id.action_start_webview: - if(daemon.isStartedOkay()) + if(getDaemon().isStartedOkay()) startActivity(new Intent(getApplicationContext(), WebConsoleActivity.class)); else Toast.makeText(this,"I2Pd not was started!", Toast.LENGTH_SHORT).show(); @@ -325,7 +230,7 @@ private void onActionBatteryOptimizations() { private void onReloadTunnelsConfig() { Log.i(TAG, "reloading tunnels"); - daemon.reloadTunnelsConfigs(); + getDaemon().reloadTunnelsConfigs(); Toast.makeText(this, R.string.tunnels_reloading, Toast.LENGTH_SHORT).show(); } @@ -335,7 +240,7 @@ private void i2pdStop() { textView.setText(getText(R.string.stopping)); new Thread(() -> { try { - daemon.stopDaemon(); + getDaemon().stopDaemon(); } catch (Throwable tr) { Log.e(TAG, "", tr); } @@ -343,14 +248,12 @@ private void i2pdStop() { }, "stop").start(); } - private static volatile Timer gracefulQuitTimer; - private void i2pdGracefulStop() { - if (daemon.getState() == DaemonWrapper.State.stopped) { + if (getDaemon().getState() == DaemonWrapper.State.stopped) { Toast.makeText(this, R.string.already_stopped, Toast.LENGTH_SHORT).show(); return; } - if (getGracefulQuitTimer() != null) { + if (I2PDApplication.getGracefulQuitTimer() != null) { Toast.makeText(this, R.string.graceful_stop_is_already_in_progress, Toast.LENGTH_SHORT).show(); return; } @@ -358,12 +261,12 @@ private void i2pdGracefulStop() { Toast.makeText(this, R.string.graceful_stop_is_in_progress, Toast.LENGTH_SHORT).show(); new Thread(() -> { try { - if (daemon.isStartedOkay()) { - daemon.stopAcceptingTunnels(); + if (getDaemon().isStartedOkay()) { + getDaemon().stopAcceptingTunnels(); long gracefulStopAtMillis; - synchronized (graceStartedMillis_LOCK) { - graceStartedMillis = System.currentTimeMillis(); - gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; + synchronized (I2PDApplication.graceStartedMillis_LOCK) { + I2PDApplication.graceStartedMillis = System.currentTimeMillis(); + gracefulStopAtMillis = I2PDApplication.graceStartedMillis + I2PDApplication.GRACEFUL_DELAY_MILLIS; } rescheduleGraceStop(null, gracefulStopAtMillis); } else @@ -380,8 +283,8 @@ private void cancelGracefulStop() Log.i(TAG, "canceling graceful stop"); new Thread(() -> { try { - if (daemon.isStartedOkay()) { - daemon.startAcceptingTunnels(); + if (getDaemon().isStartedOkay()) { + getDaemon().startAcceptingTunnels(); runOnUiThread(() -> Toast.makeText(this, R.string.shutdown_canceled, Toast.LENGTH_SHORT).show()); } else i2pdStop(); @@ -395,7 +298,7 @@ private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAt if (gracefulQuitTimerOld != null) gracefulQuitTimerOld.cancel(); - if (daemon.getTransitTunnelsCount() <= 0) { // no tunnels left + if (getDaemon().getTransitTunnelsCount() <= 0) { // no tunnels left Log.i(TAG, "no transit tunnels left, stopping"); i2pdStop(); return; @@ -420,19 +323,15 @@ public void run() { gracefulQuitTimer.scheduleAtFixedRate(tickerTask, 0/*start delay*/, 1000/*millis period*/); } - private static Timer getGracefulQuitTimer() { - return gracefulQuitTimer; - } - private void setGracefulQuitTimer(Timer gracefulQuitTimer) { - I2PDActivity.gracefulQuitTimer = gracefulQuitTimer; + I2PDApplication.gracefulQuitTimer = gracefulQuitTimer; runOnUiThread(() -> { Menu menu = optionsMenu; if (menu != null) { MenuItem item = menu.findItem(R.id.action_graceful_stop); if (item != null) { - synchronized (graceStartedMillis_LOCK) { - item.setTitle(getGracefulQuitTimer() != null ? R.string.action_cancel_graceful_stop : R.string.action_graceful_stop); + synchronized (I2PDApplication.graceStartedMillis_LOCK) { + item.setTitle(I2PDApplication.getGracefulQuitTimer() != null ? R.string.action_cancel_graceful_stop : R.string.action_graceful_stop); } } } @@ -453,7 +352,7 @@ private void openBatteryOptimizationDialogIfNeeded() { try { startActivity(new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse(PACKAGE_URI_SCHEME + getPackageName()))); } catch (ActivityNotFoundException e) { - Log.e(TAG, "BATT_OPTIM_ActvtNotFound", e); + Log.e(TAG, "BATT_OPTIM_ActivityNotFound", e); Toast.makeText(this, R.string.device_does_not_support_disabling_battery_optimizations, Toast.LENGTH_SHORT).show(); } }); @@ -506,11 +405,6 @@ private void quit() { } catch (Throwable tr) { Log.e(TAG, "", tr); } - try { - daemon.stopDaemon(); - } catch (Throwable tr) { - Log.e(TAG, "", tr); - } - System.exit(0); + I2PDApplication.quit(); } } diff --git a/app/src/main/java/org/purplei2p/i2pd/I2PDApplication.java b/app/src/main/java/org/purplei2p/i2pd/I2PDApplication.java new file mode 100644 index 0000000..5ca66ac --- /dev/null +++ b/app/src/main/java/org/purplei2p/i2pd/I2PDApplication.java @@ -0,0 +1,234 @@ +package org.purplei2p.i2pd; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.os.Build; +import android.os.Environment; +import android.os.IBinder; +import android.util.Log; + +import androidx.core.content.ContextCompat; + +import java.lang.reflect.Method; +import java.util.Timer; + +public class I2PDApplication extends android.app.Application { + public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; + private static final String TAG = "App"; + public static final Object graceStartedMillis_LOCK = new Object(); + private static I2PDApplication instance = null; + + private static volatile boolean startDaemon = false; + public static volatile long graceStartedMillis; + public static volatile Timer gracefulQuitTimer; + + public I2PDApplication() { + I2PDApplication.instance = this; + } + + + public static synchronized boolean isStartDaemon() { + return startDaemon; + } + + public static synchronized void setStartDaemon(boolean startDaemon) { + I2PDApplication.startDaemon = startDaemon; + } + +//private static final I2PD_JNI jniHolder = new I2PD_JNI(); + + private static volatile DaemonWrapper daemonWrapper; + private String versionName; + + private static volatile boolean mIsBound; + + + public synchronized static DaemonWrapper getDaemonWrapper() { + return daemonWrapper; + } + + public static void startForegroundService(Context context) { + Intent serviceIntent = new Intent(context, ForegroundService.class); + serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + ContextCompat.startForegroundService(context, serviceIntent); + } else { + context.startService(serviceIntent); + } + } + + public static void maybeAutostartForegroundServiceOnBoot(Context context) { + boolean autostartOnBoot = isAutostartOnBoot(context); + if(autostartOnBoot) { + startForegroundService(context); + } + } + + public static boolean isAutostartOnBoot(Context context) { + SharedPreferences sharedPref = context.getSharedPreferences( + org.purplei2p.i2pd.BootUpReceiver.SHARED_PREF_FILE_KEY, MODE_PRIVATE); + return sharedPref.getBoolean(org.purplei2p.i2pd.BootUpReceiver.AUTOSTART_ON_BOOT, true); + } + + public static I2PDApplication getInstance() { + return instance; + } + + public static String formatGraceTimeRemaining() { + long remainingSeconds; + synchronized (graceStartedMillis_LOCK) { + remainingSeconds = Math.round(Math.max(0, graceStartedMillis + GRACEFUL_DELAY_MILLIS - System.currentTimeMillis()) / 1000.0D); + } + long remainingMinutes = (long) Math.floor(remainingSeconds / 60.0D); + long remSec = remainingSeconds - remainingMinutes * 60; + return remainingMinutes + ":" + (remSec / 10) + remSec % 10; + } + + public static Timer getGracefulQuitTimer() { + return gracefulQuitTimer; + } + + @Override + public void onCreate() { + Log.d(TAG, "App.onCreate"); + super.onCreate(); + if(I2PDApplication.isAutostartOnBoot(getApplicationContext())){ + Log.d(TAG, "calling App.setStartDaemon(true)"); + I2PDApplication.setStartDaemon(true); + } + if(I2PDApplication.isStartDaemon()){ + Log.d(TAG, "calling App.doBindService()"); + doBindService(); + } + Log.d(TAG, "calling App.maybeAutostartForegroundServiceOnBoot()"); + maybeAutostartForegroundServiceOnBoot(getApplicationContext()); +// synchronized (this) { +// if (getDaemonWrapper() == null) { +// createDaemonWrapper(); +// } + versionName = BuildConfig.VERSION_NAME; +// startService(new Intent(this, ForegroundService.class)); +// } + startService(new Intent(this, ForegroundService.class)); + createDaemonWrapper(); + + //daemonWrapper.addStateChangeListener(daemonStateUpdatedListener); + //daemonStateUpdatedListener.daemonStateUpdate(DaemonWrapper.State.uninitialized, daemon.getState()); + Log.d(TAG, "App.onCreate() leave"); + } + + private void createDaemonWrapper() { + ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService( + Context.CONNECTIVITY_SERVICE); + daemonWrapper = new DaemonWrapper(getAssets(), connectivityManager); + ForegroundService.init(daemonWrapper); + } + + private synchronized void doBindService() { + if (mIsBound) + return; + // Establish a connection with the service. We use an explicit + // class name because we want a specific service implementation that + // we know will be running in our own process (and thus won't be + // supporting component replacement by other applications). + bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); + mIsBound = true; + } + + private synchronized void doUnbindService() { + if (mIsBound) { + // Detach our existing connection. + unbindService(mConnection); + mIsBound = false; + } + } + + @Override + public void onTerminate() { + quit(); + super.onTerminate(); + } + + private final ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + /* This is called when the connection with the service has been + established, giving us the service object we can use to + interact with the service. Because we have bound to a explicit + service that we know is running in our own process, we can + cast its IBinder to a concrete class and directly access it. */ + // mBoundService = ((LocalService.LocalBinder)service).getService(); + + /* Tell the user about this for our demo. */ + // Toast.makeText(Binding.this, R.string.local_service_connected, + // Toast.LENGTH_SHORT).show(); + } + + public void onServiceDisconnected(ComponentName className) { + /* This is called when the connection with the service has been + unexpectedly disconnected -- that is, its process crashed. + Because it is running in our same process, we should never + see this happen. */ + // mBoundService = null; + // Toast.makeText(Binding.this, R.string.local_service_disconnected, + // Toast.LENGTH_SHORT).show(); + } + }; + + public static synchronized void quit() { + try { + if (daemonWrapper != null) daemonWrapper.stopDaemon(); + } catch (Throwable tr) { + Log.e(TAG, "", tr); + } + + try { + if(instance!=null)instance.doUnbindService(); + } catch (IllegalArgumentException ex) { + Log.e(TAG, "throwable caught and ignored", ex); + final String message = ex.getMessage(); + if (message!=null && message.startsWith("Service not registered: " + I2PDActivity.class.getName())) { + Log.i(TAG, "Service not registered exception seems to be normal, not a bug it seems."); + } + } catch (Throwable tr) { + Log.e(TAG, "throwable caught and ignored", tr); + } + try { + Log.d(TAG, "calling fgservice.stop"); + ForegroundService.deinit(); + } catch (Throwable tr) { + Log.e(TAG, "", tr); + } + System.exit(0); + } + + public boolean isPermittedToWriteToExternalStorage() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + return Environment.isExternalStorageManager(); + } else { + Method methodCheckPermission; + + try { + methodCheckPermission = getClass().getMethod( + "checkSelfPermission", String.class); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + + Integer resultObj; + + try { + resultObj = (Integer) methodCheckPermission.invoke( + this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE); + } catch (Throwable e) { + throw new RuntimeException(e); + } + + return resultObj != null && resultObj == PackageManager.PERMISSION_GRANTED; + } + } +} diff --git a/app/src/main/java/org/purplei2p/i2pd/I2PDPermsAskerActivity.java b/app/src/main/java/org/purplei2p/i2pd/I2PDPermissionsAskerActivity.java similarity index 97% rename from app/src/main/java/org/purplei2p/i2pd/I2PDPermsAskerActivity.java rename to app/src/main/java/org/purplei2p/i2pd/I2PDPermissionsAskerActivity.java index 2df2780..55c3bbc 100644 --- a/app/src/main/java/org/purplei2p/i2pd/I2PDPermsAskerActivity.java +++ b/app/src/main/java/org/purplei2p/i2pd/I2PDPermissionsAskerActivity.java @@ -17,11 +17,9 @@ //dangerous perms, per https://developer.android.com/guide/topics/permissions/normal-permissions.html : //android.permission.WRITE_EXTERNAL_STORAGE -public class I2PDPermsAskerActivity extends Activity { +public class I2PDPermissionsAskerActivity extends Activity { private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 0; - private static final int PERMISSION_MANAGE_EXTERNAL_STORAGE = 0; - private Button button_request_write_ext_storage_perms; private TextView textview_retry; @@ -153,7 +151,7 @@ private void startMainActivity() { private static final int APP_STORAGE_ACCESS_REQUEST_CODE = 2; private void showExplanation() { - Intent intent = new Intent(this, I2PDPermsExplanationActivity.class); + Intent intent = new Intent(this, I2PDPermissionsExplanationActivity.class); startActivityForResult(intent, SHOW_EXPLANATION_REQUEST); } diff --git a/app/src/main/java/org/purplei2p/i2pd/I2PDPermsExplanationActivity.java b/app/src/main/java/org/purplei2p/i2pd/I2PDPermissionsExplanationActivity.java similarity index 51% rename from app/src/main/java/org/purplei2p/i2pd/I2PDPermsExplanationActivity.java rename to app/src/main/java/org/purplei2p/i2pd/I2PDPermissionsExplanationActivity.java index 33f3a28..469d168 100644 --- a/app/src/main/java/org/purplei2p/i2pd/I2PDPermsExplanationActivity.java +++ b/app/src/main/java/org/purplei2p/i2pd/I2PDPermissionsExplanationActivity.java @@ -4,33 +4,27 @@ import android.content.Intent; import android.os.Bundle; import android.app.Activity; -import android.view.View; import android.widget.Button; -public class I2PDPermsExplanationActivity extends Activity { +public class I2PDPermissionsExplanationActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_perms_explanation); + setContentView(R.layout.activity_permissions_explanation); ActionBar actionBar = getActionBar(); if (actionBar != null) actionBar.setHomeButtonEnabled(false); - Button button_ok = (Button) findViewById(R.id.button_ok); - button_ok.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - returnFromActivity(); - } - }); + Button button_ok = findViewById(R.id.button_ok); + button_ok.setOnClickListener(view -> returnFromActivity()); } private void returnFromActivity() { - Intent data = new Intent(); + Intent intent = new Intent(); Activity parent = getParent(); if (parent == null) { - setResult(Activity.RESULT_OK, data); + setResult(Activity.RESULT_OK, intent); } else { - parent.setResult(Activity.RESULT_OK, data); + parent.setResult(Activity.RESULT_OK, intent); } finish(); } diff --git a/app/src/main/java/org/purplei2p/i2pd/I2PdQSTileService.java b/app/src/main/java/org/purplei2p/i2pd/I2PDQuickSettingsTileService.java similarity index 92% rename from app/src/main/java/org/purplei2p/i2pd/I2PdQSTileService.java rename to app/src/main/java/org/purplei2p/i2pd/I2PDQuickSettingsTileService.java index 3a06165..3646ff3 100644 --- a/app/src/main/java/org/purplei2p/i2pd/I2PdQSTileService.java +++ b/app/src/main/java/org/purplei2p/i2pd/I2PDQuickSettingsTileService.java @@ -1,7 +1,6 @@ package org.purplei2p.i2pd; import android.content.Intent; -import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; import android.util.Log; @@ -9,7 +8,7 @@ import android.os.Build; @TargetApi(Build.VERSION_CODES.N) -public class I2PdQSTileService extends TileService { +public class I2PDQuickSettingsTileService extends TileService { private static final String TAG = "MyQSTileService"; @Override diff --git a/app/src/main/java/org/purplei2p/i2pd/receivers/BootUpReceiver.java b/app/src/main/java/org/purplei2p/i2pd/receivers/BootUpReceiver.java deleted file mode 100644 index 2a4078f..0000000 --- a/app/src/main/java/org/purplei2p/i2pd/receivers/BootUpReceiver.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.purplei2p.i2pd.receivers; - - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -//import org.purplei2p.i2pd.ForegroundService; -//ToDo:* fix^^^ change to service, not on window on start. -import org.purplei2p.i2pd.I2PDPermsAskerActivity; - -import java.io.File; - -import static org.purplei2p.i2pd.SettingsActivity.onBootFileName; - -public class BootUpReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - /* todo: disable the autostart? */ - File onBoot = - new File( - context.getApplicationContext().getCacheDir().getAbsolutePath() - + onBootFileName); - if(onBoot.exists()) { - Intent i = new Intent(context, I2PDPermsAskerActivity.class); - i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(i); - } - - } -} - diff --git a/app/src/main/res/layout/activity_perms_explanation.xml b/app/src/main/res/layout/activity_permissions_explanation.xml similarity index 94% rename from app/src/main/res/layout/activity_perms_explanation.xml rename to app/src/main/res/layout/activity_permissions_explanation.xml index 9129a43..428dbd4 100644 --- a/app/src/main/res/layout/activity_perms_explanation.xml +++ b/app/src/main/res/layout/activity_permissions_explanation.xml @@ -8,7 +8,7 @@ android:paddingLeft="@dimen/horizontal_page_margin" android:paddingRight="@dimen/horizontal_page_margin" android:paddingTop="@dimen/vertical_page_margin" - tools:context=".I2PDPermsAskerActivity"> + tools:context=".I2PDPermissionsAskerActivity"> + tools:context=".I2PDPermissionsAskerActivity">