Skip to content

Commit d3d6f81

Browse files
committed
update target SDK version: from 30 (Android 11) to 33 (Android 13)
changes: * Android 10+: add foreground service type * Android 11+: add permission to access all files * Android 12+: add mutability flag to pending intent in notification * Android 12+: show foreground service notification without 10s delay * Android 12+: remove content from collapsed state of notification - height restrictions for custom notifications on Android 12+: * 48dp: collapsed state * 88dp: heads up * 252dp: expanded state - height of custom notification: * 64dp * Android 13+: add runtime permission to show foreground service notification * update build tools see: * https://developer.android.com/about/versions/10/features#fg-service-types https://developer.android.com/reference/android/R.attr#foregroundServiceType * https://developer.android.com/about/versions/11/privacy/storage#permissions https://developer.android.com/about/versions/11/privacy/storage#all-files-access * https://developer.android.com/about/versions/12/behavior-changes-12#pending-intent-mutability * https://developer.android.com/about/versions/12/behavior-changes-all#foreground-service-notification-delay https://developer.android.com/guide/components/foreground-services#notification-immediate * https://developer.android.com/about/versions/12/behavior-changes-12#custom-notifications https://developer.android.com/develop/ui/views/notifications/custom-notification * https://developer.android.com/about/versions/13/behavior-changes-13#notification-permission-fgs-appearance https://developer.android.com/develop/ui/views/notifications/notification-permission
1 parent 6c8ec1a commit d3d6f81

File tree

10 files changed

+142
-34
lines changed

10 files changed

+142
-34
lines changed

android-studio-project/NodeJS-Frontend/src/main/AndroidManifest.xml

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@
77

88
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
99
<uses-permission android:name="android.permission.INTERNET"/>
10-
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
10+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
1111
<uses-permission android:name="android.permission.WAKE_LOCK" />
12-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
12+
13+
<!-- file access permissions: Android 1 to 10 -->
14+
<uses-permission android:maxSdkVersion="29" android:name="android.permission.READ_EXTERNAL_STORAGE"/>
15+
<uses-permission android:maxSdkVersion="29" android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
16+
17+
<!-- file access permissions: Android 11+ -->
18+
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
1319

1420
<application
1521
android:theme="@style/AppTheme"
@@ -25,7 +31,8 @@
2531
android:theme="@style/AppTheme"
2632
android:label="@string/app_name"
2733
android:configChanges="colorMode|density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
28-
android:launchMode="standard">
34+
android:launchMode="standard"
35+
android:exported="true">
2936
<intent-filter>
3037
<action android:name="android.intent.action.MAIN" />
3138
<category android:name="android.intent.category.LAUNCHER" />
@@ -37,13 +44,15 @@
3744
android:theme="@style/AppTheme"
3845
android:label="@string/app_name"
3946
android:configChanges="colorMode|density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
40-
android:launchMode="standard">
47+
android:launchMode="standard"
48+
android:exported="false">
4149
</activity>
4250

4351
<!-- one distinct-process service is used to execute non-daemon apps -->
4452

4553
<service
4654
android:name=".services.exec.RemoteService"
55+
android:foregroundServiceType="dataSync"
4756
android:process=":exec_process"
4857
android:enabled="true"
4958
android:exported="false" />
@@ -52,101 +61,121 @@
5261

