This commit is contained in:
andrew 2023-07-26 14:36:06 +09:30
parent 55216875ac
commit d3ea4e2e30
18 changed files with 99 additions and 85 deletions

View File

@ -1,10 +1,22 @@
package org.thoughtcrime.securesms.notifications
import android.content.Context
import com.huawei.hmf.tasks.Tasks
import com.huawei.hms.aaid.HmsInstanceId
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
class HuaweiPushManager(val context: Context): PushManager {
@Singleton
class HuaweiPushManager @Inject constructor(
@ApplicationContext private val context: Context,
private val genericPushManager: GenericPushManager
): PushManager {
private var huaweiPushInstanceIdJob: Job? = null
@Synchronized
@ -17,13 +29,11 @@ class HuaweiPushManager(val context: Context): PushManager {
val hmsInstanceId = HmsInstanceId.getInstance(context)
val task = hmsInstanceId.aaid
// HuaweiPushNotificationService().start()
//
// huaweiPushInstanceIdJob = HmsInstanceId.getInstance(this) { hmsInstanceId ->
// RegisterHuaweiPushService(hmsInstanceId, this, force).start()
// Unit.INSTANCE
// }
MainScope().launch(Dispatchers.IO) {
val task = hmsInstanceId.aaid
Tasks.await(task)
if (!isActive) return@launch // don't 'complete' task if we were canceled
task.result?.id?.let { genericPushManager.refresh(it, force) }
}
}
}

View File

@ -8,17 +8,6 @@ import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object HuaweiPushModule {
@Provides
@Singleton
fun provideFirebasePushManager(
@ApplicationContext context: Context,
) = HuaweiPushManager(context)
}
@Module
@InstallIn(SingletonComponent::class)
abstract class HuaweiBindingModule {

View File

@ -1,17 +1,9 @@
package org.thoughtcrime.securesms.notifications
import android.os.Bundle
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.huawei.hms.push.HmsMessageService
import com.huawei.hms.push.RemoteMessage
import dagger.hilt.android.AndroidEntryPoint
import org.session.libsession.messaging.jobs.BatchMessageReceiveJob
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.jobs.MessageReceiveParameters
import org.session.libsession.messaging.utilities.MessageWrapper
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.Log
import javax.inject.Inject
@ -20,16 +12,13 @@ class HuaweiPushNotificationService: HmsMessageService() {
@Inject lateinit var pushManager: PushManager
@Inject lateinit var pushHandler: PushHandler
override fun onNewToken(token: String?, bundle: Bundle?) {
Log.d("Loki", "New HCM token: $token.")
pushManager.refresh(true)
}
override fun onMessageReceived(message: RemoteMessage?) {
pushHandler.onPush(message?.dataOfMap)
}
override fun onDeletedMessages() {
pushManager.refresh(true)
}

View File

@ -67,6 +67,7 @@ import org.thoughtcrime.securesms.home.search.GlobalSearchViewModel
import org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.notifications.PushManager
import org.thoughtcrime.securesms.onboarding.SeedActivity
import org.thoughtcrime.securesms.onboarding.SeedReminderViewDelegate
import org.thoughtcrime.securesms.permissions.Permissions
@ -106,6 +107,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
@Inject lateinit var groupDatabase: GroupDatabase
@Inject lateinit var textSecurePreferences: TextSecurePreferences
@Inject lateinit var configFactory: ConfigFactory
@Inject lateinit var pushManager: PushManager
private val globalSearchViewModel by viewModels<GlobalSearchViewModel>()
private val homeViewModel by viewModels<HomeViewModel>()
@ -230,8 +232,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
(applicationContext as ApplicationContext).startPollingIfNeeded()
// update things based on TextSecurePrefs (profile info etc)
// Set up remaining components if needed
val application = ApplicationContext.getInstance(this@HomeActivity)
application.registerForPnIfNeeded(false)
pushManager.refresh(false)
if (textSecurePreferences.getLocalNumber() != null) {
OpenGroupManager.startPolling()
JobQueue.shared.resumePendingJobs()

View File

@ -1,7 +1,10 @@
package org.thoughtcrime.securesms.notifications
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import org.session.libsession.utilities.TextSecurePreferences
import javax.inject.Inject
import javax.inject.Singleton
class ExpiryManager(
private val context: Context,

View File

@ -1,12 +1,17 @@
package org.thoughtcrime.securesms.notifications
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import org.session.libsession.utilities.TextSecurePreferences
import javax.inject.Inject
import javax.inject.Singleton
class FcmTokenManager(
private val context: Context,
private val expiryManager: ExpiryManager
@Singleton
class FcmTokenManager @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val expiryManager = ExpiryManager(context)
val isUsingFCM get() = TextSecurePreferences.isUsingFCM(context)
var fcmToken

View File

@ -19,6 +19,7 @@ import org.session.libsession.utilities.ThemeUtil
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.home.HomeActivity
import org.thoughtcrime.securesms.notifications.PushManager
import org.thoughtcrime.securesms.showSessionDialog
import org.thoughtcrime.securesms.util.GlowViewUtilities
import org.thoughtcrime.securesms.util.PNModeView
@ -27,8 +28,12 @@ import org.thoughtcrime.securesms.util.getAccentColor
import org.thoughtcrime.securesms.util.getColorWithID
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
import org.thoughtcrime.securesms.util.show
import javax.inject.Inject
class PNModeActivity : BaseActionBarActivity() {
@Inject lateinit var pushManager: PushManager
private lateinit var binding: ActivityPnModeBinding
private var selectedOptionView: PNModeView? = null
@ -161,7 +166,7 @@ class PNModeActivity : BaseActionBarActivity() {
TextSecurePreferences.setIsUsingFCM(this, (selectedOptionView == binding.fcmOptionView))
val application = ApplicationContext.getInstance(this)
application.startPollingIfNeeded()
application.registerForPnIfNeeded(true)
pushManager.refresh(true)
val intent = Intent(this, HomeActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
intent.putExtra(HomeActivity.FROM_ONBOARDING, true)

View File

@ -1,10 +1,12 @@
package org.thoughtcrime.securesms.preferences
import android.os.Bundle
import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.R
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment
@AndroidEntryPoint
class NotificationSettingsActivity : PassphraseRequiredActionBarActivity() {
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {

View File

@ -23,14 +23,22 @@ import org.session.libsession.utilities.TextSecurePreferences;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.notifications.PushManager;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
import network.loki.messenger.R;
@AndroidEntryPoint
public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragment {
@SuppressWarnings("unused")
private static final String TAG = NotificationsPreferenceFragment.class.getSimpleName();
@Inject
PushManager pushManager;
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
@ -41,7 +49,7 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
this.findPreference(fcmKey)
.setOnPreferenceChangeListener((preference, newValue) -> {
TextSecurePreferences.setIsUsingFCM(getContext(), (boolean) newValue);
ApplicationContext.getInstance(getContext()).registerForPnIfNeeded(true);
pushManager.refresh(true);
return true;
});

View File

@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.notifications
import android.content.Context
import com.goterl.lazysodium.utils.KeyPair
import dagger.hilt.android.qualifiers.ApplicationContext
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.combine.and
import org.session.libsession.messaging.sending_receiving.notifications.PushManagerV1
@ -18,7 +19,7 @@ private const val TAG = "GenericPushManager"
@Singleton
class GenericPushManager @Inject constructor(
private val context: Context,
@ApplicationContext private val context: Context,
private val device: Device,
private val tokenManager: FcmTokenManager,
private val pushManagerV2: PushManagerV2,
@ -60,17 +61,25 @@ class GenericPushManager @Inject constructor(
publicKey: String,
userEd25519Key: KeyPair,
namespaces: List<Int> = listOf(Namespace.DEFAULT)
): Promise<*, Exception> = PushManagerV1.register(
token = token,
device = device,
publicKey = publicKey
) and pushManagerV2.register(
token, publicKey, userEd25519Key, namespaces
) fail {
Log.e(TAG, "registerBoth failed", it)
} success {
Log.d(TAG, "registerBoth success... saving token!!")
tokenManager.fcmToken = token
): Promise<*, Exception> {
val v1 = PushManagerV1.register(
device = device,
token = token,
publicKey = publicKey
) fail {
Log.e(TAG, "register v1 failed", it)
}
val v2 = pushManagerV2.register(
Device.ANDROID, token, publicKey, userEd25519Key, namespaces
) fail {
Log.e(TAG, "register v2 failed", it)
}
return v1 and v2 success {
Log.d(TAG, "registerBoth success... saving token!!")
tokenManager.fcmToken = token
}
}
private fun unregister(
@ -78,10 +87,10 @@ class GenericPushManager @Inject constructor(
userPublicKey: String,
userEdKey: KeyPair
): Promise<*, Exception> = PushManagerV1.unregister() and pushManagerV2.unregister(
token, userPublicKey, userEdKey
Device.ANDROID, token, userPublicKey, userEdKey
) fail {
Log.e(TAG, "unregisterBoth failed", it)
} success {
tokenManager.fcmToken = null
}
}
}

View File

@ -16,6 +16,7 @@ import org.session.libsession.messaging.sending_receiving.notifications.*
import org.session.libsession.snode.OnionRequestAPI
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.snode.Version
import org.session.libsession.utilities.Device
import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.Namespace
@ -31,6 +32,7 @@ class PushManagerV2 @Inject constructor(private val pushHandler: PushHandler) {
private val sodium = LazySodiumAndroid(SodiumAndroid())
fun register(
device: Device,
token: String,
publicKey: String,
userEd25519Key: KeyPair,
@ -48,7 +50,7 @@ class PushManagerV2 @Inject constructor(private val pushHandler: PushHandler) {
session_ed25519 = userEd25519Key.publicKey.asHexString,
namespaces = listOf(Namespace.DEFAULT),
data = true, // only permit data subscription for now (?)
service = "firebase",
service = device.service,
sig_ts = timestamp,
signature = Base64.encodeBytes(signature),
service_info = mapOf("token" to token),
@ -61,6 +63,7 @@ class PushManagerV2 @Inject constructor(private val pushHandler: PushHandler) {
}
fun unregister(
device: Device,
token: String,
userPublicKey: String,
userEdKey: KeyPair
@ -74,7 +77,7 @@ class PushManagerV2 @Inject constructor(private val pushHandler: PushHandler) {
val requestParameters = UnsubscriptionRequest(
pubkey = userPublicKey,
session_ed25519 = userEdKey.publicKey.asHexString,
service = "firebase",
service = device.service,
sig_ts = timestamp,
signature = Base64.encodeBytes(signature),
service_info = mapOf("token" to token),

View File

@ -4,7 +4,7 @@
<application tools:node="merge">
<service
android:name="org.thoughtcrime.securesms.notifications.PushNotificationService"
android:name="org.thoughtcrime.securesms.notifications.FirebasePushNotificationService"
android:enabled="true"
android:exported="false">
<intent-filter>

View File

@ -1,9 +1,6 @@
package org.thoughtcrime.securesms.notifications
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Job
import org.session.libsession.utilities.Device
import org.session.libsignal.utilities.Log
import javax.inject.Inject
import javax.inject.Singleton
@ -12,11 +9,9 @@ private const val TAG = "FirebasePushManager"
@Singleton
class FirebasePushManager @Inject constructor(
@ApplicationContext private val context: Context
private val genericPushManager: GenericPushManager
): PushManager {
@Inject lateinit var genericPushManager: GenericPushManager
private var firebaseInstanceIdJob: Job? = null
@Synchronized
@ -24,7 +19,10 @@ class FirebasePushManager @Inject constructor(
Log.d(TAG, "refresh() called with: force = $force")
firebaseInstanceIdJob?.apply {
if (force) cancel() else if (isActive) return
when {
force -> cancel()
isActive -> return
}
}
firebaseInstanceIdJob = getFcmInstanceId { task ->

View File

@ -1,23 +1,15 @@
package org.thoughtcrime.securesms.notifications
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import dagger.hilt.android.AndroidEntryPoint
import org.session.libsession.messaging.jobs.BatchMessageReceiveJob
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.jobs.MessageReceiveParameters
import org.session.libsession.messaging.utilities.MessageWrapper
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.Log
import javax.inject.Inject
private const val TAG = "PushNotificationService"
private const val TAG = "FirebasePushNotificationService"
@AndroidEntryPoint
class PushNotificationService : FirebaseMessagingService() {
class FirebasePushNotificationService : FirebaseMessagingService() {
@Inject lateinit var pushManager: PushManager
@Inject lateinit var pushHandler: PushHandler
@ -37,7 +29,6 @@ class PushNotificationService : FirebaseMessagingService() {
override fun onDeletedMessages() {
Log.d(TAG, "Called onDeletedMessages.")
super.onDeletedMessages()
pushManager.refresh(true)
}
}

View File

@ -94,7 +94,7 @@ fun MessageSender.create(
// Add the group to the config now that it was successfully created
storage.createInitialConfigGroup(groupPublicKey, name, GroupUtil.createConfigMemberMap(members, admins), sentTime, encryptionKeyPair)
// Notify the PN server
PushManagerV1.register(publicKey = userPublicKey, device = device)
PushManagerV1.register(device = device, publicKey = userPublicKey)
// Start polling
ClosedGroupPollerV2.shared.startPolling(groupPublicKey)
// Fulfill the promise

View File

@ -556,7 +556,7 @@ private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPubli
// Set expiration timer
storage.setExpirationTimer(groupID, expireTimer)
// Notify the PN server
PushManagerV1.register(publicKey = userPublicKey, device = MessagingModuleConfiguration.shared.device)
PushManagerV1.register(device = MessagingModuleConfiguration.shared.device, publicKey = userPublicKey)
// Notify the user
if (userPublicKey == sender && !groupExists) {
val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID))

View File

@ -27,18 +27,19 @@ object PushManagerV1 {
private val server = Server.LEGACY
fun register(
device: Device,
isUsingFCM: Boolean = TextSecurePreferences.isUsingFCM(context),
token: String? = TextSecurePreferences.getFCMToken(context),
publicKey: String? = TextSecurePreferences.getLocalNumber(context),
device: Device,
legacyGroupPublicKeys: Collection<String> = MessagingModuleConfiguration.shared.storage.getAllClosedGroupPublicKeys()
): Promise<*, Exception> =
if (!isUsingFCM) {
emptyPromise()
} else retryIfNeeded(maxRetryCount) {
doRegister(token, publicKey, device, legacyGroupPublicKeys)
} fail { exception ->
Log.d(TAG, "Couldn't register for FCM due to error: $exception.")
when {
isUsingFCM -> retryIfNeeded(maxRetryCount) {
doRegister(token, publicKey, device, legacyGroupPublicKeys)
} fail { exception ->
Log.d(TAG, "Couldn't register for FCM due to error: $exception.")
}
else -> emptyPromise()
}
private fun doRegister(token: String?, publicKey: String?, device: Device, legacyGroupPublicKeys: Collection<String>): Promise<*, Exception> {
@ -50,7 +51,7 @@ object PushManagerV1 {
val parameters = mapOf(
"token" to token,
"pubKey" to publicKey,
"device" to device,
"device" to device.value,
"legacyGroupPublicKeys" to legacyGroupPublicKeys
)

View File

@ -1,6 +1,6 @@
package org.session.libsession.utilities
enum class Device(val value: String) {
ANDROID("android"),
enum class Device(val value: String, val service: String = value) {
ANDROID("android", "firebase"),
HUAWEI("huawei");
}