Skip to content

Commit

Permalink
changes to enable unified push notifications in generic build. Signed…
Browse files Browse the repository at this point in the history
…-off-by: Gavin Element <[email protected]>
  • Loading branch information
gavine99 committed Sep 5, 2024
1 parent 4e9d6ac commit 8fde157
Show file tree
Hide file tree
Showing 81 changed files with 318 additions and 133 deletions.
3 changes: 3 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,9 @@ dependencies {
implementation "com.github.nextcloud-deps.hwsecurity:hwsecurity-fido:$fidoVersion"
implementation "com.github.nextcloud-deps.hwsecurity:hwsecurity-fido2:$fidoVersion"

// unified push library for generic flavour
genericImplementation 'org.codeberg.UnifiedPush:android-connector:2.4.0'

// document scanner not available on FDroid (generic) due to OpenCV binaries
gplayImplementation project(':appscan')
huaweiImplementation project(':appscan')
Expand Down
21 changes: 21 additions & 0 deletions app/src/generic/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Nextcloud - Android Client
~
~ SPDX-FileCopyrightText: 2024 TSI-mc <[email protected]>
~ SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<receiver android:exported="true" android:enabled="true" android:name="com.nextcloud.unifiedpush.UnifiedPush">
<intent-filter>
<action android:name="org.unifiedpush.android.connector.MESSAGE"/>
<action android:name="org.unifiedpush.android.connector.UNREGISTERED"/>
<action android:name="org.unifiedpush.android.connector.NEW_ENDPOINT"/>
<action android:name="org.unifiedpush.android.connector.REGISTRATION_FAILED"/>
</intent-filter>
</receiver>
</application>
</manifest>
102 changes: 102 additions & 0 deletions app/src/generic/java/com/nextcloud/unifiedpush/UnifiedPush.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Your Name <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.nextcloud.unifiedpush

import android.content.Context
import android.content.res.Resources
import android.util.TypedValue
import androidx.appcompat.view.ContextThemeWrapper
import androidx.work.WorkManager
import com.google.gson.Gson
import com.nextcloud.client.core.ClockImpl
import com.nextcloud.client.jobs.BackgroundJobManager
import com.nextcloud.client.jobs.BackgroundJobManagerImpl
import com.nextcloud.client.jobs.NotificationWork
import com.nextcloud.client.preferences.AppPreferencesImpl
import com.owncloud.android.MainApp
import com.owncloud.android.R
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl
import com.owncloud.android.datamodel.PushConfigurationState
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.ui.activity.DrawerActivity
import com.owncloud.android.utils.PushUtils
import org.unifiedpush.android.connector.ChooseDialog
import org.unifiedpush.android.connector.MessagingReceiver
import org.unifiedpush.android.connector.NoDistributorDialog
import org.unifiedpush.android.connector.RegistrationDialogContent
import org.unifiedpush.android.connector.UnifiedPush

class UnifiedPush : MessagingReceiver() {
private val TAG: String? = UnifiedPush::class.java.simpleName

companion object {
fun registerForPushMessaging(activity: DrawerActivity, accountName: String) {
if ((activity === null) || (activity.mHandler === null) || (activity.isFinishing === true))
return

// if a distributor is registered and available, re-register to ensure in sync
if (UnifiedPush.getSavedDistributor(activity) !== null) {
UnifiedPush.registerApp(activity, accountName)
} else {
// else, previous distributor has gone away (uninstalled maybe) or there never was one,
// register now if possible
activity.mHandler.post {
UnifiedPush.registerAppWithDialog(
ContextThemeWrapper(activity, R.style.Theme_ownCloud_Dialog),
accountName,
RegistrationDialogContent(
NoDistributorDialog(
message = activity.getString(R.string.unified_push_no_distributors_dialog_text),
title = activity.getString(R.string.unified_push_choose_distributor_title)
),
ChooseDialog(activity.getString(R.string.unified_push_choose_distributor_title))
)
)
}
}
}

fun unregisterForPushMessaging(accountName: String) {
val context = MainApp.getAppContext()

// unregister with distributor
UnifiedPush.unregisterApp(context, accountName)

// delete locally saved endpoint value
ArbitraryDataProviderImpl(context).deleteKeyForAccount(accountName, PushUtils.KEY_PUSH)
}
}

override fun onMessage(context: Context, message: ByteArray, instance: String) {
// called when a new message is received. The message contains the full POST body of the push message
Log_OC.d(TAG, "unified push message received")

val workManager = WorkManager.getInstance(context)
val preferences = AppPreferencesImpl.fromContext(context)
val backgroundJobManager: BackgroundJobManager = BackgroundJobManagerImpl(workManager, ClockImpl(), preferences)
backgroundJobManager.startNotificationJob(message.toString(Charsets.UTF_8), instance, NotificationWork.BACKEND_TYPE_UNIFIED_PUSH)
}

override fun onNewEndpoint(context: Context, endpoint: String, instance: String) {
// called when a new endpoint is to be used for sending push messages
val newAccountPushData = PushConfigurationState()
newAccountPushData.setPushToken(endpoint)
ArbitraryDataProviderImpl(context).storeOrUpdateKeyValue(instance, PushUtils.KEY_PUSH, Gson().toJson(newAccountPushData))
}

override fun onRegistrationFailed(context: Context, instance: String) {
// called when the registration is not possible, eg. no network
// just dump the registration to make sure it's cleaned up. re-register will be auto-reattempted
unregisterForPushMessaging(instance)
}

override fun onUnregistered(context: Context, instance: String) {
// called when this application is remotely unregistered from receiving push messages
unregisterForPushMessaging(instance)
}
}
28 changes: 26 additions & 2 deletions app/src/generic/java/com/owncloud/android/utils/PushUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@

import android.content.Context;

import android.accounts.Account;

import com.google.gson.Gson;
import com.nextcloud.client.account.UserAccountManager;
import com.nextcloud.client.preferences.AppPreferencesImpl;
import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl;
import com.owncloud.android.datamodel.PushConfigurationState;
import com.owncloud.android.datamodel.SignatureVerification;
import com.nextcloud.unifiedpush.UnifiedPush;
import com.owncloud.android.ui.activity.DrawerActivity;

import java.security.Key;

Expand All @@ -22,8 +29,25 @@ public final class PushUtils {
private PushUtils() {
}

public static void pushRegistrationToServer(final UserAccountManager accountManager, final String pushToken) {
// do nothing
public static void updateRegistrationsWithServer(final DrawerActivity activity,
final UserAccountManager accountManager,
final String pushToken) {
for (Account account : accountManager.getAccounts()) {
PushConfigurationState accountPushData = new Gson().fromJson(
new ArbitraryDataProviderImpl(MainApp.getAppContext()).getValue(account.name, KEY_PUSH),
PushConfigurationState.class
);
if ((accountPushData == null) || (accountPushData.isShouldBeDeleted() == false)) {
UnifiedPush.Companion.registerForPushMessaging(activity, account.name);
} else {
UnifiedPush.Companion.unregisterForPushMessaging(account.name);
}
}
}

public static void updateRegistrationsWithServerNoUI(final UserAccountManager accountManager,
final String pushToken) {
updateRegistrationsWithServer(null, accountManager, pushToken);
}

public static void reinitKeys(UserAccountManager accountManager) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
final String subject = data.get(NotificationWork.KEY_NOTIFICATION_SUBJECT);
final String signature = data.get(NotificationWork.KEY_NOTIFICATION_SIGNATURE);
if (subject != null && signature != null) {
backgroundJobManager.startNotificationJob(subject, signature);
backgroundJobManager.startNotificationJob(subject,
signature,
NotificationWork.BACKEND_TYPE_FIREBASE_CLOUD_MESSAGING);
}
}

Expand All @@ -52,7 +54,7 @@ public void onNewToken(@NonNull String newToken) {

if (!TextUtils.isEmpty(getResources().getString(R.string.push_server_url))) {
preferences.setPushToken(newToken);
PushUtils.pushRegistrationToServer(accountManager, preferences.getPushToken());
PushUtils.updateRegistrationsWithServer(null, accountManager, preferences.getPushToken());
}
}
}
12 changes: 10 additions & 2 deletions app/src/gplay/java/com/owncloud/android/utils/PushUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.owncloud.android.lib.resources.notifications.UnregisterAccountDeviceForNotificationsOperation;
import com.owncloud.android.lib.resources.notifications.UnregisterAccountDeviceForProxyOperation;
import com.owncloud.android.lib.resources.notifications.models.PushResponse;
import com.owncloud.android.ui.activity.DrawerActivity;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.io.FileUtils;
Expand Down Expand Up @@ -164,7 +165,9 @@ private static void deleteRegistrationForAccount(Account account) {
}
}

