Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android 14 update #2894

Merged
merged 17 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions app/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="org.commcare.dalvik"
xmlns:android="http://schemas.android.com/apk/res/android"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:versionCode="106"
android:versionName="2.55">
Expand Down Expand Up @@ -38,6 +37,7 @@
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
android:usesPermissionFlags="neverForLocation"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />

<uses-feature
android:name="android.hardware.telephony"
Expand Down Expand Up @@ -304,12 +304,14 @@
android:name="org.commcare.activities.FormRecordListActivity"
android:windowSoftInputMode="adjustResize">
</activity>

<service
android:enabled="true"
android:foregroundServiceType="specialUse"
android:name="org.commcare.services.CommCareSessionService">
<property
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="Service that maintains an encryption key in memory to securely submit data to the server" />
</service>

<activity
android:launchMode="singleTop"
android:name="org.commcare.activities.FormEntryActivity"
Expand Down Expand Up @@ -372,7 +374,9 @@
<activity android:name="org.commcare.activities.MessageActivity">
</activity>

<receiver android:name="org.commcare.views.notifications.NotificationClearReceiver">
<receiver
android:exported="false"
android:name="org.commcare.views.notifications.NotificationClearReceiver">
Comment on lines +377 to +379
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should either add a qa note to test clearning of notifications or test it out ourselves and mention it in safety story of the PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this and it worked fine, I will add a note to the PR.

</receiver>

<activity
Expand Down Expand Up @@ -560,6 +564,7 @@
Below code removes this receiver's entry from Manifest.
-->
<receiver android:name="io.ona.kujaku.receivers.KujakuNetworkChangeReceiver"
android:exported="false"
tools:node="remove"/>

<!-- The zebra-print-android library is not yet targeting Android 12 and at least one
Expand Down
55 changes: 28 additions & 27 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,32 @@ configurations {
}