5362
<service
5463
android:name=".services.fork.NodeService_01"
64+
android:foregroundServiceType="dataSync"
5565
android:process=":process_01"
5666
android:enabled="true"
5767
android:exported="true" />
5868
<service
5969
android:name=".services.fork.NodeService_02"
70+
android:foregroundServiceType="dataSync"
6071
android:process=":process_02"
6172
android:enabled="true"
6273
android:exported="true" />
6374
<service
6475
android:name=".services.fork.NodeService_03"
76+
android:foregroundServiceType="dataSync"
6577
android:process=":process_03"
6678
android:enabled="true"
6779
android:exported="true" />
6880
<service
6981
android:name=".services.fork.NodeService_04"
82+
android:foregroundServiceType="dataSync"
7083
android:process=":process_04"
7184
android:enabled="true"
7285
android:exported="true" />
7386
<service
7487
android:name=".services.fork.NodeService_05"
88+
android:foregroundServiceType="dataSync"
7589
android:process=":process_05"
7690
android:enabled="true"
7791
android:exported="true" />
7892
<service
7993
android:name=".services.fork.NodeService_06"
94+
android:foregroundServiceType="dataSync"
8095
android:process=":process_06"
8196
android:enabled="true"
8297
android:exported="true" />
8398
<service
8499
android:name=".services.fork.NodeService_07"
100+
android:foregroundServiceType="dataSync"
85101
android:process=":process_07"
86102
android:enabled="true"
87103
android:exported="true" />
88104
<service
89105
android:name=".services.fork.NodeService_08"
106+
android:foregroundServiceType="dataSync"
90107
android:process=":process_08"
91108
android:enabled="true"
92109
android:exported="true" />
93110
<service
94111
android:name=".services.fork.NodeService_09"
112+
android:foregroundServiceType="dataSync"
95113
android:process=":process_09"
96114
android:enabled="true"
97115
android:exported="true" />
98116
<service
99117
android:name=".services.fork.NodeService_10"
118+
android:foregroundServiceType="dataSync"
100119
android:process=":process_10"
101120
android:enabled="true"
102121
android:exported="true" />
103122
<service
104123
android:name=".services.fork.NodeService_11"
124+
android:foregroundServiceType="dataSync"
105125
android:process=":process_11"
106126
android:enabled="true"
107127
android:exported="true" />
108128
<service
109129
android:name=".services.fork.NodeService_12"
130+
android:foregroundServiceType="dataSync"
110131
android:process=":process_12"
111132
android:enabled="true"
112133
android:exported="true" />
113134
<service
114135
android:name=".services.fork.NodeService_13"
136+
android:foregroundServiceType="dataSync"
115137
android:process=":process_13"
116138
android:enabled="true"
117139
android:exported="true" />
118140
<service
119141
android:name=".services.fork.NodeService_14"
142+
android:foregroundServiceType="dataSync"
120143
android:process=":process_14"
121144
android:enabled="true"
122145
android:exported="true" />
123146
<service
124147
android:name=".services.fork.NodeService_15"
148+
android:foregroundServiceType="dataSync"
125149
android:process=":process_15"
126150
android:enabled="true"
127151
android:exported="true" />
128152
<service
129153
android:name=".services.fork.NodeService_16"
154+
android:foregroundServiceType="dataSync"
130155
android:process=":process_16"
131156
android:enabled="true"
132157
android:exported="true" />
133158
<service
134159
android:name=".services.fork.NodeService_17"
160+
android:foregroundServiceType="dataSync"
135161
android:process=":process_17"
136162
android:enabled="true"
137163
android:exported="true" />
138164
<service
139165
android:name=".services.fork.NodeService_18"
166+
android:foregroundServiceType="dataSync"
140167
android:process=":process_18"
141168
android:enabled="true"
142169
android:exported="true" />
143170
<service
144171
android:name=".services.fork.NodeService_19"
172+
android:foregroundServiceType="dataSync"
145173
android:process=":process_19"
146174
android:enabled="true"
147175
android:exported="true" />
148176
<service
149177
android:name=".services.fork.NodeService_20"
178+
android:foregroundServiceType="dataSync"
150179
android:process=":process_20"
151180
android:enabled="true"
152181
android:exported="true" />

android-studio-project/NodeJS-Frontend/src/main/java/com/github/warren_bank/nodejs_frontend/helpers/RuntimePermissionsMgr.java

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22

33
import android.app.Activity;
44
import android.content.Context;
5+
import android.content.Intent;
56
import android.content.pm.PackageInfo;
67
import android.content.pm.PackageManager;
78
import android.content.pm.PermissionInfo;
9+
import android.net.Uri;
810
import android.os.Build;
11+
import android.os.Environment;
12+
import android.provider.Settings;
13+
914
import java.util.ArrayList;
1015
import java.util.Collections;
1116
import java.util.Date;
@@ -34,19 +39,28 @@ private static ArrayList<String> getMandatoryPermissions(OnRuntimePermissionsLis
3439
}
3540