public static void pushRegistrationToServer(final UserAccountManager accountManager, final String token) {
public static void updateRegistrationsWithServer(final DrawerActivity activity,
final UserAccountManager accountManager,
final String token) {
arbitraryDataProvider = new ArbitraryDataProviderImpl(MainApp.getAppContext());

if (!TextUtils.isEmpty(MainApp.getAppContext().getResources().getString(R.string.push_server_url)) &&
Expand Down Expand Up @@ -246,6 +249,11 @@ public static void pushRegistrationToServer(final UserAccountManager accountMana
}
}

public static void updateRegistrationsWithServerNoUI(final UserAccountManager accountManager,
final String pushToken) {
updateRegistrationsWithServer(null, accountManager, pushToken);
}

public static Key readKeyFromFile(boolean readPublicKey) {
String keyPath = MainApp.getAppContext().getFilesDir().getAbsolutePath() + File.separator +
MainApp.getDataFolder() + File.separator + KEYPAIR_FOLDER;
Expand Down Expand Up @@ -343,7 +351,7 @@ public static void reinitKeys(final UserAccountManager accountManager) {

AppPreferences preferences = AppPreferencesImpl.fromContext(context);
String pushToken = preferences.getPushToken();
pushRegistrationToServer(accountManager, pushToken);
updateRegistrationsWithServer(null, accountManager, pushToken);
preferences.setKeysReInitEnabled();
}

Expand Down
10 changes: 9 additions & 1 deletion app/src/huawei/java/com/owncloud/android/utils/PushUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.nextcloud.client.preferences.AppPreferencesImpl;
import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.SignatureVerification;
import com.owncloud.android.ui.activity.DrawerActivity;

import java.security.Key;

Expand All @@ -22,7 +23,14 @@ public final class PushUtils {
private PushUtils() {
}

public static void pushRegistrationToServer(final UserAccountManager accountManager, final String pushToken) {
public static void updateRegistrationsWithServer(final DrawerActivity activity,
final UserAccountManager accountManager,
final String pushToken) {
// do nothing
}

public static void updateRegistrationsWithServerNoUI(final UserAccountManager accountManager,
final String pushToken) {
// do nothing
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class AccountRemovalWork(
PushUtils.KEY_PUSH,
gson.toJson(pushArbitraryData)
)
PushUtils.pushRegistrationToServer(userAccountManager, pushArbitraryData.getPushToken())
PushUtils.updateRegistrationsWithServerNoUI(userAccountManager, pushArbitraryData.getPushToken())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ interface BackgroundJobManager {
fun scheduleMediaFoldersDetectionJob()
fun startMediaFoldersDetectionJob()

fun startNotificationJob(subject: String, signature: String)
fun startNotificationJob(subject: String, signature: String, backendType: Int)
fun startAccountRemovalJob(accountName: String, remoteWipe: Boolean)
fun startFilesUploadJob(user: User)
fun getFileUploads(user: User): LiveData<List<JobInfo>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,10 +489,11 @@ internal class BackgroundJobManagerImpl(
)
}

override fun startNotificationJob(subject: String, signature: String) {
override fun startNotificationJob(subject: String, signature: String, backendType: Int) {
val data = Data.Builder()
.putString(NotificationWork.KEY_NOTIFICATION_SUBJECT, subject)
.putString(NotificationWork.KEY_NOTIFICATION_SIGNATURE, signature)
.putInt(NotificationWork.KEY_NOTIFICATION_TYPE, backendType)
.build()

val request = oneTimeRequestBuilder(NotificationWork::class, JOB_NOTIFICATION)
Expand Down
Loading

0 comments on commit 8fde157

Please sign in to comment.