dependencies {
testImplementation 'junit:junit:4.12'
testImplementation 'junit:junit:4.13.2'
testImplementation('org.robolectric:robolectric:4.8.2') {
exclude(group: 'org.bouncycastle', module: 'bcprov-jdk15on')
}
testImplementation 'androidx.test:core:1.5.0'
testImplementation 'androidx.test:runner:1.5.2'
testImplementation 'androidx.test.ext:junit:1.1.3'
testImplementation 'androidx.work:work-testing:2.7.1'
testImplementation 'androidx.test.espresso:espresso-core:3.4.0'
testImplementation 'androidx.test.espresso:espresso-intents:3.5.1'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.2'
testImplementation 'androidx.test:core:1.6.1'
testImplementation 'androidx.test:runner:1.6.2'
testImplementation 'androidx.test.ext:junit:1.2.1'
testImplementation 'androidx.work:work-testing:2.10.0'
testImplementation 'androidx.test.espresso:espresso-core:3.6.1'
testImplementation 'androidx.test.espresso:espresso-intents:3.6.1'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
testImplementation 'io.mockk:mockk:1.12.7'
testImplementation 'org.json:json:20140107'
testImplementation 'org.json:json:20231013'
testImplementation project(path: ':commcare-core', configuration: 'testsAsJar')

androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.ext:truth:1.4.0'
androidTestImplementation 'androidx.test:rules:1.5.0'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0'
androidTestImplementation 'androidx.test:runner:1.6.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.ext:truth:1.6.0'
androidTestImplementation 'androidx.test:rules:1.6.1'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.6.1'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.6.1'

// need uiautomator to rotate the device.
// this only works with API >=18
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.3.0'

// release build type expects commcare jars to be in app/libs
implementation(project(':commcare-core')) {
Expand Down Expand Up @@ -121,10 +121,10 @@ dependencies {
exclude group: 'com.mapbox.mapboxsdk', module: 'mapbox-android-accounts'
exclude group: 'io.realm'
}
implementation 'androidx.work:work-runtime:2.7.1'
implementation 'androidx.work:work-runtime-ktx:2.7.1'
implementation 'androidx.work:work-runtime:2.10.0'
implementation 'androidx.work:work-runtime-ktx:2.10.0'

implementation 'com.google.android.play:core:1.10.3'
implementation 'com.google.android.play:app-update:2.1.0'
implementation 'android.arch.lifecycle:common-java8:1.1.1'


Expand All @@ -138,7 +138,7 @@ dependencies {
implementation 'com.appmattus.certificatetransparency:certificatetransparency-android:2.5.4'

// Dependency required for API desugaring
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_minimal:2.0.3'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_minimal:2.1.3'
}

ext {
Expand Down Expand Up @@ -184,7 +184,7 @@ afterEvaluate {
* https://discuss.gradle.org/t/gradle-7-0-seems-to-take-an-overzealous-approach-to-inter-task-dependencies/39656/2
* Gradle 7.0 treats any copy tasks as having an implicit dependencies with each other.
*/
task injectPropertiesIntoFirebaseConfigFile {
tasks.register('injectPropertiesIntoFirebaseConfigFile') {
description = 'Injects properties into the google-services.json file at runtime'

copy {
Expand Down Expand Up @@ -222,7 +222,7 @@ static def getDate() {

android {
namespace 'org.commcare.dalvik'
compileSdk 33
compileSdk 35

lintOptions {
abortOnError false
Expand All @@ -249,7 +249,8 @@ android {

defaultConfig {
minSdkVersion 21
targetSdkVersion 33
targetSdkVersion 34

applicationId 'org.commcare.dalvik'
testNamespace 'org.commcare.dalvik.test'

Expand Down Expand Up @@ -491,7 +492,7 @@ android {
* Download and unpack commcare app associated with 'cc_app_id' into assets
* folder
*/
task downloadCCApp(type: Exec)
tasks.register('downloadCCApp', Exec)

// task configuration phase
downloadCCApp {
Expand Down Expand Up @@ -521,7 +522,7 @@ downloadCCApp {
}


task downloadRestoreFile(type: Exec)
tasks.register('downloadRestoreFile', Exec)

// task configuration phase
downloadRestoreFile {
Expand Down Expand Up @@ -551,7 +552,7 @@ downloadRestoreFile {
}

// dynamically inject commcare app download into standalone build process
tasks.whenTaskAdded { task ->
tasks.configureEach { task ->
if ((task.name == 'processStandaloneDebugResources' ||
task.name == 'processStandaloneReleaseResources') && 'true' == runDownloadScripts) {
task.dependsOn downloadCCApp
Expand Down
10 changes: 9 additions & 1 deletion app/src/org/commcare/activities/CommCareActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import android.content.DialogInterface;
import android.content.IntentFilter;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.text.Spannable;
import android.util.DisplayMetrics;
Expand Down Expand Up @@ -302,7 +303,14 @@ protected void onResume() {

if (shouldListenToSyncComplete() && isBackgroundSyncEnabled()) {
dataSyncCompleteBroadcastReceiver = new DataSyncCompleteBroadcastReceiver();
registerReceiver(dataSyncCompleteBroadcastReceiver, new IntentFilter(COMMCARE_DATA_UPDATE_ACTION));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(
dataSyncCompleteBroadcastReceiver,
new IntentFilter(COMMCARE_DATA_UPDATE_ACTION), Context.RECEIVER_NOT_EXPORTED);
} else {
registerReceiver(
dataSyncCompleteBroadcastReceiver, new IntentFilter(COMMCARE_DATA_UPDATE_ACTION));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,11 @@ public void onResumeSessionSafe() {
.findFragmentById(R.id.wifi_manager_fragment);

mReceiver = new WiFiDirectBroadcastReceiver(mManager, fragment);
registerReceiver(mReceiver, mIntentFilter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(mReceiver, mIntentFilter, Context.RECEIVER_EXPORTED);
} else {
registerReceiver(mReceiver, mIntentFilter);
}

fragment.startReceiver(mManager, mChannel);

Expand Down
12 changes: 10 additions & 2 deletions app/src/org/commcare/activities/FormEntryActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,11 @@ public void onReceive(Context context, Intent intent) {
IntentFilter filter = new IntentFilter();
filter.addAction(PollSensorAction.XPATH_ERROR_ACTION);
filter.addAction(GeoUtils.ACTION_LOCATION_ERROR);
registerReceiver(mLocationServiceIssueReceiver, filter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(mLocationServiceIssueReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
} else {
registerReceiver(mLocationServiceIssueReceiver, filter);
}
}

@Override
Expand Down Expand Up @@ -997,7 +1001,11 @@ public void onResumeSessionSafe() {
reportVideoUsageIfAny();

IntentFilter intentFilter = new IntentFilter(PENGING_SYNC_ALERT_ACTION);
registerReceiver(pendingSyncAlertBroadcastReceiver, intentFilter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(pendingSyncAlertBroadcastReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED);
} else {
registerReceiver(pendingSyncAlertBroadcastReceiver, intentFilter);
}

// Flag that a background sync shouldn't be triggered when this activity is in the foreground
CommCareApplication.instance().setBackgroundSyncSafe(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import android.content.IntentFilter
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import androidx.annotation.RequiresApi
import org.commcare.utils.GeoUtils

/**
Expand Down Expand Up @@ -47,7 +49,12 @@ class CommCareProviderLocationController(private var mContext: Context?,
mListener?.missingPermissions()
return
}
mContext?.registerReceiver(mReceiver, IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION))
val intentFilter = IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
mContext?.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_EXPORTED)
} else {
mContext?.registerReceiver(mReceiver, intentFilter)
}
checkProviderAndRequestLocation()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ private void showNotification(RemoteMessage.Notification notification) {
i.setAction(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_LAUNCHER);

PendingIntent contentIntent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
contentIntent = PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_IMMUTABLE);
else
contentIntent = PendingIntent.getActivity(this, 0, i, 0);
int pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
pendingIntentFlags = pendingIntentFlags | PendingIntent.FLAG_IMMUTABLE;
shubham1g5 marked this conversation as resolved.
Show resolved Hide resolved
}
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, i, pendingIntentFlags);

NotificationCompat.Builder fcmNotification = new NotificationCompat.Builder(this,
CommCareNoficationManager.NOTIFICATION_CHANNEL_PUSH_NOTIFICATIONS_ID)
Expand Down
19 changes: 11 additions & 8 deletions app/src/org/commcare/services/CommCareSessionService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
Expand Down Expand Up @@ -208,11 +209,14 @@ public IBinder onBind(Intent intent) {
/**
* Show a notification while this service is running.
*/
@SuppressLint("UnspecifiedImmutableFlag")
public void showLoggedInNotification(@Nullable User user) {
// Send the notification. This will cause error messages if CommCare doesn't have
// permission to post notifications
this.startForeground(NOTIFICATION, createSessionNotification());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
this.startForeground(NOTIFICATION, createSessionNotification(), ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
} else {
this.startForeground(NOTIFICATION, createSessionNotification());
}
}

/**
Expand Down Expand Up @@ -702,12 +706,11 @@ private Notification createSessionNotification(){
callable.setAction("android.intent.action.MAIN");
callable.addCategory("android.intent.category.LAUNCHER");

// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
contentIntent = PendingIntent.getActivity(this, 0, callable, PendingIntent.FLAG_IMMUTABLE);
else
contentIntent = PendingIntent.getActivity(this, 0, callable, 0);
int pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
pendingIntentFlags = pendingIntentFlags | PendingIntent.FLAG_IMMUTABLE;
}
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, callable, pendingIntentFlags);

String notificationText;
if (AppUtils.getInstalledAppRecords().size() > 1) {
Expand Down
8 changes: 7 additions & 1 deletion app/src/org/commcare/utils/SessionRegistrationHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Build;
import android.util.Log;

import org.commcare.activities.DispatchActivity;
Expand Down Expand Up @@ -52,7 +54,11 @@ public static boolean handleSessionExpiration(AppCompatActivity activity) {
}

public static void registerSessionExpirationReceiver(AppCompatActivity activity) {
activity.registerReceiver(userSessionExpiredReceiver, expirationFilter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
activity.registerReceiver(userSessionExpiredReceiver, expirationFilter, Context.RECEIVER_NOT_EXPORTED);
} else {
activity.registerReceiver(userSessionExpiredReceiver, expirationFilter);
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:8.0.1'
classpath 'com.android.tools.build:gradle:8.1.1'
classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
Expand Down
4 changes: 2 additions & 2 deletions commcare-support-library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ afterEvaluate {

android {
namespace "org.commcare.commcaresupportlibrary"
compileSdk 33
compileSdk 35
shubham1g5 marked this conversation as resolved.
Show resolved Hide resolved
defaultConfig {
minSdkVersion 21
targetSdkVersion 33
targetSdkVersion 34
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
Expand Down
2 changes: 1 addition & 1 deletion commcare-support-library/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="org.commcare.commcaresupportlibrary" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think we should be bumping the Android sdk version in support lib build.gradle as well to go along with this change.

<manifest />
Loading