Browse Source

fix crash when there are 2 or more unifiedpush distributors (#5015)

`UnifiedPush.registerAppWithDialog` will show a dialog when there are 2
or more distributors, for that it needs an activity context but we
passed an application one. I think this is improved in a newer Unified
push library version, will upgrade soon. In the meantime this change
fixes the crash.

```
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:1314)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:421)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:149)
    at android.app.Dialog.show(Dialog.java:352)
    at org.unifiedpush.android.connector.UnifiedPush.registerAppWithDialog(UnifiedPush.kt:139)
    at org.unifiedpush.android.connector.UnifiedPush.registerAppWithDialog$default(UnifiedPush.kt:67)
    at com.keylesspalace.tusky.components.systemnotifications.NotificationService.setupPushNotificationsForAccount(NotificationService.kt:775)
    at com.keylesspalace.tusky.components.systemnotifications.NotificationService.access$setupPushNotificationsForAccount(NotificationService.kt:76)
    at com.keylesspalace.tusky.components.systemnotifications.NotificationService$setupPushNotificationsForAccount$1.invokeSuspend(Unknown Source:15)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
    at android.os.Handler.handleCallback(Handler.java:942)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7932)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:942)
```
pull/5030/head
Konrad Pozniak 12 months ago committed by GitHub
parent
commit
706a7f9c8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      app/src/main/java/com/keylesspalace/tusky/MainActivity.kt
  2. 14
      app/src/main/java/com/keylesspalace/tusky/MainViewModel.kt
  3. 21
      app/src/main/java/com/keylesspalace/tusky/components/systemnotifications/NotificationService.kt

4
app/src/main/java/com/keylesspalace/tusky/MainActivity.kt

@ -184,7 +184,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
private val requestNotificationPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
viewModel.setupNotifications()
viewModel.setupNotifications(this)
}
}
@ -213,6 +213,8 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED
) {
requestNotificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
} else {
viewModel.setupNotifications(this)
}
if (explodeAnimationWasRequested()) {

14
app/src/main/java/com/keylesspalace/tusky/MainViewModel.kt

@ -27,7 +27,6 @@ import com.keylesspalace.tusky.appstore.NewNotificationsEvent
import com.keylesspalace.tusky.appstore.NotificationsLoadingEvent
import com.keylesspalace.tusky.components.systemnotifications.NotificationService
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.db.entity.AccountEntity
import com.keylesspalace.tusky.entity.Emoji
import com.keylesspalace.tusky.entity.Notification
import com.keylesspalace.tusky.entity.Status
@ -97,8 +96,6 @@ class MainViewModel @Inject constructor(
accountManager.updateAccount(activeAccount, userInfo)
shareShortcutHelper.updateShortcuts()
setupNotifications(activeAccount)
},
{ throwable ->
Log.e(TAG, "Failed to fetch user info.", throwable)
@ -161,19 +158,16 @@ class MainViewModel @Inject constructor(
}
}
fun setupNotifications(account: AccountEntity? = null) {
fun setupNotifications(activity: MainActivity) {
// TODO this is only called on full app (re) start; so changes in-between (push distributor uninstalled/subscription changed, or
// notifications fully disabled) will get unnoticed; and also an app restart cannot be easily triggered by the user.
if (account != null) {
// TODO it's quite odd to separate channel creation (for an account) from the "is enabled by channels" question below
notificationService.createNotificationChannelsForAccount(account)
}
// TODO it's quite odd to separate channel creation (for an account) from the "is enabled by channels" question below
notificationService.createNotificationChannelsForAccount(activeAccount)
if (notificationService.areNotificationsEnabledBySystem()) {
viewModelScope.launch {
notificationService.setupNotifications(account)
notificationService.setupNotifications(activity)
}
} else {
viewModelScope.launch {

21
app/src/main/java/com/keylesspalace/tusky/components/systemnotifications/NotificationService.kt

@ -1,6 +1,7 @@
package com.keylesspalace.tusky.components.systemnotifications
import android.Manifest
import android.app.Activity
import android.app.NotificationChannel
import android.app.NotificationChannelGroup
import android.app.NotificationManager
@ -111,11 +112,11 @@ class NotificationService @Inject constructor(
}
}
suspend fun setupNotifications(account: AccountEntity?) {
suspend fun setupNotifications(activity: Activity) {
resetPushWhenDistributorIsMissing()
if (arePushNotificationsAvailable()) {
setupPushNotifications(account)
setupPushNotifications(activity)
}
// At least as a fallback and otherwise as main source when there are no push distributors installed:
@ -731,20 +732,14 @@ class NotificationService @Inject constructor(
fun arePushNotificationsAvailable(): Boolean =
UnifiedPush.getDistributors(context).isNotEmpty()
private suspend fun setupPushNotifications(account: AccountEntity?) {
val relevantAccounts: List<AccountEntity> = if (account != null) {
listOf(account)
} else {
accountManager.accounts
}
relevantAccounts.forEach {
private suspend fun setupPushNotifications(activity: Activity) {
accountManager.accounts.forEach {
val notificationGroupEnabled = Build.VERSION.SDK_INT < 28 ||
notificationManager.getNotificationChannelGroup(it.identifier)?.isBlocked == false
val shouldEnable = it.notificationsEnabled && notificationGroupEnabled
if (shouldEnable) {
setupPushNotificationsForAccount(it)
setupPushNotificationsForAccount(activity, it)
Log.d(TAG, "Enabled push notifications for account ${it.id}.")
} else {
disablePushNotificationsForAccount(it)
@ -753,7 +748,7 @@ class NotificationService @Inject constructor(
}
}
private suspend fun setupPushNotificationsForAccount(account: AccountEntity) {
private suspend fun setupPushNotificationsForAccount(activity: Activity, account: AccountEntity) {
val currentSubscription = getActiveSubscription(account)
if (currentSubscription != null) {
@ -772,7 +767,7 @@ class NotificationService @Inject constructor(
// make sure this is done in any inconsistent case (is not too often and doesn't hurt).
unregisterPushEndpoint(account)
UnifiedPush.registerAppWithDialog(context, account.id.toString(), features = arrayListOf(UnifiedPush.FEATURE_BYTES_MESSAGE))
UnifiedPush.registerAppWithDialog(activity, account.id.toString(), features = arrayListOf(UnifiedPush.FEATURE_BYTES_MESSAGE))
// Will lead to call of registerPushEndpoint()
}
}

Loading…
Cancel
Save