mirror of
https://github.com/PurpleI2P/i2pd-android.git
synced 2024-12-06 19:27:28 +01:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 97abcc661f | |||
| 8a791c45c2 | |||
| 4334fd4bdb | |||
| f0132e9847 | |||
| 06b567d910 | |||
| dd17608af9 | |||
| 2e10678278 |
@@ -71,4 +71,10 @@ Download Android SDK command line tools for Windows, unpack and install it repla
|
||||
|
||||
`ANDROID_SDK_ROOT` variable must point to SDK using linux-way path, like `/c/dev/android-sdk` when SDK installed to `C:\dev\android-sdk`.
|
||||
|
||||
Gradle can be called with `./gradlew` command inside project root, or you can install it using `pacman` and call `gradle` like on linux.
|
||||
Gradle can be called with `./gradlew` command inside project root, or you can install it using `pacman` and call `gradle` like on linux.
|
||||
|
||||
## Release signing
|
||||
|
||||
Current releases signed with certificate fingerprint (SHA-256):
|
||||
|
||||
`FC:C3:C7:34:9E:22:6A:77:B3:70:46:BB:00:FD:04:BB:A5:30:32:21:01:F8:62:F3:6D:8C:3D:B0:EB:B6:35:20`
|
||||
|
||||
+7
-6
@@ -3,19 +3,19 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.core:core:1.6.0'
|
||||
implementation 'androidx.core:core:1.9.0'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 32
|
||||
compileSdkVersion 33
|
||||
|
||||
defaultConfig {
|
||||
applicationId "org.purplei2p.i2pd"
|
||||
targetSdkVersion 32
|
||||
targetSdkVersion 33
|
||||
minSdkVersion 16
|
||||
versionCode 2450000
|
||||
versionName "2.45.0"
|
||||
versionCode 2450100
|
||||
versionName "2.45.1"
|
||||
archivesBaseName += "-$versionName"
|
||||
ndkVersion "23.2.8568313"
|
||||
|
||||
@@ -73,6 +73,7 @@ android {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
namespace 'org.purplei2p.i2pd'
|
||||
}
|
||||
|
||||
ext.abiCodes = ['armeabi-v7a': 1, 'x86': 2, 'arm64-v8a': 3, 'x86_64': 4]
|
||||
@@ -83,7 +84,7 @@ android.applicationVariants.all { variant ->
|
||||
def baseAbiVersionCode = project.ext.abiCodes.get(output.getFilter(OutputFile.ABI))
|
||||
|
||||
if (baseAbiVersionCode != null) {
|
||||
output.versionCodeOverride = baseAbiVersionCode * 10 + variant.versionCode
|
||||
output.versionCodeOverride = baseAbiVersionCode + variant.versionCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
Submodule app/jni/i2pd updated: 321c7cb7cf...f34abe60fa
@@ -1,12 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.purplei2p.i2pd"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:installLocation="auto">
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29" />
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
@@ -41,13 +45,14 @@
|
||||
android:label="NetworkChangeReceiver"
|
||||
android:exported="true" >
|
||||
<intent-filter>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"
|
||||
tools:ignore="BatteryLife" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name=".I2PDPermsAskerActivity"
|
||||
android:exported="false" >
|
||||
android:exported="true" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.purplei2p.i2pd;
|
||||
|
||||
import static android.app.PendingIntent.FLAG_IMMUTABLE;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
@@ -139,19 +141,19 @@ public class ForegroundService extends Service {
|
||||
|
||||
// The PendingIntent to launch our activity if the user selects this notification
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
||||
new Intent(this, I2PDActivity.class), 0);
|
||||
new Intent(this, I2PDActivity.class),
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? FLAG_IMMUTABLE : 0);
|
||||
|
||||
// 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)
|
||||
String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : "";
|
||||
String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? createNotificationChannel() : "";
|
||||
|
||||
// Set the info for the views that show in the notification panel.
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
|
||||
.setOngoing(true)
|
||||
.setSmallIcon(R.drawable.ic_notification_icon); // the status icon
|
||||
if (Build.VERSION.SDK_INT >= 16)
|
||||
builder = builder.setPriority(Notification.PRIORITY_DEFAULT);
|
||||
if (Build.VERSION.SDK_INT >= 21)
|
||||
builder = builder.setPriority(Notification.PRIORITY_DEFAULT);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
builder = builder.setCategory(Notification.CATEGORY_SERVICE);
|
||||
Notification notification = builder
|
||||
.setTicker(text) // the status text
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.net.ConnectivityManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.preference.PreferenceManager;
|
||||
@@ -126,11 +127,17 @@ public class I2PDActivity extends Activity {
|
||||
|
||||
daemon.addStateChangeListener(daemonStateUpdatedListener);
|
||||
daemonStateUpdatedListener.daemonStateUpdate(DaemonWrapper.State.uninitialized, daemon.getState());
|
||||
|
||||
// request permissions
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
if(!Environment.isExternalStorageManager()) {
|
||||
Log.e(TAG, "MANAGE_EXTERNAL_STORAGE perm declined, stopping i2pd");
|
||||
i2pdStop();
|
||||
}
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
|
||||
MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,11 @@ import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.provider.Settings;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
@@ -16,6 +20,7 @@ import java.lang.reflect.Method;
|
||||
public class I2PDPermsAskerActivity 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;
|
||||
@@ -24,7 +29,7 @@ public class I2PDPermsAskerActivity extends Activity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
//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 < Build.VERSION_CODES.M) {
|
||||
startMainActivity();
|
||||
return;
|
||||
}
|
||||
@@ -48,57 +53,66 @@ public class I2PDPermsAskerActivity extends Activity {
|
||||
textview_retry.setVisibility(TextView.GONE);
|
||||
button_request_write_ext_storage_perms.setVisibility(Button.GONE);
|
||||
|
||||
Method methodCheckPermission;
|
||||
Method method_shouldShowRequestPermissionRationale;
|
||||
Method method_requestPermissions;
|
||||
try {
|
||||
methodCheckPermission = getClass().getMethod("checkSelfPermission", String.class);
|
||||
method_shouldShowRequestPermissionRationale =
|
||||
getClass().getMethod("shouldShowRequestPermissionRationale", String.class);
|
||||
method_requestPermissions =
|
||||
getClass().getMethod("requestPermissions", String[].class, int.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Integer resultObj;
|
||||
try {
|
||||
resultObj = (Integer) methodCheckPermission.invoke(
|
||||
this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
if(!Environment.isExternalStorageManager()) {
|
||||
showExplanation();
|
||||
} else {
|
||||
startMainActivity();
|
||||
}
|
||||
} else {
|
||||
Method methodCheckPermission;
|
||||
Method method_shouldShowRequestPermissionRationale;
|
||||
Method method_requestPermissions;
|
||||
|
||||
if (resultObj != PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
// Should we show an explanation?
|
||||
Boolean aBoolean;
|
||||
try {
|
||||
aBoolean = (Boolean) method_shouldShowRequestPermissionRationale.invoke(this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
} catch (Exception e) {
|
||||
methodCheckPermission = getClass().getMethod("checkSelfPermission", String.class);
|
||||
method_shouldShowRequestPermissionRationale =
|
||||
getClass().getMethod("shouldShowRequestPermissionRationale", String.class);
|
||||
method_requestPermissions =
|
||||
getClass().getMethod("requestPermissions", String[].class, int.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (aBoolean) {
|
||||
|
||||
// Show an explanation to the user *asynchronously* -- don't block
|
||||
// this thread waiting for the user's response! After the user
|
||||
// sees the explanation, try again to request the permission.
|
||||
Integer resultObj;
|
||||
|
||||
showExplanation();
|
||||
|
||||
} else {
|
||||
|
||||
// No explanation needed, we can request the permission.
|
||||
try {
|
||||
resultObj = (Integer) methodCheckPermission.invoke(
|
||||
this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if (resultObj != PackageManager.PERMISSION_GRANTED) {
|
||||
// Should we show an explanation?
|
||||
Boolean aBoolean;
|
||||
try {
|
||||
method_requestPermissions.invoke(this,
|
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
PERMISSION_WRITE_EXTERNAL_STORAGE);
|
||||
aBoolean = (Boolean) method_shouldShowRequestPermissionRationale.invoke(this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
} else startMainActivity();
|
||||
|
||||
if (aBoolean) {
|
||||
|
||||
// Show an explanation to the user *asynchronously* -- don't block
|
||||
// this thread waiting for the user's response! After the user
|
||||
// sees the explanation, try again to request the permission.
|
||||
|
||||
showExplanation();
|
||||
|
||||
} else {
|
||||
// No explanation needed, we can request the permission.
|
||||
try {
|
||||
method_requestPermissions.invoke(this,
|
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
PERMISSION_WRITE_EXTERNAL_STORAGE);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
} else startMainActivity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,6 +150,7 @@ public class I2PDPermsAskerActivity extends Activity {
|
||||
}
|
||||
|
||||
private static final int SHOW_EXPLANATION_REQUEST = 1; // The request code
|
||||
private static final int APP_STORAGE_ACCESS_REQUEST_CODE = 2;
|
||||
|
||||
private void showExplanation() {
|
||||
Intent intent = new Intent(this, I2PDPermsExplanationActivity.class);
|
||||
@@ -144,11 +159,14 @@ public class I2PDPermsAskerActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
// Check which request we're responding to
|
||||
if (requestCode == SHOW_EXPLANATION_REQUEST) {
|
||||
// Make sure the request was successful
|
||||
if (resultCode == RESULT_OK) {
|
||||
// Request the permission
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
// Check which request we're responding to and make sure the request was successful
|
||||
if (requestCode == SHOW_EXPLANATION_REQUEST && resultCode == RESULT_OK) {
|
||||
// Request the permission
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
Intent intentManageAccess = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, Uri.parse("package:" + BuildConfig.APPLICATION_ID));
|
||||
startActivityForResult(intentManageAccess, APP_STORAGE_ACCESS_REQUEST_CODE);
|
||||
} else {
|
||||
Method method_requestPermissions;
|
||||
try {
|
||||
method_requestPermissions =
|
||||
@@ -163,9 +181,19 @@ public class I2PDPermsAskerActivity extends Activity {
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
finish(); //close the app
|
||||
}
|
||||
} else if (requestCode == APP_STORAGE_ACCESS_REQUEST_CODE && resultCode == RESULT_OK) {
|
||||
if (Environment.isExternalStorageManager()) {
|
||||
startMainActivity();
|
||||
} else {
|
||||
textview_retry.setText(R.string.permDenied);
|
||||
textview_retry.setVisibility(TextView.VISIBLE);
|
||||
button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE);
|
||||
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
finish(); // close the app
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,17 +1,17 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.1.3'
|
||||
classpath 'com.android.tools.build:gradle:7.3.1'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
* Fix storage access issue on Android 11+
|
||||
@@ -0,0 +1 @@
|
||||
* Fix installation and start on some Android 11+ devices
|
||||
@@ -0,0 +1 @@
|
||||
* Updated codebase to 2.45.1
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=f581709a9c35e9cb92e16f585d2c4bc99b2b1a5f85d2badbd3dc6bff59e1e6dd
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
||||
distributionSha256Sum=8cc27038d5dbd815759851ba53e70cf62e481b87494cc97cfd97982ada5ba634
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
Reference in New Issue
Block a user