mirror of
https://github.com/PurpleI2P/i2pd-android.git
synced 2025-02-09 05:14:24 +00:00
i2pd 2.33.0-63, tabulation, gradle configuration
Signed-off-by: R4SAS <r4sas@i2pmail.org>
This commit is contained in:
parent
e4c71893a5
commit
d4110e64d9
@ -3,7 +3,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.core:core:1.0.2'
|
implementation 'androidx.core:core:1.3.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -14,8 +14,8 @@ android {
|
|||||||
applicationId "org.purplei2p.i2pd"
|
applicationId "org.purplei2p.i2pd"
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
versionCode 23210
|
versionCode 23300
|
||||||
versionName "2.32.1"
|
versionName "2.33.0-63-g2648f1ba"
|
||||||
setProperty("archivesBaseName", archivesBaseName + "-" + versionName)
|
setProperty("archivesBaseName", archivesBaseName + "-" + versionName)
|
||||||
|
|
||||||
ndk {
|
ndk {
|
||||||
@ -39,14 +39,13 @@ android {
|
|||||||
enable true
|
enable true
|
||||||
reset()
|
reset()
|
||||||
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||||
//include "armeabi-v7a", "x86"
|
|
||||||
universalApk true
|
universalApk true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
orignal {
|
release {
|
||||||
storeFile file("i2pdapk.jks")
|
storeFile file('i2pdapk.jks')
|
||||||
storePassword "android"
|
storePassword "android"
|
||||||
keyAlias "i2pdapk"
|
keyAlias "i2pdapk"
|
||||||
keyPassword "android"
|
keyPassword "android"
|
||||||
@ -55,10 +54,12 @@ android {
|
|||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
signingConfig signingConfigs.release
|
||||||
signingConfig signingConfigs.orignal
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
|
||||||
}
|
}
|
||||||
|
debug {
|
||||||
|
jniDebuggable = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
@ -68,8 +69,8 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = '1.8'
|
sourceCompatibility = "1.8"
|
||||||
targetCompatibility = '1.8'
|
targetCompatibility = "1.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 6735b2686b6c13a36546dd794ee49b4d583565e0
|
Subproject commit 2648f1ba89d5032262a72ca8b2d2d8a70e441b9a
|
@ -2,180 +2,183 @@ package org.purplei2p.i2pd;
|
|||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.purplei2p.i2pd.R;
|
import org.purplei2p.i2pd.R;
|
||||||
|
|
||||||
public class DaemonSingleton {
|
public class DaemonSingleton {
|
||||||
private static final String TAG = "i2pd";
|
private static final String TAG = "i2pd";
|
||||||
private static final DaemonSingleton instance = new DaemonSingleton();
|
private static final DaemonSingleton instance = new DaemonSingleton();
|
||||||
|
|
||||||
public interface StateUpdateListener {
|
public interface StateUpdateListener {
|
||||||
void daemonStateUpdate();
|
void daemonStateUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>();
|
private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>();
|
||||||
|
|
||||||
public static DaemonSingleton getInstance() {
|
public static DaemonSingleton getInstance() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void addStateChangeListener(StateUpdateListener listener) {
|
public synchronized void addStateChangeListener(StateUpdateListener listener) {
|
||||||
stateUpdateListeners.add(listener);
|
stateUpdateListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void removeStateChangeListener(StateUpdateListener listener) {
|
public synchronized void removeStateChangeListener(StateUpdateListener listener) {
|
||||||
stateUpdateListeners.remove(listener);
|
stateUpdateListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void setState(State newState) {
|
private synchronized void setState(State newState) {
|
||||||
if (newState == null)
|
if (newState == null)
|
||||||
throw new NullPointerException();
|
throw new NullPointerException();
|
||||||
|
|
||||||
State oldState = state;
|
State oldState = state;
|
||||||
|
|
||||||
if (oldState == null)
|
if (oldState == null)
|
||||||
throw new NullPointerException();
|
throw new NullPointerException();
|
||||||
|
|
||||||
if (oldState.equals(newState))
|
if (oldState.equals(newState))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
state = newState;
|
state = newState;
|
||||||
fireStateUpdate1();
|
fireStateUpdate1();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void stopAcceptingTunnels() {
|
public synchronized void stopAcceptingTunnels() {
|
||||||
if (isStartedOkay()) {
|
if (isStartedOkay()) {
|
||||||
setState(State.gracefulShutdownInProgress);
|
setState(State.gracefulShutdownInProgress);
|
||||||
I2PD_JNI.stopAcceptingTunnels();
|
I2PD_JNI.stopAcceptingTunnels();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void startAcceptingTunnels() {
|
public synchronized void startAcceptingTunnels() {
|
||||||
if (isStartedOkay()) {
|
if (isStartedOkay()) {
|
||||||
setState(State.startedOkay);
|
setState(State.startedOkay);
|
||||||
I2PD_JNI.startAcceptingTunnels();
|
I2PD_JNI.startAcceptingTunnels();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void reloadTunnelsConfigs() {
|
public synchronized void reloadTunnelsConfigs() {
|
||||||
if (isStartedOkay()) {
|
if (isStartedOkay()) {
|
||||||
I2PD_JNI.reloadTunnelsConfigs();
|
I2PD_JNI.reloadTunnelsConfigs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized int GetTransitTunnelsCount() {
|
public synchronized int GetTransitTunnelsCount() {
|
||||||
return I2PD_JNI.GetTransitTunnelsCount();
|
return I2PD_JNI.GetTransitTunnelsCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
private volatile boolean startedOkay;
|
private volatile boolean startedOkay;
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
uninitialized(R.string.uninitialized),
|
uninitialized(R.string.uninitialized),
|
||||||
starting(R.string.starting),
|
starting(R.string.starting),
|
||||||
jniLibraryLoaded(R.string.jniLibraryLoaded),
|
jniLibraryLoaded(R.string.jniLibraryLoaded),
|
||||||
startedOkay(R.string.startedOkay),
|
startedOkay(R.string.startedOkay),
|
||||||
startFailed(R.string.startFailed),
|
startFailed(R.string.startFailed),
|
||||||
gracefulShutdownInProgress(R.string.gracefulShutdownInProgress),
|
gracefulShutdownInProgress(R.string.gracefulShutdownInProgress),
|
||||||
stopped(R.string.stopped);
|
stopped(R.string.stopped);
|
||||||
|
|
||||||
State(int statusStringResourceId) {
|
State(int statusStringResourceId) {
|
||||||
this.statusStringResourceId = statusStringResourceId;
|
this.statusStringResourceId = statusStringResourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final int statusStringResourceId;
|
private final int statusStringResourceId;
|
||||||
|
|
||||||
public int getStatusStringResourceId() {
|
public int getStatusStringResourceId() {
|
||||||
return statusStringResourceId;
|
return statusStringResourceId;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
private volatile State state = State.uninitialized;
|
;
|
||||||
|
|
||||||
public State getState() {
|
private volatile State state = State.uninitialized;
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
public State getState() {
|
||||||
setState(State.starting);
|
return state;
|
||||||
new Thread(new Runnable() {
|
}
|
||||||
|
|
||||||
@Override
|
{
|
||||||
public void run() {
|
setState(State.starting);
|
||||||
try {
|
new Thread(new Runnable() {
|
||||||
I2PD_JNI.loadLibraries();
|
|
||||||
setState(State.jniLibraryLoaded);
|
|
||||||
} catch (Throwable tr) {
|
|
||||||
lastThrowable = tr;
|
|
||||||
setState(State.startFailed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
synchronized (DaemonSingleton.this) {
|
|
||||||
I2PD_JNI.setDataDir(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd");
|
|
||||||
daemonStartResult = I2PD_JNI.startDaemon();
|
|
||||||
if ("ok".equals(daemonStartResult)) {
|
|
||||||
setState(State.startedOkay);
|
|
||||||
setStartedOkay(true);
|
|
||||||
} else
|
|
||||||
setState(State.startFailed);
|
|
||||||
}
|
|
||||||
} catch (Throwable tr) {
|
|
||||||
lastThrowable = tr;
|
|
||||||
setState(State.startFailed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}, "i2pdDaemonStart").start();
|
@Override
|
||||||
}
|
public void run() {
|
||||||
|
try {
|
||||||
|
I2PD_JNI.loadLibraries();
|
||||||
|
setState(State.jniLibraryLoaded);
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
lastThrowable = tr;
|
||||||
|
setState(State.startFailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
synchronized (DaemonSingleton.this) {
|
||||||
|
I2PD_JNI.setDataDir(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd");
|
||||||
|
daemonStartResult = I2PD_JNI.startDaemon();
|
||||||
|
if ("ok".equals(daemonStartResult)) {
|
||||||
|
setState(State.startedOkay);
|
||||||
|
setStartedOkay(true);
|
||||||
|
} else
|
||||||
|
setState(State.startFailed);
|
||||||
|
}
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
lastThrowable = tr;
|
||||||
|
setState(State.startFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Throwable lastThrowable;
|
}, "i2pdDaemonStart").start();
|
||||||
private String daemonStartResult = "N/A";
|
}
|
||||||
|
|
||||||
private void fireStateUpdate1() {
|
private Throwable lastThrowable;
|
||||||
Log.i(TAG, "daemon state change: " + state);
|
private String daemonStartResult = "N/A";
|
||||||
for (StateUpdateListener listener : stateUpdateListeners) {
|
|
||||||
try {
|
|
||||||
listener.daemonStateUpdate();
|
|
||||||
} catch (Throwable tr) {
|
|
||||||
Log.e(TAG, "exception in listener ignored", tr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Throwable getLastThrowable() {
|
private void fireStateUpdate1() {
|
||||||
return lastThrowable;
|
Log.i(TAG, "daemon state change: " + state);
|
||||||
}
|
for (StateUpdateListener listener : stateUpdateListeners) {
|
||||||
|
try {
|
||||||
|
listener.daemonStateUpdate();
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
Log.e(TAG, "exception in listener ignored", tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String getDaemonStartResult() {
|
public Throwable getLastThrowable() {
|
||||||
return daemonStartResult;
|
return lastThrowable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Object startedOkayLock = new Object();
|
public String getDaemonStartResult() {
|
||||||
|
return daemonStartResult;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isStartedOkay() {
|
private final Object startedOkayLock = new Object();
|
||||||
synchronized (startedOkayLock) {
|
|
||||||
return startedOkay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setStartedOkay(boolean startedOkay) {
|
public boolean isStartedOkay() {
|
||||||
synchronized (startedOkayLock) {
|
synchronized (startedOkayLock) {
|
||||||
this.startedOkay = startedOkay;
|
return startedOkay;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void stopDaemon() {
|
private void setStartedOkay(boolean startedOkay) {
|
||||||
if (isStartedOkay()) {
|
synchronized (startedOkayLock) {
|
||||||
try {
|
this.startedOkay = startedOkay;
|
||||||
I2PD_JNI.stopDaemon();
|
}
|
||||||
} catch(Throwable tr) {
|
}
|
||||||
Log.e(TAG, "", tr);
|
|
||||||
}
|
|
||||||
|
|
||||||
setStartedOkay(false);
|
public synchronized void stopDaemon() {
|
||||||
setState(State.stopped);
|
if (isStartedOkay()) {
|
||||||
}
|
try {
|
||||||
}
|
I2PD_JNI.stopDaemon();
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
Log.e(TAG, "", tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
setStartedOkay(false);
|
||||||
|
setState(State.stopped);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,140 +10,144 @@ import android.content.Intent;
|
|||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class ForegroundService extends Service {
|
public class ForegroundService extends Service {
|
||||||
private static final String TAG="FgService";
|
private static final String TAG = "FgService";
|
||||||
|
|
||||||
private volatile boolean shown;
|
private volatile boolean shown;
|
||||||
|
|
||||||
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
|
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
|
||||||
new DaemonSingleton.StateUpdateListener() {
|
new DaemonSingleton.StateUpdateListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void daemonStateUpdate() {
|
public void daemonStateUpdate() {
|
||||||
try {
|
try {
|
||||||
synchronized (ForegroundService.this) {
|
synchronized (ForegroundService.this) {
|
||||||
if (shown) cancelNotification();
|
if (shown) cancelNotification();
|
||||||
showNotification();
|
showNotification();
|
||||||
}
|
}
|
||||||
} catch (Throwable tr) {
|
} catch (Throwable tr) {
|
||||||
Log.e(TAG,"error ignored",tr);
|
Log.e(TAG, "error ignored", tr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private NotificationManager notificationManager;
|
private NotificationManager notificationManager;
|
||||||
|
|
||||||
// Unique Identification Number for the Notification.
|
// Unique Identification Number for the Notification.
|
||||||
// We use it on Notification start, and to cancel it.
|
// We use it on Notification start, and to cancel it.
|
||||||
private int NOTIFICATION = 1;
|
private int NOTIFICATION = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for clients to access. Because we know this service always
|
* Class for clients to access. Because we know this service always
|
||||||
* runs in the same process as its clients, we don't need to deal with
|
* runs in the same process as its clients, we don't need to deal with
|
||||||
* IPC.
|
* IPC.
|
||||||
*/
|
*/
|
||||||
public class LocalBinder extends Binder {
|
public class LocalBinder extends Binder {
|
||||||
ForegroundService getService() {
|
ForegroundService getService() {
|
||||||
return ForegroundService.this;
|
return ForegroundService.this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
|
DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
|
||||||
if (!shown) daemonStateUpdatedListener.daemonStateUpdate();
|
if (!shown) daemonStateUpdatedListener.daemonStateUpdate();
|
||||||
}
|
}
|
||||||
// Tell the user we started.
|
// Tell the user we started.
|
||||||
// Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show();
|
// Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
Log.i("ForegroundService", "Received start id " + startId + ": " + intent);
|
Log.i("ForegroundService", "Received start id " + startId + ": " + intent);
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener);
|
DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener);
|
||||||
cancelNotification();
|
cancelNotification();
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void cancelNotification() {
|
private synchronized void cancelNotification() {
|
||||||
// Cancel the persistent notification.
|
// Cancel the persistent notification.
|
||||||
notificationManager.cancel(NOTIFICATION);
|
notificationManager.cancel(NOTIFICATION);
|
||||||
|
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
|
|
||||||
// Tell the user we stopped.
|
// Tell the user we stopped.
|
||||||
//Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
|
//Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
|
||||||
shown=false;
|
shown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
return mBinder;
|
return mBinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the object that receives interactions from clients. See
|
// This is the object that receives interactions from clients. See
|
||||||
// RemoteService for a more complete example.
|
// RemoteService for a more complete example.
|
||||||
private final IBinder mBinder = new LocalBinder();
|
private final IBinder mBinder = new LocalBinder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a notification while this service is running.
|
* Show a notification while this service is running.
|
||||||
*/
|
*/
|
||||||
private synchronized void showNotification() {
|
private synchronized void showNotification() {
|
||||||
// In this sample, we'll use the same text for the ticker and the expanded notification
|
// In this sample, we'll use the same text for the ticker and the expanded notification
|
||||||
CharSequence text = getText(DaemonSingleton.getInstance().getState().getStatusStringResourceId());
|
CharSequence text = getText(DaemonSingleton.getInstance().getState().getStatusStringResourceId());
|
||||||
|
|
||||||
// The PendingIntent to launch our activity if the user selects this notification
|
// The PendingIntent to launch our activity if the user selects this notification
|
||||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
||||||
new Intent(this, I2PDActivity.class), 0);
|
new Intent(this, I2PDActivity.class), 0);
|
||||||
|
|
||||||
// If earlier version channel ID is not used
|
// If earlier version channel ID is not used
|
||||||
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
||||||
String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : "";
|
String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : "";
|
||||||
|
|
||||||
// Set the info for the views that show in the notification panel.
|
// Set the info for the views that show in the notification panel.
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon
|
.setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon
|
||||||
if(Build.VERSION.SDK_INT >= 16) builder = builder.setPriority(Notification.PRIORITY_DEFAULT);
|
if (Build.VERSION.SDK_INT >= 16)
|
||||||
if(Build.VERSION.SDK_INT >= 21) builder = builder.setCategory(Notification.CATEGORY_SERVICE);
|
builder = builder.setPriority(Notification.PRIORITY_DEFAULT);
|
||||||
Notification notification = builder
|
if (Build.VERSION.SDK_INT >= 21)
|
||||||
.setTicker(text) // the status text
|
builder = builder.setCategory(Notification.CATEGORY_SERVICE);
|
||||||
.setWhen(System.currentTimeMillis()) // the time stamp
|
Notification notification = builder
|
||||||
.setContentTitle(getText(R.string.app_name)) // the label of the entry
|
.setTicker(text) // the status text
|
||||||
.setContentText(text) // the contents of the entry
|
.setWhen(System.currentTimeMillis()) // the time stamp
|
||||||
.setContentIntent(contentIntent) // The intent to send when the entry is clicked
|
.setContentTitle(getText(R.string.app_name)) // the label of the entry
|
||||||
.build();
|
.setContentText(text) // the contents of the entry
|
||||||
|
.setContentIntent(contentIntent) // The intent to send when the entry is clicked
|
||||||
|
.build();
|
||||||
|
|
||||||
// Send the notification.
|
// Send the notification.
|
||||||
//mNM.notify(NOTIFICATION, notification);
|
//mNM.notify(NOTIFICATION, notification);
|
||||||
startForeground(NOTIFICATION, notification);
|
startForeground(NOTIFICATION, notification);
|
||||||
shown = true;
|
shown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private synchronized String createNotificationChannel() {
|
private synchronized String createNotificationChannel() {
|
||||||
String channelId = getString(R.string.app_name);
|
String channelId = getString(R.string.app_name);
|
||||||
CharSequence channelName = "I2Pd service";
|
CharSequence channelName = "I2Pd service";
|
||||||
NotificationChannel chan = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
|
NotificationChannel chan = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
|
||||||
//chan.setLightColor(Color.PURPLE);
|
//chan.setLightColor(Color.PURPLE);
|
||||||
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
||||||
NotificationManager service = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
|
NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
if(service!=null)service.createNotificationChannel(chan);
|
if (service != null) service.createNotificationChannel(chan);
|
||||||
else Log.e(TAG, "error: NOTIFICATION_SERVICE is null");
|
else Log.e(TAG, "error: NOTIFICATION_SERVICE is null");
|
||||||
return channelId;
|
return channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -15,156 +15,157 @@ import java.lang.reflect.Method;
|
|||||||
//android.permission.WRITE_EXTERNAL_STORAGE
|
//android.permission.WRITE_EXTERNAL_STORAGE
|
||||||
public class I2PDPermsAskerActivity extends Activity {
|
public class I2PDPermsAskerActivity extends Activity {
|
||||||
|
|
||||||
private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 0;
|
private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 0;
|
||||||
|
|
||||||
private Button button_request_write_ext_storage_perms;
|
private Button button_request_write_ext_storage_perms;
|
||||||
private TextView textview_retry;
|
private TextView textview_retry;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
//if less than Android 6, no runtime perms req system present
|
//if less than Android 6, no runtime perms req system present
|
||||||
if (android.os.Build.VERSION.SDK_INT < 23) {
|
if (android.os.Build.VERSION.SDK_INT < 23) {
|
||||||
startMainActivity();
|
startMainActivity();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_perms_asker);
|
setContentView(R.layout.activity_perms_asker);
|
||||||
button_request_write_ext_storage_perms = (Button) findViewById(R.id.button_request_write_ext_storage_perms);
|
button_request_write_ext_storage_perms = (Button) findViewById(R.id.button_request_write_ext_storage_perms);
|
||||||
textview_retry = (TextView) findViewById(R.id.textview_retry);
|
textview_retry = (TextView) findViewById(R.id.textview_retry);
|
||||||
|
|
||||||
button_request_write_ext_storage_perms.setOnClickListener(new View.OnClickListener() {
|
button_request_write_ext_storage_perms.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
request_write_ext_storage_perms();
|
request_write_ext_storage_perms();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
request_write_ext_storage_perms();
|
request_write_ext_storage_perms();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void request_write_ext_storage_perms() {
|
private void request_write_ext_storage_perms() {
|
||||||
|
|
||||||
textview_retry.setVisibility(TextView.GONE);
|
textview_retry.setVisibility(TextView.GONE);
|
||||||
button_request_write_ext_storage_perms.setVisibility(Button.GONE);
|
button_request_write_ext_storage_perms.setVisibility(Button.GONE);
|
||||||
|
|
||||||
Method methodCheckPermission;
|
Method methodCheckPermission;
|
||||||
Method method_shouldShowRequestPermissionRationale;
|
Method method_shouldShowRequestPermissionRationale;
|
||||||
Method method_requestPermissions;
|
Method method_requestPermissions;
|
||||||
try {
|
try {
|
||||||
methodCheckPermission = getClass().getMethod("checkSelfPermission", String.class);
|
methodCheckPermission = getClass().getMethod("checkSelfPermission", String.class);
|
||||||
method_shouldShowRequestPermissionRationale =
|
method_shouldShowRequestPermissionRationale =
|
||||||
getClass().getMethod("shouldShowRequestPermissionRationale", String.class);
|
getClass().getMethod("shouldShowRequestPermissionRationale", String.class);
|
||||||
method_requestPermissions =
|
method_requestPermissions =
|
||||||
getClass().getMethod("requestPermissions", String[].class, int.class);
|
getClass().getMethod("requestPermissions", String[].class, int.class);
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
Integer resultObj;
|
Integer resultObj;
|
||||||
try {
|
try {
|
||||||
resultObj = (Integer) methodCheckPermission.invoke(
|
resultObj = (Integer) methodCheckPermission.invoke(
|
||||||
this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resultObj != PackageManager.PERMISSION_GRANTED) {
|
if (resultObj != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
|
||||||
// Should we show an explanation?
|
// Should we show an explanation?
|
||||||
Boolean aBoolean;
|
Boolean aBoolean;
|
||||||
try {
|
try {
|
||||||
aBoolean = (Boolean) method_shouldShowRequestPermissionRationale.invoke(this,
|
aBoolean = (Boolean) method_shouldShowRequestPermissionRationale.invoke(this,
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
if (aBoolean) {
|
if (aBoolean) {
|
||||||
|
|
||||||
// Show an explanation to the user *asynchronously* -- don't block
|
// Show an explanation to the user *asynchronously* -- don't block
|
||||||
// this thread waiting for the user's response! After the user
|
// this thread waiting for the user's response! After the user
|
||||||
// sees the explanation, try again to request the permission.
|
// sees the explanation, try again to request the permission.
|
||||||
|
|
||||||
showExplanation();
|
showExplanation();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// No explanation needed, we can request the permission.
|
// No explanation needed, we can request the permission.
|
||||||
|
|
||||||
try {
|
try {
|
||||||
method_requestPermissions.invoke(this,
|
method_requestPermissions.invoke(this,
|
||||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||||
PERMISSION_WRITE_EXTERNAL_STORAGE);
|
PERMISSION_WRITE_EXTERNAL_STORAGE);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else startMainActivity();
|
} else startMainActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode,
|
public void onRequestPermissionsResult(int requestCode,
|
||||||
String permissions[], int[] grantResults) {
|
String permissions[], int[] grantResults) {
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case PERMISSION_WRITE_EXTERNAL_STORAGE: {
|
case PERMISSION_WRITE_EXTERNAL_STORAGE: {
|
||||||
// If request is cancelled, the result arrays are empty.
|
// If request is cancelled, the result arrays are empty.
|
||||||
if (grantResults.length > 0
|
if (grantResults.length > 0
|
||||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
|
||||||
// permission was granted, yay! Do the
|
// permission was granted, yay! Do the
|
||||||
// contacts-related task you need to do.
|
// contacts-related task you need to do.
|
||||||
|
|
||||||
startMainActivity();
|
startMainActivity();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// permission denied, boo! Disable the
|
// permission denied, boo! Disable the
|
||||||
// functionality that depends on this permission.
|
// functionality that depends on this permission.
|
||||||
textview_retry.setText(R.string.permDenied);
|
textview_retry.setText(R.string.permDenied);
|
||||||
textview_retry.setVisibility(TextView.VISIBLE);
|
textview_retry.setVisibility(TextView.VISIBLE);
|
||||||
button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE);
|
button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// other 'case' lines to check for other
|
// other 'case' lines to check for other
|
||||||
// permissions this app might request.
|
// permissions this app might request.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startMainActivity() {
|
private void startMainActivity() {
|
||||||
startActivity(new Intent(this, I2PDActivity.class));
|
startActivity(new Intent(this, I2PDActivity.class));
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int SHOW_EXPLANATION_REQUEST = 1; // The request code
|
private static final int SHOW_EXPLANATION_REQUEST = 1; // The request code
|
||||||
private void showExplanation() {
|
|
||||||
Intent intent = new Intent(this, I2PDPermsExplanationActivity.class);
|
|
||||||
startActivityForResult(intent, SHOW_EXPLANATION_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private void showExplanation() {
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
Intent intent = new Intent(this, I2PDPermsExplanationActivity.class);
|
||||||
// Check which request we're responding to
|
startActivityForResult(intent, SHOW_EXPLANATION_REQUEST);
|
||||||
if (requestCode == SHOW_EXPLANATION_REQUEST) {
|
}
|
||||||
// Make sure the request was successful
|
|
||||||
if (resultCode == RESULT_OK) {
|
@Override
|
||||||
// Request the permission
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
Method method_requestPermissions;
|
// Check which request we're responding to
|
||||||
try {
|
if (requestCode == SHOW_EXPLANATION_REQUEST) {
|
||||||
method_requestPermissions =
|
// Make sure the request was successful
|
||||||
getClass().getMethod("requestPermissions", String[].class, int.class);
|
if (resultCode == RESULT_OK) {
|
||||||
} catch (NoSuchMethodException e) {
|
// Request the permission
|
||||||
throw new RuntimeException(e);
|
Method method_requestPermissions;
|
||||||
}
|
try {
|
||||||
try {
|
method_requestPermissions =
|
||||||
method_requestPermissions.invoke(this,
|
getClass().getMethod("requestPermissions", String[].class, int.class);
|
||||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
} catch (NoSuchMethodException e) {
|
||||||
PERMISSION_WRITE_EXTERNAL_STORAGE);
|
throw new RuntimeException(e);
|
||||||
} catch (Exception e) {
|
}
|
||||||
throw new RuntimeException(e);
|
try {
|
||||||
}
|
method_requestPermissions.invoke(this,
|
||||||
} else {
|
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||||
finish(); //close the app
|
PERMISSION_WRITE_EXTERNAL_STORAGE);
|
||||||
}
|
} catch (Exception e) {
|
||||||
}
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
finish(); //close the app
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,30 +9,30 @@ import android.widget.Button;
|
|||||||
|
|
||||||
public class I2PDPermsExplanationActivity extends Activity {
|
public class I2PDPermsExplanationActivity extends Activity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_perms_explanation);
|
setContentView(R.layout.activity_perms_explanation);
|
||||||
ActionBar actionBar = getActionBar();
|
ActionBar actionBar = getActionBar();
|
||||||
if(actionBar!=null)actionBar.setHomeButtonEnabled(false);
|
if (actionBar != null) actionBar.setHomeButtonEnabled(false);
|
||||||
Button button_ok = (Button) findViewById(R.id.button_ok);
|
Button button_ok = (Button) findViewById(R.id.button_ok);
|
||||||
button_ok.setOnClickListener(new View.OnClickListener() {
|
button_ok.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
returnFromActivity();
|
returnFromActivity();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void returnFromActivity() {
|
private void returnFromActivity() {
|
||||||
Intent data = new Intent();
|
Intent data = new Intent();
|
||||||
Activity parent = getParent();
|
Activity parent = getParent();
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
setResult(Activity.RESULT_OK, data);
|
setResult(Activity.RESULT_OK, data);
|
||||||
} else {
|
} else {
|
||||||
parent.setResult(Activity.RESULT_OK, data);
|
parent.setResult(Activity.RESULT_OK, data);
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
package org.purplei2p.i2pd;
|
package org.purplei2p.i2pd;
|
||||||
|
|
||||||
public class I2PD_JNI {
|
public class I2PD_JNI {
|
||||||
public static native String getABICompiledWith();
|
public static native String getABICompiledWith();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns error info if failed
|
* returns error info if failed
|
||||||
* returns "ok" if daemon initialized and started okay
|
* returns "ok" if daemon initialized and started okay
|
||||||
*/
|
*/
|
||||||
public static native String startDaemon();
|
public static native String startDaemon();
|
||||||
|
|
||||||
//should only be called after startDaemon() success
|
//should only be called after startDaemon() success
|
||||||
public static native void stopDaemon();
|
public static native void stopDaemon();
|
||||||
|
|
||||||
public static native void stopAcceptingTunnels();
|
public static native void stopAcceptingTunnels();
|
||||||
|
|
||||||
public static native void startAcceptingTunnels();
|
public static native void startAcceptingTunnels();
|
||||||
|
|
||||||
public static native void reloadTunnelsConfigs();
|
public static native void reloadTunnelsConfigs();
|
||||||
|
|
||||||
public static native void onNetworkStateChanged(boolean isConnected);
|
public static native void onNetworkStateChanged(boolean isConnected);
|
||||||
|
|
||||||
public static native void setDataDir(String jdataDir);
|
public static native void setDataDir(String jdataDir);
|
||||||
|
|
||||||
public static native int GetTransitTunnelsCount();
|
public static native int GetTransitTunnelsCount();
|
||||||
|
|
||||||
public static void loadLibraries() {
|
public static void loadLibraries() {
|
||||||
//System.loadLibrary("c++_shared");
|
//System.loadLibrary("c++_shared");
|
||||||
System.loadLibrary("i2pd");
|
System.loadLibrary("i2pd");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,22 +9,23 @@ import android.net.NetworkInfo;
|
|||||||
|
|
||||||
public class NetworkStateChangeReceiver extends BroadcastReceiver {
|
public class NetworkStateChangeReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
private static final String TAG = "i2pd";
|
private static final String TAG = "i2pd";
|
||||||
|
|
||||||
//api level 1
|
//api level 1
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
Log.d(TAG,"Network state change");
|
Log.d(TAG, "Network state change");
|
||||||
try {
|
try {
|
||||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();
|
assert cm != null;
|
||||||
boolean isConnected = activeNetworkInfo!=null && activeNetworkInfo.isConnected();
|
NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();
|
||||||
// https://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html?hl=ru
|
boolean isConnected = activeNetworkInfo != null && activeNetworkInfo.isConnected();
|
||||||
// boolean isWiFi = activeNetworkInfo!=null && (activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
|
// https://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html?hl=ru
|
||||||
|
// boolean isWiFi = activeNetworkInfo!=null && (activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
|
||||||
|
|
||||||
I2PD_JNI.onNetworkStateChanged(isConnected);
|
I2PD_JNI.onNetworkStateChanged(isConnected);
|
||||||
} catch (Throwable tr) {
|
} catch (Throwable tr) {
|
||||||
Log.d(TAG,"",tr);
|
Log.d(TAG, "", tr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
<string name="startFailed">Start failed</string>
|
<string name="startFailed">Start failed</string>
|
||||||
<string name="stopped">Application stopped</string>
|
<string name="stopped">Application stopped</string>
|
||||||
<string name="remaining">remaining</string>
|
<string name="remaining">remaining</string>
|
||||||
<string name="ok">OK</string>
|
<string name="ok" translatable="false">OK</string>
|
||||||
|
|
||||||
<string name="title_activity_i2_pdperms_asker_prompt">Prompt</string>
|
<string name="title_activity_i2_pdperms_asker_prompt">Prompt</string>
|
||||||
<string name="permDenied">SD card write permission denied, you need to allow this to continue</string>
|
<string name="permDenied">SD card write permission denied, you need to allow this to continue</string>
|
||||||
|
@ -5,7 +5,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.4.2'
|
classpath 'com.android.tools.build:gradle:3.6.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
gradle/wrapper/gradle-wrapper.properties
vendored
12
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
#Tue Aug 20 14:39:08 MSK 2019
|
#Fri Jun 12 07:37:19 MSK 2020
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||||
|
@ -1 +1,2 @@
|
|||||||
include ':app'
|
include ':app'
|
||||||
|
project(":app").name = "i2pd"
|
Loading…
x
Reference in New Issue
Block a user