3641
public static boolean isEnabled(Activity activity) {
42+
boolean result = true;
43+
3744
if (Build.VERSION.SDK_INT < 23)
38-
return true;
45+
return result;
3946

4047
final String[] dangerousPermissions = getAllDangerousRequestedPermissions(activity);
48+
if ((dangerousPermissions != null) && (dangerousPermissions.length > 0)) {
49+
result = false;
50+
activity.requestPermissions(dangerousPermissions, REQUEST_CODE_PERMISSIONS);
51+
}
4152

42-
if ((dangerousPermissions == null) || (dangerousPermissions.length <= 0))
43-
return true;
53+
if ((Build.VERSION.SDK_INT >= 30) && !Environment.isExternalStorageManager()) {
54+
result = false;
55+
Uri uri = Uri.parse("package:" + activity.getPackageName());
56+
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri);
57+
activity.startActivityForResult(intent, REQUEST_CODE_PERMISSIONS);
58+
}
4459

45-
activity.requestPermissions(dangerousPermissions, REQUEST_CODE_PERMISSIONS);
46-
return false;
60+
return result;
4761
}
4862

49-
public static void onRequestPermissionsResult (Activity activity, OnRuntimePermissionsListener listener, int requestCode, String[] permissions, int[] grantResults) {
63+
public static void onRequestPermissionsResult(OnRuntimePermissionsListener listener, int requestCode, String[] permissions, int[] grantResults) {
5064
if (requestCode != REQUEST_CODE_PERMISSIONS)
5165
return;
5266

@@ -97,6 +111,18 @@ public static void onRequestPermissionsResult (Activity activity, OnRuntimePermi
97111
}
98112
}
99113

114+
public static void onActivityResult(OnRuntimePermissionsListener listener, int requestCode, int resultCode, Intent data) {
115+
if (requestCode != REQUEST_CODE_PERMISSIONS)
116+
return;
117+
118+
if (resultCode == Activity.RESULT_OK) {
119+
listener.onPermissionsGranted();
120+
}
121+
else {
122+
listener.onPermissionsDenied(/* permissions= */ null);
123+
}
124+
}
125+
100126
// =============================================================================================
101127
// required helpers
102128

android-studio-project/NodeJS-Frontend/src/main/java/com/github/warren_bank/nodejs_frontend/services/fork/AbstractNodeService.java

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,22 @@ private void hideNotification() {
163163
}
164164

165165
private Notification getNotification() {
166-
Notification notification = (Build.VERSION.SDK_INT >= 26)
167-
? (new Notification.Builder(/* context= */ AbstractNodeService.this, /* channelId= */ getNotificationChannelId())).build()
168-
: new Notification()
169-
;
166+
Notification notification;
167+
168+
if (Build.VERSION.SDK_INT >= 26) {
169+
Notification.Builder builder = new Notification.Builder(/* context= */ AbstractNodeService.this, /* channelId= */ getNotificationChannelId());
170+
171+
if (Build.VERSION.SDK_INT >= 31) {
172+
builder.setContentTitle(nodejs_app_name);
173+
builder.setContentText (getString(R.string.notification_service_content_line3));
174+
builder.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE);
175+
}
176+
177+
notification = builder.build();
178+
}
179+
else {
180+
notification = new Notification();
181+
}
170182

171183
notification.when = System.currentTimeMillis();
172184
notification.flags = 0;
@@ -193,7 +205,13 @@ private Notification getNotification() {
193205
contentView.setTextViewText(R.id.notification_text_line1, getString(R.string.notification_service_content_line1));
194206
contentView.setTextViewText(R.id.notification_text_line2, nodejs_app_name);
195207
contentView.setTextViewText(R.id.notification_text_line3, getString(R.string.notification_service_content_line3));
196-
notification.contentView = contentView;
208+
209+
if (Build.VERSION.SDK_INT < 31)
210+
notification.contentView = contentView;
211+
if (Build.VERSION.SDK_INT >= 16)
212+
notification.bigContentView = contentView;
213+
if (Build.VERSION.SDK_INT >= 21)
214+
notification.headsUpContentView = contentView;
197215

198216
return notification;
199217
}
@@ -202,7 +220,11 @@ private PendingIntent getPendingIntent_StopService() {
202220
Intent intent = new Intent(AbstractNodeService.this, AbstractNodeService.this.getClass());
203221
intent.setAction(ACTION_STOP);
204222

205-
return PendingIntent.getService(AbstractNodeService.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
223+
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
224+
if (Build.VERSION.SDK_INT >= 23)
225+
flags |= PendingIntent.FLAG_IMMUTABLE;
226+
227+
return PendingIntent.getService(AbstractNodeService.this, 0, intent, flags);
206228
}
207229

208230
}

android-studio-project/NodeJS-Frontend/src/main/java/com/github/warren_bank/nodejs_frontend/ui/activity_main/MainActivity.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.github.warren_bank.nodejs_frontend.ui.activity_main.tabs.AbstractTabFragment;
77

88
import android.content.Intent;
9+
import android.os.Build;
910
import android.os.Bundle;
1011
import android.os.Process;
1112
import android.text.TextUtils;
@@ -79,6 +80,8 @@ private AbstractTabFragment getCurrentTabFragment() {
7980
public void onActivityResult(int requestCode, int resultCode, Intent data) {
8081
super.onActivityResult(requestCode, resultCode, data);
8182

83+
RuntimePermissionsMgr.onActivityResult(/* listener= */ MainActivity.this, requestCode, resultCode, data);
84+
8285
BackupRestoreMgr.onActivityResult(/* activity= */ MainActivity.this, requestCode, resultCode, data);
8386

8487
AbstractTabFragment tabFragment = getCurrentTabFragment();
@@ -247,6 +250,8 @@ public void onPermissionsDeniedWithoutPrompt(String[] permissions) {
247250
}
248251

249252
private void showPermissionsDeniedNotification(String[] permissions) {
253+
if (permissions == null) return;
254+
250255
String divider = "\n• ";
251256

252257
String message;
@@ -258,6 +263,6 @@ private void showPermissionsDeniedNotification(String[] permissions) {
258263

259264
@Override
260265
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
261-
RuntimePermissionsMgr.onRequestPermissionsResult(/* activity= */ MainActivity.this, /* listener= */ MainActivity.this, requestCode, permissions, grantResults);
266+
RuntimePermissionsMgr.onRequestPermissionsResult(/* listener= */ MainActivity.this, requestCode, permissions, grantResults);
262267
}
263268
}

android-studio-project/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ buildscript {
66
}
77

88
dependencies {
9-
classpath 'com.android.tools.build:gradle:7.0.3' // https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google
9+
classpath 'com.android.tools.build:gradle:7.3.1' // https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google
1010
}
1111
}
1212

android-studio-project/constants.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ project.ext {
33
releaseVersion = '001.00.02-19API'
44
javaVersion = JavaVersion.VERSION_1_8
55
minSdkVersion = 19
6-
targetSdkVersion = 30
7-
compileSdkVersion = 30
8-
buildToolsVersion = '30.0.3'
6+
targetSdkVersion = 33
7+
compileSdkVersion = 33
8+
buildToolsVersion = '33.0.1'
99
ndkVersion = '21.3.6528147'
1010
cmakeVersion = '3.10.2.4988404'
1111

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,15 @@
11
android.useAndroidX=true
2+
3+
# ----------------------------------------------------------
4+
# increase RAM allocation in 2x places:
5+
#
6+
# 1) in file:
7+
# C:\Android\android-studio\bin\studio64.exe.vmoptions
8+
# by changing value from:
9+
# -Xmx768m
10+
# to:
11+
# -Xmx2048m
12+
#
13+
# 2) here:
214
org.gradle.jvmargs=-Xmx2048M
15+
# ----------------------------------------------------------

android-studio-project/gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
33
zipStoreBase=GRADLE_USER_HOME
44
zipStorePath=wrapper/dists
5-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-all.zip
5+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip

0 commit comments

Comments
 (0)