mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-23 00:17:34 +00:00
Refactor to accept Huawei token from getToken() and/or onNewToken()
This commit is contained in:
parent
c8dcfbf32c
commit
5a5b2f593f
@ -14,11 +14,6 @@ private val TAG = HuaweiPushService::class.java.simpleName
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class HuaweiPushService: HmsMessageService() {
|
class HuaweiPushService: HmsMessageService() {
|
||||||
|
|
||||||
init {
|
|
||||||
Log.d(TAG, "init Huawei Service")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject lateinit var pushRegistry: PushRegistry
|
@Inject lateinit var pushRegistry: PushRegistry
|
||||||
@Inject lateinit var pushReceiver: PushReceiver
|
@Inject lateinit var pushReceiver: PushReceiver
|
||||||
|
|
||||||
@ -32,33 +27,13 @@ class HuaweiPushService: HmsMessageService() {
|
|||||||
pushReceiver.onPush(message?.data?.let(Base64::decode))
|
pushReceiver.onPush(message?.data?.let(Base64::decode))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMessageSent(p0: String?) {
|
override fun onNewToken(token: String?) {
|
||||||
Log.d(TAG, "onMessageSent() called with: p0 = $p0")
|
pushRegistry.register(token)
|
||||||
super.onMessageSent(p0)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSendError(p0: String?, p1: Exception?) {
|
|
||||||
Log.d(TAG, "onSendError() called with: p0 = $p0, p1 = $p1")
|
|
||||||
super.onSendError(p0, p1)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMessageDelivered(p0: String?, p1: Exception?) {
|
|
||||||
Log.d(TAG, "onMessageDelivered")
|
|
||||||
super.onMessageDelivered(p0, p1)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun onNewToken(p0: String?) {
|
|
||||||
Log.d(TAG, "onNewToken")
|
|
||||||
super.onNewToken(p0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewToken(token: String?, bundle: Bundle?) {
|
override fun onNewToken(token: String?, bundle: Bundle?) {
|
||||||
Log.d(TAG, "New HCM token: $token.")
|
Log.d(TAG, "New HCM token: $token.")
|
||||||
|
onNewToken(token)
|
||||||
TextSecurePreferences.setPushToken(this, token)
|
|
||||||
|
|
||||||
pushRegistry.refresh(token, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDeletedMessages() {
|
override fun onDeletedMessages() {
|
||||||
|
@ -2,26 +2,28 @@ package org.thoughtcrime.securesms.notifications
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.huawei.hms.aaid.HmsInstanceId
|
import com.huawei.hms.aaid.HmsInstanceId
|
||||||
|
import dagger.Lazy
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.session.libsignal.utilities.Log
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
private const val APP_ID = "107205081"
|
||||||
|
private const val TOKEN_SCOPE = "HCM"
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class HuaweiTokenFetcher @Inject constructor(
|
class HuaweiTokenFetcher @Inject constructor(
|
||||||
@ApplicationContext private val context: Context
|
@ApplicationContext private val context: Context,
|
||||||
|
private val pushRegistry: Lazy<PushRegistry>,
|
||||||
): TokenFetcher {
|
): TokenFetcher {
|
||||||
override fun fetch(): Job {
|
override suspend fun fetch(): String? = HmsInstanceId.getInstance(context).run {
|
||||||
val hmsInstanceId = HmsInstanceId.getInstance(context)
|
// https://developer.huawei.com/consumer/en/doc/development/HMS-Guides/push-basic-capability#h2-1576218800370
|
||||||
|
// getToken may return an empty string, if so HuaweiPushService#onNewToken will be called.
|
||||||
return MainScope().launch(Dispatchers.IO) {
|
withContext(Dispatchers.IO) { getToken(APP_ID, TOKEN_SCOPE) }
|
||||||
val appId = "107205081"
|
|
||||||
val tokenScope = "HCM"
|
|
||||||
// getToken returns an empty string, but triggers the service to initialize.
|
|
||||||
hmsInstanceId.getToken(appId, tokenScope)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,11 +427,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class ProviderInitializationException extends RuntimeException { }
|
private static class ProviderInitializationException extends RuntimeException { }
|
||||||
|
|
||||||
public void registerForPnIfNeeded(final Boolean force) {
|
|
||||||
pushRegistry.refresh(force);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setUpPollingIfNeeded() {
|
private void setUpPollingIfNeeded() {
|
||||||
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||||
if (userPublicKey == null) return;
|
if (userPublicKey == null) return;
|
||||||
|
@ -75,7 +75,7 @@ class PushReceiver @Inject constructor(@ApplicationContext val context: Context)
|
|||||||
else -> this["ENCRYPTED_DATA"]?.let(Base64::decode)
|
else -> this["ENCRYPTED_DATA"]?.let(Base64::decode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decrypt(encPayload: ByteArray): ByteArray? {
|
private fun decrypt(encPayload: ByteArray): ByteArray? {
|
||||||
Log.d(TAG, "decrypt() called")
|
Log.d(TAG, "decrypt() called")
|
||||||
|
|
||||||
val encKey = getOrCreateNotificationKey()
|
val encKey = getOrCreateNotificationKey()
|
||||||
|
@ -4,6 +4,8 @@ import android.content.Context
|
|||||||
import com.goterl.lazysodium.utils.KeyPair
|
import com.goterl.lazysodium.utils.KeyPair
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.MainScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import nl.komponents.kovenant.Promise
|
import nl.komponents.kovenant.Promise
|
||||||
import nl.komponents.kovenant.combine.and
|
import nl.komponents.kovenant.combine.and
|
||||||
import org.session.libsession.messaging.sending_receiving.notifications.PushRegistryV1
|
import org.session.libsession.messaging.sending_receiving.notifications.PushRegistryV1
|
||||||
@ -22,8 +24,10 @@ private val TAG = PushRegistry::class.java.name
|
|||||||
class PushRegistry @Inject constructor(
|
class PushRegistry @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
private val device: Device,
|
private val device: Device,
|
||||||
private val tokenManager: PushTokenManager,
|
private val tokenManager: TokenManager,
|
||||||
private val pushRegistryV2: PushRegistryV2,
|
private val pushRegistryV2: PushRegistryV2,
|
||||||
|
private val prefs: TextSecurePreferences,
|
||||||
|
private val tokenFetcher: TokenFetcher,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private var pushRegistrationJob: Job? = null
|
private var pushRegistrationJob: Job? = null
|
||||||
@ -32,42 +36,33 @@ class PushRegistry @Inject constructor(
|
|||||||
Log.d(TAG, "refresh() called with: force = $force")
|
Log.d(TAG, "refresh() called with: force = $force")
|
||||||
|
|
||||||
pushRegistrationJob?.apply {
|
pushRegistrationJob?.apply {
|
||||||
if (force) cancel() else if (isActive) return
|
if (force) cancel() else if (isActive || !tokenManager.hasValidRegistration) return
|
||||||
}
|
}
|
||||||
|
|
||||||
pushRegistrationJob = tokenManager.fetchToken()
|
pushRegistrationJob = MainScope().launch {
|
||||||
|
register(tokenFetcher.fetch()) fail {
|
||||||
|
Log.e(TAG, "register failed", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refresh(token: String?, force: Boolean): Promise<*, Exception> {
|
fun register(token: String?): Promise<*, Exception> {
|
||||||
Log.d(TAG, "refresh($token, $force) called")
|
Log.d(TAG, "refresh($token) called")
|
||||||
|
|
||||||
token ?: return emptyPromise()
|
if (token?.isNotEmpty() != true) return emptyPromise()
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context) ?: return emptyPromise()
|
|
||||||
|
prefs.setPushToken(token)
|
||||||
|
|
||||||
|
val userPublicKey = prefs.getLocalNumber() ?: return emptyPromise()
|
||||||
val userEdKey = KeyPairUtilities.getUserED25519KeyPair(context) ?: return emptyPromise()
|
val userEdKey = KeyPairUtilities.getUserED25519KeyPair(context) ?: return emptyPromise()
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
tokenManager.isPushEnabled -> register(force, token, userPublicKey, userEdKey)
|
prefs.isPushEnabled() -> register(token, userPublicKey, userEdKey)
|
||||||
tokenManager.requiresUnregister -> unregister(token, userPublicKey, userEdKey)
|
tokenManager.isRegistered -> unregister(token, userPublicKey, userEdKey)
|
||||||
else -> emptyPromise()
|
else -> emptyPromise()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Register for push notifications if:
|
|
||||||
* force is true
|
|
||||||
* there is no FCM Token
|
|
||||||
* FCM Token has expired
|
|
||||||
*/
|
|
||||||
private fun register(
|
|
||||||
force: Boolean,
|
|
||||||
token: String,
|
|
||||||
publicKey: String,
|
|
||||||
userEd25519Key: KeyPair,
|
|
||||||
namespaces: List<Int> = listOf(Namespace.DEFAULT)
|
|
||||||
): Promise<*, Exception> = if (force || tokenManager.isInvalid()) {
|
|
||||||
register(token, publicKey, userEd25519Key, namespaces)
|
|
||||||
} else emptyPromise()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register for push notifications.
|
* Register for push notifications.
|
||||||
*/
|
*/
|
||||||
@ -77,7 +72,7 @@ class PushRegistry @Inject constructor(
|
|||||||
userEd25519Key: KeyPair,
|
userEd25519Key: KeyPair,
|
||||||
namespaces: List<Int> = listOf(Namespace.DEFAULT)
|
namespaces: List<Int> = listOf(Namespace.DEFAULT)
|
||||||
): Promise<*, Exception> {
|
): Promise<*, Exception> {
|
||||||
android.util.Log.d(
|
Log.d(
|
||||||
TAG,
|
TAG,
|
||||||
"register() called with: token = $token, publicKey = $publicKey, userEd25519Key = $userEd25519Key, namespaces = $namespaces"
|
"register() called with: token = $token, publicKey = $publicKey, userEd25519Key = $userEd25519Key, namespaces = $namespaces"
|
||||||
)
|
)
|
||||||
@ -97,8 +92,8 @@ class PushRegistry @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return v1 and v2 success {
|
return v1 and v2 success {
|
||||||
Log.d(TAG, "registerBoth success... saving token!!")
|
Log.d(TAG, "register v1 & v2 success")
|
||||||
tokenManager.fcmToken = token
|
tokenManager.register()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,6 +106,6 @@ class PushRegistry @Inject constructor(
|
|||||||
) fail {
|
) fail {
|
||||||
Log.e(TAG, "unregisterBoth failed", it)
|
Log.e(TAG, "unregisterBoth failed", it)
|
||||||
} success {
|
} success {
|
||||||
tokenManager.fcmToken = null
|
tokenManager.unregister()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,34 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.notifications
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class PushTokenManager @Inject constructor(
|
|
||||||
@ApplicationContext private val context: Context,
|
|
||||||
private val tokenFetcher: TokenFetcher
|
|
||||||
) {
|
|
||||||
private val expiryManager = ExpiryManager(context)
|
|
||||||
|
|
||||||
val isPushEnabled get() = TextSecurePreferences.isPushEnabled(context)
|
|
||||||
|
|
||||||
var fcmToken
|
|
||||||
get() = TextSecurePreferences.getPushToken(context)
|
|
||||||
set(value) {
|
|
||||||
TextSecurePreferences.setPushToken(context, value)
|
|
||||||
if (value != null) markTime() else clearTime()
|
|
||||||
}
|
|
||||||
|
|
||||||
val requiresUnregister get() = fcmToken != null
|
|
||||||
|
|
||||||
private fun clearTime() = expiryManager.clearTime()
|
|
||||||
private fun markTime() = expiryManager.markTime()
|
|
||||||
private fun isExpired() = expiryManager.isExpired()
|
|
||||||
|
|
||||||
fun isInvalid(): Boolean = fcmToken == null || isExpired()
|
|
||||||
fun fetchToken(): Job = tokenFetcher.fetch()
|
|
||||||
}
|
|
@ -1,7 +1,5 @@
|
|||||||
package org.thoughtcrime.securesms.notifications
|
package org.thoughtcrime.securesms.notifications
|
||||||
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
|
|
||||||
interface TokenFetcher {
|
interface TokenFetcher {
|
||||||
fun fetch(): Job
|
suspend fun fetch(): String?
|
||||||
}
|
}
|
||||||
|
@ -6,17 +6,21 @@ import org.session.libsession.utilities.TextSecurePreferences
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
class ExpiryManager(
|
private const val INTERVAL: Int = 12 * 60 * 60 * 1000
|
||||||
private val context: Context,
|
|
||||||
private val interval: Int = 12 * 60 * 60 * 1000
|
|
||||||
) {
|
|
||||||
fun isExpired() = currentTime() > time + interval
|
|
||||||
|
|
||||||
fun markTime() {
|
@Singleton
|
||||||
|
class TokenManager @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
) {
|
||||||
|
val hasValidRegistration get() = isRegistered && !isExpired
|
||||||
|
val isRegistered get() = time > 0
|
||||||
|
private val isExpired get() = currentTime() > time + INTERVAL
|
||||||
|
|
||||||
|
fun register() {
|
||||||
time = currentTime()
|
time = currentTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearTime() {
|
fun unregister() {
|
||||||
time = 0
|
time = 0
|
||||||
}
|
}
|
||||||
|
|
@ -18,7 +18,7 @@ class FirebasePushService : FirebaseMessagingService() {
|
|||||||
override fun onNewToken(token: String) {
|
override fun onNewToken(token: String) {
|
||||||
if (token == prefs.getPushToken()) return
|
if (token == prefs.getPushToken()) return
|
||||||
|
|
||||||
pushRegistry.refresh(token, true)
|
pushRegistry.register(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMessageReceived(message: RemoteMessage) {
|
override fun onMessageReceived(message: RemoteMessage) {
|
||||||
|
@ -1,43 +1,19 @@
|
|||||||
package org.thoughtcrime.securesms.notifications
|
package org.thoughtcrime.securesms.notifications
|
||||||
|
|
||||||
import com.google.android.gms.tasks.Task
|
|
||||||
import com.google.android.gms.tasks.Tasks
|
import com.google.android.gms.tasks.Tasks
|
||||||
import com.google.firebase.iid.FirebaseInstanceId
|
import com.google.firebase.iid.FirebaseInstanceId
|
||||||
import com.google.firebase.iid.InstanceIdResult
|
|
||||||
import dagger.Lazy
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.MainScope
|
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.withContext
|
||||||
import org.session.libsignal.utilities.Log
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
private val TAG = FirebaseTokenFetcher::class.java.name
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class FirebaseTokenFetcher @Inject constructor(
|
class FirebaseTokenFetcher @Inject constructor(): TokenFetcher {
|
||||||
private val pushRegistry: Lazy<PushRegistry>,
|
override suspend fun fetch() = withContext(Dispatchers.IO) {
|
||||||
): TokenFetcher {
|
|
||||||
override fun fetch(): Job = MainScope().launch(Dispatchers.IO) {
|
|
||||||
FirebaseInstanceId.getInstance().instanceId
|
FirebaseInstanceId.getInstance().instanceId
|
||||||
.also(Tasks::await)
|
.also(Tasks::await)
|
||||||
.also { if (!isActive) return@launch } // don't 'complete' task if we were canceled
|
.takeIf { isActive } // don't 'complete' task if we were canceled
|
||||||
.process()
|
?.run { result?.token ?: throw exception!! }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Task<InstanceIdResult>.process() = when {
|
|
||||||
isSuccessful -> try {
|
|
||||||
result?.token?.let {
|
|
||||||
pushRegistry.get().refresh(it, force = true).get()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
onFail(e)
|
|
||||||
}
|
|
||||||
else -> exception?.let(::onFail)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onFail(e: Exception) = Log.e(TAG, "fetch failed", e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user