Merge branch 'unifiedpush' into sc
Change-Id: I0d19e4032b0f31cc1dee404cb383046d04a3259e
This commit is contained in:
commit
4918b7e7bf
|
@ -44,6 +44,8 @@ allprojects {
|
||||||
includeGroupByRegex 'com\\.github\\.chrisbanes'
|
includeGroupByRegex 'com\\.github\\.chrisbanes'
|
||||||
// PFLockScreen-Android
|
// PFLockScreen-Android
|
||||||
includeGroupByRegex 'com\\.github\\.vector-im'
|
includeGroupByRegex 'com\\.github\\.vector-im'
|
||||||
|
// UnifiedPush
|
||||||
|
includeGroupByRegex 'com\\.github\\.UnifiedPush'
|
||||||
|
|
||||||
// Chat effects
|
// Chat effects
|
||||||
includeGroupByRegex 'com\\.github\\.jetradarmobile'
|
includeGroupByRegex 'com\\.github\\.jetradarmobile'
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Use UnifiedPush and allows user to have push without FCM.
|
|
@ -311,6 +311,10 @@ android {
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding true
|
viewBinding true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packagingOptions {
|
||||||
|
exclude 'META-INF/lib_release.kotlin_module'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -344,6 +348,7 @@ dependencies {
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||||
|
|
||||||
|
@ -360,6 +365,7 @@ dependencies {
|
||||||
implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.9.0"
|
implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.9.0"
|
||||||
|
|
||||||
implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
|
implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
|
||||||
|
implementation "com.squareup.moshi:moshi-kotlin:$moshi_version"
|
||||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
|
||||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
|
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"
|
||||||
|
@ -455,8 +461,10 @@ dependencies {
|
||||||
implementation "com.google.dagger:dagger:$daggerVersion"
|
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||||
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
|
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||||
|
|
||||||
// gplay flavor only
|
// UnifiedPush
|
||||||
gplayImplementation('com.google.firebase:firebase-messaging:22.0.0') {
|
implementation 'com.github.UnifiedPush:android-connector:1.2.0'
|
||||||
|
// UnifiedPush gplay flavor only
|
||||||
|
gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:1.1.0') {
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
exclude group: 'com.google.firebase', module: 'firebase-core'
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-analytics'
|
exclude group: 'com.google.firebase', module: 'firebase-analytics'
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
|
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="im.vector.app">
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
|
||||||
<!--
|
|
||||||
Required for long polling account synchronisation in background.
|
|
||||||
If not present ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS intent action won't work
|
|
||||||
-->
|
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
|
||||||
|
|
||||||
<application>
|
|
||||||
|
|
||||||
<receiver android:name=".fdroid.receiver.OnApplicationUpgradeOrRebootReceiver">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
|
|
||||||
<receiver
|
|
||||||
android:name=".fdroid.receiver.AlarmSyncBroadcastReceiver"
|
|
||||||
android:enabled="true"
|
|
||||||
android:exported="false" />
|
|
||||||
|
|
||||||
</application>
|
|
||||||
|
|
||||||
</manifest>
|
|
|
@ -17,56 +17,13 @@
|
||||||
|
|
||||||
package im.vector.app.push.fcm
|
package im.vector.app.push.fcm
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
|
||||||
import im.vector.app.core.pushers.PushersManager
|
|
||||||
import im.vector.app.fdroid.BackgroundSyncStarter
|
|
||||||
import im.vector.app.fdroid.receiver.AlarmSyncBroadcastReceiver
|
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class has an alter ego in the gplay variant.
|
* This class has an alter ego in the gplay variant.
|
||||||
*/
|
*/
|
||||||
object FcmHelper {
|
object FcmHelper {
|
||||||
|
fun isPlayServicesAvailable(context: Context): Boolean {
|
||||||
fun isPushSupported(): Boolean = false
|
return false
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the FCM registration token.
|
|
||||||
*
|
|
||||||
* @return the FCM token or null if not received from FCM
|
|
||||||
*/
|
|
||||||
fun getFcmToken(context: Context): String? {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store FCM token to the SharedPrefs
|
|
||||||
*
|
|
||||||
* @param context android context
|
|
||||||
* @param token the token to store
|
|
||||||
*/
|
|
||||||
fun storeFcmToken(context: Context, token: String?) {
|
|
||||||
// No op
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* onNewToken may not be called on application upgrade, so ensure my shared pref is set
|
|
||||||
*
|
|
||||||
* @param activity the first launch Activity
|
|
||||||
*/
|
|
||||||
fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) {
|
|
||||||
// No op
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onEnterForeground(context: Context, activeSessionHolder: ActiveSessionHolder) {
|
|
||||||
// try to stop all regardless of background mode
|
|
||||||
activeSessionHolder.getSafeActiveSession()?.stopAnyBackgroundSync()
|
|
||||||
AlarmSyncBroadcastReceiver.cancelAlarm(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onEnterBackground(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) {
|
|
||||||
BackgroundSyncStarter.start(context, vectorPreferences, activeSessionHolder)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,21 +16,28 @@
|
||||||
package im.vector.app.push.fcm
|
package im.vector.app.push.fcm
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import im.vector.app.fdroid.features.settings.troubleshoot.TestAutoStartBoot
|
import im.vector.app.core.pushers.UPHelper
|
||||||
import im.vector.app.fdroid.features.settings.troubleshoot.TestBackgroundRestrictions
|
import im.vector.app.features.settings.troubleshoot.TestAutoStartBoot
|
||||||
import im.vector.app.fdroid.features.settings.troubleshoot.TestBatteryOptimization
|
import im.vector.app.features.settings.troubleshoot.TestBackgroundRestrictions
|
||||||
|
import im.vector.app.features.settings.troubleshoot.TestBatteryOptimization
|
||||||
import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager
|
import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager
|
||||||
import im.vector.app.features.settings.troubleshoot.TestAccountSettings
|
import im.vector.app.features.settings.troubleshoot.TestAccountSettings
|
||||||
import im.vector.app.features.settings.troubleshoot.TestDeviceSettings
|
import im.vector.app.features.settings.troubleshoot.TestDeviceSettings
|
||||||
|
import im.vector.app.features.settings.troubleshoot.TestNewEndpoint
|
||||||
import im.vector.app.features.settings.troubleshoot.TestNotification
|
import im.vector.app.features.settings.troubleshoot.TestNotification
|
||||||
|
import im.vector.app.features.settings.troubleshoot.TestPushFromPushGateway
|
||||||
import im.vector.app.features.settings.troubleshoot.TestPushRulesSettings
|
import im.vector.app.features.settings.troubleshoot.TestPushRulesSettings
|
||||||
import im.vector.app.features.settings.troubleshoot.TestSystemSettings
|
import im.vector.app.features.settings.troubleshoot.TestSystemSettings
|
||||||
|
import im.vector.app.features.settings.troubleshoot.TestTokenRegistration
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class NotificationTroubleshootTestManagerFactory @Inject constructor(
|
class NotificationTroubleshootTestManagerFactory @Inject constructor(
|
||||||
private val testSystemSettings: TestSystemSettings,
|
private val testSystemSettings: TestSystemSettings,
|
||||||
private val testAccountSettings: TestAccountSettings,
|
private val testAccountSettings: TestAccountSettings,
|
||||||
private val testDeviceSettings: TestDeviceSettings,
|
private val testDeviceSettings: TestDeviceSettings,
|
||||||
|
private val testNewEndpoint: TestNewEndpoint,
|
||||||
|
private val testTokenRegistration: TestTokenRegistration,
|
||||||
|
private val testPushFromPushGateway: TestPushFromPushGateway,
|
||||||
private val testPushRulesSettings: TestPushRulesSettings,
|
private val testPushRulesSettings: TestPushRulesSettings,
|
||||||
private val testAutoStartBoot: TestAutoStartBoot,
|
private val testAutoStartBoot: TestAutoStartBoot,
|
||||||
private val testBackgroundRestrictions: TestBackgroundRestrictions,
|
private val testBackgroundRestrictions: TestBackgroundRestrictions,
|
||||||
|
@ -44,9 +51,15 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(
|
||||||
mgr.addTest(testAccountSettings)
|
mgr.addTest(testAccountSettings)
|
||||||
mgr.addTest(testDeviceSettings)
|
mgr.addTest(testDeviceSettings)
|
||||||
mgr.addTest(testPushRulesSettings)
|
mgr.addTest(testPushRulesSettings)
|
||||||
mgr.addTest(testAutoStartBoot)
|
if (UPHelper.distributorExists(fragment.requireContext())) {
|
||||||
mgr.addTest(testBackgroundRestrictions)
|
mgr.addTest(testNewEndpoint)
|
||||||
mgr.addTest(testBatteryOptimization)
|
mgr.addTest(testTokenRegistration)
|
||||||
|
mgr.addTest(testPushFromPushGateway)
|
||||||
|
} else {
|
||||||
|
mgr.addTest(testAutoStartBoot)
|
||||||
|
mgr.addTest(testBackgroundRestrictions)
|
||||||
|
mgr.addTest(testBatteryOptimization)
|
||||||
|
}
|
||||||
mgr.addTest(testNotification)
|
mgr.addTest(testNotification)
|
||||||
return mgr
|
return mgr
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,12 @@
|
||||||
package="im.vector.app">
|
package="im.vector.app">
|
||||||
|
|
||||||
<application>
|
<application>
|
||||||
|
<receiver android:enabled="true" android:name=".push.fcm.EmbeddedDistrib" android:exported="false">
|
||||||
<!-- Firebase components -->
|
|
||||||
<meta-data
|
|
||||||
android:name="firebase_analytics_collection_deactivated"
|
|
||||||
android:value="true" />
|
|
||||||
|
|
||||||
<service android:name=".gplay.push.fcm.VectorFirebaseMessagingService">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
<action android:name="org.unifiedpush.android.distributor.REGISTER"/>
|
||||||
|
<action android:name="org.unifiedpush.android.distributor.UNREGISTER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</receiver>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2018 New Vector Ltd
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package im.vector.app.gplay.features.settings.troubleshoot
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import com.google.firebase.messaging.FirebaseMessaging
|
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.resources.StringProvider
|
|
||||||
import im.vector.app.core.utils.startAddGoogleAccountIntent
|
|
||||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
|
||||||
import timber.log.Timber
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test that app can successfully retrieve a token via firebase
|
|
||||||
*/
|
|
||||||
class TestFirebaseToken @Inject constructor(private val context: AppCompatActivity,
|
|
||||||
private val stringProvider: StringProvider) : TroubleshootTest(R.string.settings_troubleshoot_test_fcm_title) {
|
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
|
||||||
status = TestStatus.RUNNING
|
|
||||||
try {
|
|
||||||
FirebaseMessaging.getInstance().token
|
|
||||||
.addOnCompleteListener(context) { task ->
|
|
||||||
if (!task.isSuccessful) {
|
|
||||||
// Can't find where this constant is (not documented -or deprecated in docs- and all obfuscated)
|
|
||||||
description = when (val errorMsg = task.exception?.localizedMessage ?: "Unknown") {
|
|
||||||
"SERVICE_NOT_AVAILABLE" -> {
|
|
||||||
stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed_service_not_available, errorMsg)
|
|
||||||
}
|
|
||||||
"TOO_MANY_REGISTRATIONS" -> {
|
|
||||||
stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed_too_many_registration, errorMsg)
|
|
||||||
}
|
|
||||||
"ACCOUNT_MISSING" -> {
|
|
||||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_fcm_failed_account_missing_quick_fix) {
|
|
||||||
override fun doFix() {
|
|
||||||
startAddGoogleAccountIntent(context, activityResultLauncher)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed_account_missing, errorMsg)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed, errorMsg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
status = TestStatus.FAILED
|
|
||||||
} else {
|
|
||||||
task.result?.let { token ->
|
|
||||||
val tok = token.take(8) + "********************"
|
|
||||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_fcm_success, tok)
|
|
||||||
Timber.e("Retrieved FCM token success [$tok].")
|
|
||||||
// Ensure it is well store in our local storage
|
|
||||||
FcmHelper.storeFcmToken(context, token)
|
|
||||||
}
|
|
||||||
status = TestStatus.SUCCESS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed, e.localizedMessage)
|
|
||||||
status = TestStatus.FAILED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package im.vector.app.push.fcm
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import org.unifiedpush.android.embedded_fcm_distributor.GetEndpointHandler
|
||||||
|
import org.unifiedpush.android.embedded_fcm_distributor.EmbeddedDistributorReceiver
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
val handlerFCM = object: GetEndpointHandler {
|
||||||
|
override fun getEndpoint(context: Context?, token: String, instance: String): String {
|
||||||
|
// Here token is the FCM Token, used by the gateway (sygnal)
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmbeddedDistrib: EmbeddedDistributorReceiver(handlerFCM)
|
|
@ -15,99 +15,21 @@
|
||||||
*/
|
*/
|
||||||
package im.vector.app.push.fcm
|
package im.vector.app.push.fcm
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.core.content.edit
|
|
||||||
import com.google.android.gms.common.ConnectionResult
|
import com.google.android.gms.common.ConnectionResult
|
||||||
import com.google.android.gms.common.GoogleApiAvailability
|
import com.google.android.gms.common.GoogleApiAvailability
|
||||||
import com.google.firebase.messaging.FirebaseMessaging
|
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
|
||||||
import im.vector.app.core.di.DefaultSharedPreferences
|
|
||||||
import im.vector.app.core.pushers.PushersManager
|
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class store the FCM token in SharedPrefs and ensure this token is retrieved.
|
* This class store the FCM token in SharedPrefs and ensure this token is retrieved.
|
||||||
* It has an alter ego in the fdroid variant.
|
* It has an alter ego in the fdroid variant.
|
||||||
*/
|
*/
|
||||||
object FcmHelper {
|
object FcmHelper {
|
||||||
private val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN"
|
|
||||||
|
|
||||||
fun isPushSupported(): Boolean = true
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the FCM registration token.
|
* Check the device to make sure it has the Google Play Services APK.
|
||||||
*
|
|
||||||
* @return the FCM token or null if not received from FCM
|
|
||||||
*/
|
*/
|
||||||
fun getFcmToken(context: Context): String? {
|
fun isPlayServicesAvailable(context: Context): Boolean {
|
||||||
return DefaultSharedPreferences.getInstance(context).getString(PREFS_KEY_FCM_TOKEN, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store FCM token to the SharedPrefs
|
|
||||||
* TODO Store in realm
|
|
||||||
*
|
|
||||||
* @param context android context
|
|
||||||
* @param token the token to store
|
|
||||||
*/
|
|
||||||
fun storeFcmToken(context: Context,
|
|
||||||
token: String?) {
|
|
||||||
DefaultSharedPreferences.getInstance(context).edit {
|
|
||||||
putString(PREFS_KEY_FCM_TOKEN, token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* onNewToken may not be called on application upgrade, so ensure my shared pref is set
|
|
||||||
*
|
|
||||||
* @param activity the first launch Activity
|
|
||||||
*/
|
|
||||||
fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) {
|
|
||||||
// if (TextUtils.isEmpty(getFcmToken(activity))) {
|
|
||||||
// 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features'
|
|
||||||
if (checkPlayServices(activity)) {
|
|
||||||
try {
|
|
||||||
FirebaseMessaging.getInstance().token
|
|
||||||
.addOnSuccessListener { token ->
|
|
||||||
storeFcmToken(activity, token)
|
|
||||||
if (registerPusher) {
|
|
||||||
pushersManager.registerPusherWithFcmKey(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.addOnFailureListener { e ->
|
|
||||||
Timber.e(e, "## ensureFcmTokenIsRetrieved() : failed")
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Timber.e(e, "## ensureFcmTokenIsRetrieved() : failed")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Toast.makeText(activity, R.string.no_valid_google_play_services_apk, Toast.LENGTH_SHORT).show()
|
|
||||||
Timber.e("No valid Google Play Services found. Cannot use FCM.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the device to make sure it has the Google Play Services APK. If
|
|
||||||
* it doesn't, display a dialog that allows users to download the APK from
|
|
||||||
* the Google Play Store or enable it in the device's system settings.
|
|
||||||
*/
|
|
||||||
private fun checkPlayServices(activity: Activity): Boolean {
|
|
||||||
val apiAvailability = GoogleApiAvailability.getInstance()
|
val apiAvailability = GoogleApiAvailability.getInstance()
|
||||||
val resultCode = apiAvailability.isGooglePlayServicesAvailable(activity)
|
val resultCode = apiAvailability.isGooglePlayServicesAvailable(context)
|
||||||
return resultCode == ConnectionResult.SUCCESS
|
return resultCode == ConnectionResult.SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
fun onEnterForeground(context: Context, activeSessionHolder: ActiveSessionHolder) {
|
|
||||||
// No op
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
fun onEnterBackground(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) {
|
|
||||||
// TODO FCM fallback
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,27 +16,34 @@
|
||||||
package im.vector.app.push.fcm
|
package im.vector.app.push.fcm
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import im.vector.app.core.pushers.UPHelper
|
||||||
import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager
|
import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager
|
||||||
import im.vector.app.features.settings.troubleshoot.TestAccountSettings
|
import im.vector.app.features.settings.troubleshoot.TestAccountSettings
|
||||||
|
import im.vector.app.features.settings.troubleshoot.TestAutoStartBoot
|
||||||
|
import im.vector.app.features.settings.troubleshoot.TestBackgroundRestrictions
|
||||||
|
import im.vector.app.features.settings.troubleshoot.TestBatteryOptimization
|
||||||
import im.vector.app.features.settings.troubleshoot.TestDeviceSettings
|
import im.vector.app.features.settings.troubleshoot.TestDeviceSettings
|
||||||
import im.vector.app.features.settings.troubleshoot.TestNotification
|
import im.vector.app.features.settings.troubleshoot.TestNotification
|
||||||
import im.vector.app.features.settings.troubleshoot.TestPushRulesSettings
|
import im.vector.app.features.settings.troubleshoot.TestPushRulesSettings
|
||||||
import im.vector.app.features.settings.troubleshoot.TestSystemSettings
|
import im.vector.app.features.settings.troubleshoot.TestSystemSettings
|
||||||
import im.vector.app.gplay.features.settings.troubleshoot.TestFirebaseToken
|
import im.vector.app.features.settings.troubleshoot.TestNewEndpoint
|
||||||
import im.vector.app.gplay.features.settings.troubleshoot.TestPlayServices
|
import im.vector.app.gplay.features.settings.troubleshoot.TestPlayServices
|
||||||
import im.vector.app.gplay.features.settings.troubleshoot.TestPushFromPushGateway
|
import im.vector.app.features.settings.troubleshoot.TestPushFromPushGateway
|
||||||
import im.vector.app.gplay.features.settings.troubleshoot.TestTokenRegistration
|
import im.vector.app.features.settings.troubleshoot.TestTokenRegistration
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class NotificationTroubleshootTestManagerFactory @Inject constructor(
|
class NotificationTroubleshootTestManagerFactory @Inject constructor(
|
||||||
private val testSystemSettings: TestSystemSettings,
|
private val testSystemSettings: TestSystemSettings,
|
||||||
private val testAccountSettings: TestAccountSettings,
|
private val testAccountSettings: TestAccountSettings,
|
||||||
private val testDeviceSettings: TestDeviceSettings,
|
private val testDeviceSettings: TestDeviceSettings,
|
||||||
private val testBingRulesSettings: TestPushRulesSettings,
|
|
||||||
private val testPlayServices: TestPlayServices,
|
private val testPlayServices: TestPlayServices,
|
||||||
private val testFirebaseToken: TestFirebaseToken,
|
private val testNewEndpoint: TestNewEndpoint,
|
||||||
private val testTokenRegistration: TestTokenRegistration,
|
private val testTokenRegistration: TestTokenRegistration,
|
||||||
private val testPushFromPushGateway: TestPushFromPushGateway,
|
private val testPushFromPushGateway: TestPushFromPushGateway,
|
||||||
|
private val testPushRulesSettings: TestPushRulesSettings,
|
||||||
|
private val testAutoStartBoot: TestAutoStartBoot,
|
||||||
|
private val testBackgroundRestrictions: TestBackgroundRestrictions,
|
||||||
|
private val testBatteryOptimization: TestBatteryOptimization,
|
||||||
private val testNotification: TestNotification
|
private val testNotification: TestNotification
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -45,11 +52,17 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(
|
||||||
mgr.addTest(testSystemSettings)
|
mgr.addTest(testSystemSettings)
|
||||||
mgr.addTest(testAccountSettings)
|
mgr.addTest(testAccountSettings)
|
||||||
mgr.addTest(testDeviceSettings)
|
mgr.addTest(testDeviceSettings)
|
||||||
mgr.addTest(testBingRulesSettings)
|
mgr.addTest(testPushRulesSettings)
|
||||||
mgr.addTest(testPlayServices)
|
if (UPHelper.distributorExists(fragment.requireContext())) {
|
||||||
mgr.addTest(testFirebaseToken)
|
mgr.addTest(testPlayServices)
|
||||||
mgr.addTest(testTokenRegistration)
|
mgr.addTest(testNewEndpoint)
|
||||||
mgr.addTest(testPushFromPushGateway)
|
mgr.addTest(testTokenRegistration)
|
||||||
|
mgr.addTest(testPushFromPushGateway)
|
||||||
|
} else {
|
||||||
|
mgr.addTest(testAutoStartBoot)
|
||||||
|
mgr.addTest(testBackgroundRestrictions)
|
||||||
|
mgr.addTest(testBatteryOptimization)
|
||||||
|
}
|
||||||
mgr.addTest(testNotification)
|
mgr.addTest(testNotification)
|
||||||
return mgr
|
return mgr
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,14 @@
|
||||||
android:name="android.permission.WRITE_CALENDAR"
|
android:name="android.permission.WRITE_CALENDAR"
|
||||||
tools:node="remove" />
|
tools:node="remove" />
|
||||||
|
|
||||||
|
<!-- if the user don't have FCM or any unifiedpush distributor -->
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
<!--
|
||||||
|
Required for long polling account synchronisation in background.
|
||||||
|
If not present ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS intent action won't work
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
|
|
||||||
<!-- Jitsi SDK is now API23+ -->
|
<!-- Jitsi SDK is now API23+ -->
|
||||||
<uses-sdk tools:overrideLibrary="org.jitsi.meet.sdk,com.oney.WebRTCModule,com.learnium.RNDeviceInfo,com.reactnativecommunity.asyncstorage,com.ocetnik.timer,com.calendarevents,com.reactnativecommunity.netinfo,com.kevinresol.react_native_default_preference,com.rnimmersive,com.corbt.keepawake,com.BV.LinearGradient,com.horcrux.svg" />
|
<uses-sdk tools:overrideLibrary="org.jitsi.meet.sdk,com.oney.WebRTCModule,com.learnium.RNDeviceInfo,com.reactnativecommunity.asyncstorage,com.ocetnik.timer,com.calendarevents,com.reactnativecommunity.netinfo,com.kevinresol.react_native_default_preference,com.rnimmersive,com.corbt.keepawake,com.BV.LinearGradient,com.horcrux.svg" />
|
||||||
|
|
||||||
|
@ -386,6 +394,30 @@
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/sdk_provider_paths" />
|
android:resource="@xml/sdk_provider_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<receiver android:exported="true" android:enabled="true" android:name=".core.pushers.VectorMessagingReceiver">
|
||||||
|
<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"/>
|
||||||
|
<action android:name="org.unifiedpush.android.connector.REGISTRATION_REFUSED"/>
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<!-- For the fallback with sync loop if the user don't have FCM or a UnifiedPush Distributor -->
|
||||||
|
<receiver android:name=".core.receiver.OnApplicationUpgradeOrRebootReceiver">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".core.receiver.AlarmSyncBroadcastReceiver"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -59,7 +59,7 @@ import im.vector.app.features.settings.VectorLocale
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import im.vector.app.features.version.VersionProvider
|
import im.vector.app.features.version.VersionProvider
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
import im.vector.app.core.pushers.StateHelper
|
||||||
import org.jitsi.meet.sdk.log.JitsiMeetDefaultLogHandler
|
import org.jitsi.meet.sdk.log.JitsiMeetDefaultLogHandler
|
||||||
import org.matrix.android.sdk.api.Matrix
|
import org.matrix.android.sdk.api.Matrix
|
||||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||||
|
@ -171,7 +171,7 @@ class VectorApplication :
|
||||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||||
fun entersForeground() {
|
fun entersForeground() {
|
||||||
Timber.i("App entered foreground")
|
Timber.i("App entered foreground")
|
||||||
FcmHelper.onEnterForeground(appContext, activeSessionHolder)
|
StateHelper.onEnterForeground(appContext, activeSessionHolder)
|
||||||
activeSessionHolder.getSafeActiveSession()?.also {
|
activeSessionHolder.getSafeActiveSession()?.also {
|
||||||
it.stopAnyBackgroundSync()
|
it.stopAnyBackgroundSync()
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ class VectorApplication :
|
||||||
fun entersBackground() {
|
fun entersBackground() {
|
||||||
Timber.i("App entered background") // call persistInfo
|
Timber.i("App entered background") // call persistInfo
|
||||||
notificationDrawerManager.persistInfo()
|
notificationDrawerManager.persistInfo()
|
||||||
FcmHelper.onEnterBackground(appContext, vectorPreferences, activeSessionHolder)
|
StateHelper.onEnterBackground(appContext, vectorPreferences, activeSessionHolder)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
ProcessLifecycleOwner.get().lifecycle.addObserver(appStateHandler)
|
ProcessLifecycleOwner.get().lifecycle.addObserver(appStateHandler)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.app.core.pushers
|
package im.vector.app.core.pushers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.resources.AppNameProvider
|
import im.vector.app.core.resources.AppNameProvider
|
||||||
|
@ -33,37 +34,45 @@ class PushersManager @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val appNameProvider: AppNameProvider
|
private val appNameProvider: AppNameProvider
|
||||||
) {
|
) {
|
||||||
suspend fun testPush(pushKey: String) {
|
suspend fun testPush(context: Context) {
|
||||||
val currentSession = activeSessionHolder.getActiveSession()
|
val currentSession = activeSessionHolder.getActiveSession()
|
||||||
|
|
||||||
currentSession.testPush(
|
currentSession.testPush(
|
||||||
stringProvider.getString(R.string.pusher_http_url),
|
UPHelper.getPushGateway(context)!!,
|
||||||
stringProvider.getString(R.string.pusher_app_id),
|
getPusherAppId(context),
|
||||||
pushKey,
|
UPHelper.getUpEndpoint(context)!!,
|
||||||
TEST_EVENT_ID
|
TEST_EVENT_ID
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun registerPusherWithFcmKey(pushKey: String): UUID {
|
fun registerPusher(context: Context, pushKey: String, gateway: String): UUID {
|
||||||
val currentSession = activeSessionHolder.getActiveSession()
|
val currentSession = activeSessionHolder.getActiveSession()
|
||||||
val profileTag = DEFAULT_PUSHER_FILE_TAG + "_" + abs(currentSession.myUserId.hashCode())
|
val profileTag = DEFAULT_PUSHER_FILE_TAG + "_" + abs(currentSession.myUserId.hashCode())
|
||||||
|
|
||||||
return currentSession.addHttpPusher(
|
return currentSession.addHttpPusher(
|
||||||
pushKey,
|
pushKey, // this is the UnifiedPush endpoint
|
||||||
stringProvider.getString(R.string.pusher_app_id),
|
getPusherAppId(context),
|
||||||
profileTag,
|
profileTag,
|
||||||
localeProvider.current().language,
|
localeProvider.current().language,
|
||||||
appNameProvider.getAppName(),
|
appNameProvider.getAppName(),
|
||||||
currentSession.sessionParams.deviceId ?: "MOBILE",
|
currentSession.sessionParams.deviceId ?: "MOBILE",
|
||||||
stringProvider.getString(R.string.pusher_http_url),
|
gateway,
|
||||||
append = false,
|
append = false,
|
||||||
withEventIdOnly = true
|
withEventIdOnly = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun unregisterPusher(pushKey: String) {
|
suspend fun unregisterPusher(context: Context, pushKey: String) {
|
||||||
val currentSession = activeSessionHolder.getSafeActiveSession() ?: return
|
val currentSession = activeSessionHolder.getSafeActiveSession() ?: return
|
||||||
currentSession.removeHttpPusher(pushKey, stringProvider.getString(R.string.pusher_app_id))
|
currentSession.removeHttpPusher(pushKey, getPusherAppId(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPusherAppId(context: Context) : String {
|
||||||
|
return if (UPHelper.isEmbeddedDistributor(context)) {
|
||||||
|
stringProvider.getString(R.string.pusher_app_id)
|
||||||
|
} else {
|
||||||
|
stringProvider.getString(R.string.up_pusher_app_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.core.pushers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
|
import im.vector.app.core.receiver.AlarmSyncBroadcastReceiver
|
||||||
|
import im.vector.app.core.receiver.BackgroundSyncStarter
|
||||||
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
|
||||||
|
object StateHelper {
|
||||||
|
fun onEnterForeground(context: Context, activeSessionHolder: ActiveSessionHolder) {
|
||||||
|
// try to stop all regardless of background mode
|
||||||
|
activeSessionHolder.getSafeActiveSession()?.stopAnyBackgroundSync()
|
||||||
|
AlarmSyncBroadcastReceiver.cancelAlarm(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onEnterBackground(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) {
|
||||||
|
BackgroundSyncStarter.start(context, vectorPreferences, activeSessionHolder)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package im.vector.app.core.pushers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.di.DefaultSharedPreferences
|
||||||
|
import im.vector.app.push.fcm.FcmHelper
|
||||||
|
import org.unifiedpush.android.connector.Registration
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class store the UnifiedPush Endpoint in SharedPrefs and ensure this token is retrieved.
|
||||||
|
* It has an alter ego in the fdroid variant.
|
||||||
|
*/
|
||||||
|
object UPHelper {
|
||||||
|
private const val PREFS_UP_ENDPOINT = "UP_ENDPOINT"
|
||||||
|
private const val PREFS_PUSH_GATEWAY = "PUSH_GATEWAY"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the UnifiedPush Endpoint.
|
||||||
|
*
|
||||||
|
* @return the UnifiedPush Endpoint or null if not received
|
||||||
|
*/
|
||||||
|
fun getUpEndpoint(context: Context): String? {
|
||||||
|
return DefaultSharedPreferences.getInstance(context).getString(PREFS_UP_ENDPOINT, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store UnifiedPush Endpoint to the SharedPrefs
|
||||||
|
* TODO Store in realm
|
||||||
|
*
|
||||||
|
* @param context android context
|
||||||
|
* @param endpoint the endpoint to store
|
||||||
|
*/
|
||||||
|
fun storeUpEndpoint(context: Context,
|
||||||
|
endpoint: String?) {
|
||||||
|
DefaultSharedPreferences.getInstance(context).edit {
|
||||||
|
putString(PREFS_UP_ENDPOINT, endpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the Push Gateway.
|
||||||
|
*
|
||||||
|
* @return the Push Gateway or null if not defined
|
||||||
|
*/
|
||||||
|
fun getPushGateway(context: Context): String? {
|
||||||
|
return DefaultSharedPreferences.getInstance(context).getString(PREFS_PUSH_GATEWAY, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store Push Gateway to the SharedPrefs
|
||||||
|
* TODO Store in realm
|
||||||
|
*
|
||||||
|
* @param context android context
|
||||||
|
* @param gateway the push gateway to store
|
||||||
|
*/
|
||||||
|
fun storePushGateway(context: Context,
|
||||||
|
gateway: String?) {
|
||||||
|
DefaultSharedPreferences.getInstance(context).edit {
|
||||||
|
putString(PREFS_PUSH_GATEWAY, gateway)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerUnifiedPush(context: Context) {
|
||||||
|
val up = Registration()
|
||||||
|
if (up.getDistributor(context).isNotEmpty()) {
|
||||||
|
up.registerApp(context)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val distributors = up.getDistributors(context).toMutableList()
|
||||||
|
/**
|
||||||
|
* Check if it is the gplay flavour AND GServices are not available
|
||||||
|
*/
|
||||||
|
if (!FcmHelper.isPlayServicesAvailable(context)) {
|
||||||
|
distributors.remove(context.packageName)
|
||||||
|
}
|
||||||
|
when (distributors.size) {
|
||||||
|
0 -> {
|
||||||
|
/**
|
||||||
|
* Fallback with sync service
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
up.saveDistributor(context, distributors.first())
|
||||||
|
up.registerApp(context)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val builder: AlertDialog.Builder = MaterialAlertDialogBuilder(context)
|
||||||
|
builder.setTitle(context.getString(R.string.unifiedpush_getdistributors_dialog_title))
|
||||||
|
|
||||||
|
val distributorsArray = distributors.toTypedArray()
|
||||||
|
val distributorsNameArray = distributorsArray.map {
|
||||||
|
if (it == context.packageName) {
|
||||||
|
context.getString(R.string.unifiedpush_getdistributors_dialog_fcm_fallback)
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
val ai = context.packageManager.getApplicationInfo(it, 0)
|
||||||
|
context.packageManager.getApplicationLabel(ai)
|
||||||
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
|
it
|
||||||
|
} as String
|
||||||
|
}
|
||||||
|
}.toTypedArray()
|
||||||
|
builder.setItems(distributorsNameArray) { _, which ->
|
||||||
|
val distributor = distributorsArray[which]
|
||||||
|
up.saveDistributor(context, distributor)
|
||||||
|
Timber.i("Saving distributor: $distributor")
|
||||||
|
up.registerApp(context)
|
||||||
|
}
|
||||||
|
val dialog: AlertDialog = builder.create()
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unregister(context: Context) {
|
||||||
|
val up = Registration()
|
||||||
|
up.unregisterApp(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun customOrDefaultGateway(context: Context, endpoint: String?): String {
|
||||||
|
// if we use the embedded distributor,
|
||||||
|
// register app_id type upfcm on sygnal
|
||||||
|
// the pushkey if FCM key
|
||||||
|
val up = Registration()
|
||||||
|
if (up.getDistributor(context) == context.packageName) {
|
||||||
|
return context.getString(R.string.pusher_http_url)
|
||||||
|
}
|
||||||
|
// else, unifiedpush, and pushkey is an endpoint
|
||||||
|
val default = context.getString(R.string.default_push_gateway_http_url)
|
||||||
|
endpoint?.let {
|
||||||
|
val uri = URI(it)
|
||||||
|
val custom = "${it.split(uri.rawPath)[0]}/_matrix/push/v1/notify"
|
||||||
|
Timber.i("Testing $custom")
|
||||||
|
/**
|
||||||
|
* TODO:
|
||||||
|
* if GET custom returns """{"unifiedpush":{"gateway":"matrix"}}"""
|
||||||
|
* return custom
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
return default
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasEndpoint(context: Context): Boolean {
|
||||||
|
getUpEndpoint(context)?.let {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun distributorExists(context: Context): Boolean {
|
||||||
|
val up = Registration()
|
||||||
|
return up.getDistributor(context).isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isEmbeddedDistributor(context: Context) : Boolean {
|
||||||
|
val up = Registration()
|
||||||
|
return up.getDistributor(context) == context.packageName
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,43 +17,61 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.app.gplay.push.fcm
|
package im.vector.app.core.pushers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService
|
import com.squareup.moshi.Json
|
||||||
import com.google.firebase.messaging.RemoteMessage
|
import com.squareup.moshi.JsonClass
|
||||||
|
import com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||||
import im.vector.app.BuildConfig
|
import im.vector.app.BuildConfig
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.extensions.vectorComponent
|
import im.vector.app.core.extensions.vectorComponent
|
||||||
import im.vector.app.core.network.WifiDetector
|
import im.vector.app.core.network.WifiDetector
|
||||||
import im.vector.app.core.pushers.PushersManager
|
|
||||||
import im.vector.app.features.badge.BadgeProxy
|
import im.vector.app.features.badge.BadgeProxy
|
||||||
import im.vector.app.features.notifications.NotifiableEventResolver
|
import im.vector.app.features.notifications.NotifiableEventResolver
|
||||||
import im.vector.app.features.notifications.NotifiableMessageEvent
|
|
||||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||||
import im.vector.app.features.notifications.NotificationUtils
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
import im.vector.app.features.notifications.SimpleNotifiableEvent
|
import im.vector.app.features.settings.BackgroundSyncMode
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.pushrules.Action
|
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.unifiedpush.android.connector.MessagingReceiver
|
||||||
|
import org.unifiedpush.android.connector.MessagingReceiverHandler
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class UnifiedPushMessage(
|
||||||
|
val notification: Notification
|
||||||
|
)
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class Notification(
|
||||||
|
@Json(name = "event_id") val eventId: String = "",
|
||||||
|
@Json(name = "room_id") val roomId: String = "",
|
||||||
|
var unread: Int = 0,
|
||||||
|
val counts: Counts = Counts()
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Counts(
|
||||||
|
val unread: Int = 0
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class extending FirebaseMessagingService.
|
* UnifiedPush handler.
|
||||||
*/
|
*/
|
||||||
class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
val upHandler = object: MessagingReceiverHandler {
|
||||||
|
|
||||||
private lateinit var notificationDrawerManager: NotificationDrawerManager
|
private lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||||
private lateinit var notifiableEventResolver: NotifiableEventResolver
|
private lateinit var notifiableEventResolver: NotifiableEventResolver
|
||||||
|
@ -69,9 +87,8 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
Handler(Looper.getMainLooper())
|
Handler(Looper.getMainLooper())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
fun initVar(context: Context) {
|
||||||
super.onCreate()
|
with(context.vectorComponent()) {
|
||||||
with(vectorComponent()) {
|
|
||||||
notificationDrawerManager = notificationDrawerManager()
|
notificationDrawerManager = notificationDrawerManager()
|
||||||
notifiableEventResolver = notifiableEventResolver()
|
notifiableEventResolver = notifiableEventResolver()
|
||||||
pusherManager = pusherManager()
|
pusherManager = pusherManager()
|
||||||
|
@ -85,17 +102,34 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
* Called when message is received.
|
* Called when message is received.
|
||||||
*
|
*
|
||||||
* @param message the message
|
* @param message the message
|
||||||
|
* @param instance connection, for multi-account
|
||||||
*/
|
*/
|
||||||
override fun onMessageReceived(message: RemoteMessage) {
|
override fun onMessage(context: Context?, message: String, instance: String) {
|
||||||
|
initVar(context!!)
|
||||||
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
||||||
Timber.d("## onMessageReceived() %s", message.data.toString())
|
Timber.d("## onMessageReceived() %s", message)
|
||||||
|
}
|
||||||
|
Timber.d("## onMessage() received")
|
||||||
|
|
||||||
|
val moshi: Moshi = Moshi.Builder()
|
||||||
|
.add(KotlinJsonAdapterFactory())
|
||||||
|
.build()
|
||||||
|
lateinit var notification: Notification
|
||||||
|
|
||||||
|
if (UPHelper.isEmbeddedDistributor(context)) {
|
||||||
|
notification = moshi.adapter(Notification::class.java)
|
||||||
|
.fromJson(message) ?: return
|
||||||
|
} else {
|
||||||
|
val data = moshi.adapter(UnifiedPushMessage::class.java)
|
||||||
|
.fromJson(message) ?: return
|
||||||
|
notification = data.notification
|
||||||
|
notification.unread = notification.counts.unread
|
||||||
}
|
}
|
||||||
Timber.d("## onMessageReceived() from FCM with priority %s", message.priority)
|
|
||||||
|
|
||||||
// Diagnostic Push
|
// Diagnostic Push
|
||||||
if (message.data["event_id"] == PushersManager.TEST_EVENT_ID) {
|
if (notification.eventId == PushersManager.TEST_EVENT_ID) {
|
||||||
val intent = Intent(NotificationUtils.PUSH_ACTION)
|
val intent = Intent(NotificationUtils.PUSH_ACTION)
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +143,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
// we are in foreground, let the sync do the things?
|
// we are in foreground, let the sync do the things?
|
||||||
Timber.d("PUSH received in a foreground state, ignore")
|
Timber.d("PUSH received in a foreground state, ignore")
|
||||||
} else {
|
} else {
|
||||||
onMessageReceivedInternal(message.data)
|
onMessageReceivedInternal(context, notification)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,59 +154,71 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
* when the InstanceID token is initially generated, so this is where
|
* when the InstanceID token is initially generated, so this is where
|
||||||
* you retrieve the token.
|
* you retrieve the token.
|
||||||
*/
|
*/
|
||||||
override fun onNewToken(refreshedToken: String) {
|
override fun onNewEndpoint(context: Context?, endpoint: String, instance: String) {
|
||||||
Timber.i("onNewToken: FCM Token has been updated")
|
initVar(context!!)
|
||||||
FcmHelper.storeFcmToken(this, refreshedToken)
|
Timber.i("onNewEndpoint: adding $endpoint")
|
||||||
if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
|
if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
|
||||||
pusherManager.registerPusherWithFcmKey(refreshedToken)
|
val gateway = UPHelper.customOrDefaultGateway(context, endpoint)
|
||||||
|
if (UPHelper.getUpEndpoint(context) != endpoint
|
||||||
|
|| UPHelper.getPushGateway(context) != gateway) {
|
||||||
|
UPHelper.storePushGateway(context, gateway)
|
||||||
|
UPHelper.storeUpEndpoint(context, endpoint)
|
||||||
|
pusherManager.registerPusher(context, endpoint, gateway)
|
||||||
|
} else {
|
||||||
|
Timber.i("onNewEndpoint: skipped")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED
|
||||||
|
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun onRegistrationFailed(context: Context?, instance: String) {
|
||||||
* Called when the FCM server deletes pending messages. This may be due to:
|
Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show()
|
||||||
* - Too many messages stored on the FCM server.
|
}
|
||||||
* This can occur when an app's servers send a bunch of non-collapsible messages to FCM servers while the device is offline.
|
|
||||||
* - The device hasn't connected in a long time and the app server has recently (within the last 4 weeks)
|
override fun onRegistrationRefused(context: Context?, instance: String) {
|
||||||
* sent a message to the app on that device.
|
Toast.makeText(context, "Push service registration refused by server", Toast.LENGTH_LONG).show()
|
||||||
*
|
}
|
||||||
* It is recommended that the app do a full sync with the app server after receiving this call.
|
|
||||||
*/
|
override fun onUnregistered(context: Context?, instance: String) {
|
||||||
override fun onDeletedMessages() {
|
Timber.d("Unifiedpush: Unregistered")
|
||||||
Timber.v("## onDeletedMessages()")
|
initVar(context!!)
|
||||||
|
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY
|
||||||
|
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
||||||
|
runBlocking {
|
||||||
|
try {
|
||||||
|
pusherManager.unregisterPusher(context, UPHelper.getUpEndpoint(context)!!)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.d("Probably unregistering a non existant pusher")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal receive method
|
* Internal receive method
|
||||||
*
|
*
|
||||||
* @param data Data map containing message data as key/value pairs.
|
* @param notification Notification containing message data.
|
||||||
* For Set of keys use data.keySet().
|
|
||||||
*/
|
*/
|
||||||
private fun onMessageReceivedInternal(data: Map<String, String>) {
|
private fun onMessageReceivedInternal(context: Context, notification: Notification) {
|
||||||
try {
|
try {
|
||||||
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
||||||
Timber.d("## onMessageReceivedInternal() : $data")
|
Timber.d("## onMessageReceivedInternal() : $notification")
|
||||||
} else {
|
|
||||||
Timber.d("## onMessageReceivedInternal() : $data")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the badge counter
|
// update the badge counter
|
||||||
val unreadCount = data["unread"]?.let { Integer.parseInt(it) } ?: 0
|
BadgeProxy.updateBadgeCount(context, notification.unread)
|
||||||
BadgeProxy.updateBadgeCount(applicationContext, unreadCount)
|
|
||||||
|
|
||||||
val session = activeSessionHolder.getSafeActiveSession()
|
val session = activeSessionHolder.getSafeActiveSession()
|
||||||
|
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
Timber.w("## Can't sync from push, no current session")
|
Timber.w("## Can't sync from push, no current session")
|
||||||
} else {
|
} else {
|
||||||
val eventId = data["event_id"]
|
if (isEventAlreadyKnown(notification.eventId, notification.roomId)) {
|
||||||
val roomId = data["room_id"]
|
|
||||||
|
|
||||||
if (isEventAlreadyKnown(eventId, roomId)) {
|
|
||||||
Timber.d("Ignoring push, event already known")
|
Timber.d("Ignoring push, event already known")
|
||||||
} else {
|
} else {
|
||||||
// Try to get the Event content faster
|
// Try to get the Event content faster
|
||||||
Timber.d("Requesting event in fast lane")
|
Timber.d("Requesting event in fast lane")
|
||||||
getEventFastLane(session, roomId, eventId)
|
getEventFastLane(session, notification.roomId, notification.eventId)
|
||||||
|
|
||||||
Timber.d("Requesting background sync")
|
Timber.d("Requesting background sync")
|
||||||
session.requireBackgroundSync()
|
session.requireBackgroundSync()
|
||||||
|
@ -227,87 +273,6 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleNotificationWithoutSyncingMode(data: Map<String, String>, session: Session?) {
|
|
||||||
if (session == null) {
|
|
||||||
Timber.e("## handleNotificationWithoutSyncingMode cannot find session")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Matrix event ID of the event being notified about.
|
|
||||||
// This is required if the notification is about a particular Matrix event.
|
|
||||||
// It may be omitted for notifications that only contain updated badge counts.
|
|
||||||
// This ID can and should be used to detect duplicate notification requests.
|
|
||||||
val eventId = data["event_id"] ?: return // Just ignore
|
|
||||||
|
|
||||||
val eventType = data["type"]
|
|
||||||
if (eventType == null) {
|
|
||||||
// Just add a generic unknown event
|
|
||||||
val simpleNotifiableEvent = SimpleNotifiableEvent(
|
|
||||||
session.myUserId,
|
|
||||||
eventId,
|
|
||||||
null,
|
|
||||||
true, // It's an issue in this case, all event will bing even if expected to be silent.
|
|
||||||
title = getString(R.string.notification_unknown_new_event),
|
|
||||||
description = "",
|
|
||||||
type = null,
|
|
||||||
timestamp = System.currentTimeMillis(),
|
|
||||||
soundName = Action.ACTION_OBJECT_VALUE_VALUE_DEFAULT,
|
|
||||||
isPushGatewayEvent = true
|
|
||||||
)
|
|
||||||
notificationDrawerManager.onNotifiableEventReceived(simpleNotifiableEvent)
|
|
||||||
notificationDrawerManager.refreshNotificationDrawer()
|
|
||||||
} else {
|
|
||||||
val event = parseEvent(data) ?: return
|
|
||||||
|
|
||||||
val notifiableEvent = notifiableEventResolver.resolveEvent(event, session)
|
|
||||||
|
|
||||||
if (notifiableEvent == null) {
|
|
||||||
Timber.e("Unsupported notifiable event $eventId")
|
|
||||||
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
|
||||||
Timber.e("--> $event")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (notifiableEvent is NotifiableMessageEvent) {
|
|
||||||
if (notifiableEvent.senderName.isNullOrEmpty()) {
|
|
||||||
notifiableEvent.senderName = data["sender_display_name"] ?: data["sender"] ?: ""
|
|
||||||
}
|
|
||||||
if (notifiableEvent.roomName.isNullOrEmpty()) {
|
|
||||||
notifiableEvent.roomName = findRoomNameBestEffort(data, session) ?: ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
notifiableEvent.isPushGatewayEvent = true
|
|
||||||
notifiableEvent.matrixID = session.myUserId
|
|
||||||
notificationDrawerManager.onNotifiableEventReceived(notifiableEvent)
|
|
||||||
notificationDrawerManager.refreshNotificationDrawer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findRoomNameBestEffort(data: Map<String, String>, session: Session?): String? {
|
|
||||||
var roomName: String? = data["room_name"]
|
|
||||||
val roomId = data["room_id"]
|
|
||||||
if (null == roomName && null != roomId) {
|
|
||||||
// Try to get the room name from our store
|
|
||||||
roomName = session?.getRoom(roomId)?.roomSummary()?.displayName
|
|
||||||
}
|
|
||||||
return roomName
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to create an event from the FCM data
|
|
||||||
*
|
|
||||||
* @param data the FCM data
|
|
||||||
* @return the event or null if required data are missing
|
|
||||||
*/
|
|
||||||
private fun parseEvent(data: Map<String, String>?): Event? {
|
|
||||||
return Event(
|
|
||||||
eventId = data?.get("event_id") ?: return null,
|
|
||||||
senderId = data["sender"],
|
|
||||||
roomId = data["room_id"] ?: return null,
|
|
||||||
type = data["type"] ?: return null,
|
|
||||||
originServerTs = System.currentTimeMillis()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class VectorMessagingReceiver : MessagingReceiver(upHandler)
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.app.fdroid.receiver
|
package im.vector.app.core.receiver
|
||||||
|
|
||||||
import android.app.AlarmManager
|
import android.app.AlarmManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
|
@ -14,11 +14,10 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.app.fdroid
|
package im.vector.app.core.receiver
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.fdroid.receiver.AlarmSyncBroadcastReceiver
|
|
||||||
import im.vector.app.features.settings.BackgroundSyncMode
|
import im.vector.app.features.settings.BackgroundSyncMode
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
|
@ -15,14 +15,13 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.app.fdroid.receiver
|
package im.vector.app.core.receiver
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import im.vector.app.core.di.HasVectorInjector
|
import im.vector.app.core.di.HasVectorInjector
|
||||||
import im.vector.app.core.extensions.vectorComponent
|
import im.vector.app.core.extensions.vectorComponent
|
||||||
import im.vector.app.fdroid.BackgroundSyncStarter
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() {
|
class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() {
|
|
@ -29,8 +29,8 @@ import im.vector.app.features.call.lookup.CallProtocolsChecker
|
||||||
import im.vector.app.features.call.lookup.CallUserMapper
|
import im.vector.app.features.call.lookup.CallUserMapper
|
||||||
import im.vector.app.features.call.utils.EglUtils
|
import im.vector.app.features.call.utils.EglUtils
|
||||||
import im.vector.app.features.call.vectorCallService
|
import im.vector.app.features.call.vectorCallService
|
||||||
|
import im.vector.app.core.pushers.UPHelper
|
||||||
import im.vector.app.features.session.coroutineScope
|
import im.vector.app.features.session.coroutineScope
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.asCoroutineDispatcher
|
import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
|
@ -262,7 +262,7 @@ class WebRtcCallManager @Inject constructor(
|
||||||
audioManager.setMode(CallAudioManager.Mode.DEFAULT)
|
audioManager.setMode(CallAudioManager.Mode.DEFAULT)
|
||||||
// did we start background sync? so we should stop it
|
// did we start background sync? so we should stop it
|
||||||
if (isInBackground) {
|
if (isInBackground) {
|
||||||
if (FcmHelper.isPushSupported()) {
|
if (UPHelper.hasEndpoint(context)) {
|
||||||
currentSession?.stopAnyBackgroundSync()
|
currentSession?.stopAnyBackgroundSync()
|
||||||
} else {
|
} else {
|
||||||
// for fdroid we should not stop, it should continue syncing
|
// for fdroid we should not stop, it should continue syncing
|
||||||
|
@ -367,7 +367,7 @@ class WebRtcCallManager @Inject constructor(
|
||||||
// and thus won't be able to received events. For example if the call is
|
// and thus won't be able to received events. For example if the call is
|
||||||
// accepted on an other session this device will continue ringing
|
// accepted on an other session this device will continue ringing
|
||||||
if (isInBackground) {
|
if (isInBackground) {
|
||||||
if (FcmHelper.isPushSupported()) {
|
if (UPHelper.hasEndpoint(context)) {
|
||||||
// only for push version as fdroid version is already doing it?
|
// only for push version as fdroid version is already doing it?
|
||||||
currentSession?.startAutomaticBackgroundSync(30, 0)
|
currentSession?.startAutomaticBackgroundSync(30, 0)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -68,7 +68,7 @@ import im.vector.app.features.spaces.share.ShareSpaceBottomSheet
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
||||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
|
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
import im.vector.app.core.pushers.UPHelper
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
|
import org.matrix.android.sdk.api.session.initsync.InitialSyncProgressService
|
||||||
|
@ -165,7 +165,7 @@ class HomeActivity :
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())
|
UPHelper.registerUnifiedPush(this)
|
||||||
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
|
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||||
views.drawerLayout.addDrawerListener(drawerListener)
|
views.drawerLayout.addDrawerListener(drawerListener)
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.text.TextUtils
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
@ -29,6 +30,7 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.extensions.getAllChildFragments
|
import im.vector.app.core.extensions.getAllChildFragments
|
||||||
import im.vector.app.core.extensions.toOnOff
|
import im.vector.app.core.extensions.toOnOff
|
||||||
|
import im.vector.app.core.pushers.UPHelper
|
||||||
import im.vector.app.features.settings.VectorLocale
|
import im.vector.app.features.settings.VectorLocale
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.settings.devtools.GossipingEventsSerializer
|
import im.vector.app.features.settings.devtools.GossipingEventsSerializer
|
||||||
|
@ -55,6 +57,7 @@ import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStreamWriter
|
import java.io.OutputStreamWriter
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
|
import java.net.URL
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -276,6 +279,13 @@ class BugReporter @Inject constructor(
|
||||||
.addFormDataPart("theme", ThemeUtils.getApplicationTheme(context))
|
.addFormDataPart("theme", ThemeUtils.getApplicationTheme(context))
|
||||||
.addFormDataPart("server_version", serverVersion)
|
.addFormDataPart("server_version", serverVersion)
|
||||||
|
|
||||||
|
// UnifiedPush
|
||||||
|
// Only include the UP endpoint base url to exclude private user tokens in the path or parameters
|
||||||
|
builder.addFormDataPart("unifiedpush_endpoint", strippedUrl(UPHelper.getUpEndpoint(context)).toString())
|
||||||
|
.addFormDataPart("unifiedpush_gateway", UPHelper.getPushGateway(context))
|
||||||
|
.addFormDataPart("unifiedpush_distributor_exists", UPHelper.distributorExists(context).toString())
|
||||||
|
.addFormDataPart("unifiedpush_is_embedded_distributor", UPHelper.isEmbeddedDistributor(context).toString())
|
||||||
|
|
||||||
val buildNumber = context.getString(R.string.build_number)
|
val buildNumber = context.getString(R.string.build_number)
|
||||||
if (buildNumber.isNotEmpty() && buildNumber != "0") {
|
if (buildNumber.isNotEmpty() && buildNumber != "0") {
|
||||||
builder.addFormDataPart("build_number", buildNumber)
|
builder.addFormDataPart("build_number", buildNumber)
|
||||||
|
@ -454,6 +464,16 @@ class BugReporter @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun strippedUrl(url: String?): String? {
|
||||||
|
if (TextUtils.isEmpty(url)) return null
|
||||||
|
return try {
|
||||||
|
val parsed = URL(url)
|
||||||
|
"${parsed.protocol}://${parsed.host}"
|
||||||
|
} catch (e: Exception) {
|
||||||
|
"Malformed url"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a bug report either with email or with Vector.
|
* Send a bug report either with email or with Vector.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -37,16 +37,17 @@ import im.vector.app.core.pushers.PushersManager
|
||||||
import im.vector.app.core.utils.isIgnoringBatteryOptimizations
|
import im.vector.app.core.utils.isIgnoringBatteryOptimizations
|
||||||
import im.vector.app.core.utils.requestDisablingBatteryOptimization
|
import im.vector.app.core.utils.requestDisablingBatteryOptimization
|
||||||
import im.vector.app.features.notifications.NotificationUtils
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
|
import im.vector.app.core.pushers.UPHelper
|
||||||
import im.vector.app.features.settings.BackgroundSyncMode
|
import im.vector.app.features.settings.BackgroundSyncMode
|
||||||
import im.vector.app.features.settings.BackgroundSyncModeChooserDialog
|
import im.vector.app.features.settings.BackgroundSyncModeChooserDialog
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.settings.VectorSettingsBaseFragment
|
import im.vector.app.features.settings.VectorSettingsBaseFragment
|
||||||
import im.vector.app.features.settings.VectorSettingsFragmentInteractionListener
|
import im.vector.app.features.settings.VectorSettingsFragmentInteractionListener
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.pushrules.RuleIds
|
import org.matrix.android.sdk.api.pushrules.RuleIds
|
||||||
import org.matrix.android.sdk.api.pushrules.RuleKind
|
import org.matrix.android.sdk.api.pushrules.RuleKind
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
// Referenced in vector_settings_preferences_root.xml
|
// Referenced in vector_settings_preferences_root.xml
|
||||||
|
@ -150,7 +151,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
findPreference<VectorPreferenceCategory>(VectorPreferences.SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY)?.let {
|
findPreference<VectorPreferenceCategory>(VectorPreferences.SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY)?.let {
|
||||||
it.isVisible = !FcmHelper.isPushSupported()
|
it.isVisible = !UPHelper.hasEndpoint(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
findPreference<VectorEditTextPreference>(VectorPreferences.SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY)?.let {
|
findPreference<VectorEditTextPreference>(VectorPreferences.SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY)?.let {
|
||||||
|
@ -254,7 +255,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
|
||||||
|
|
||||||
private fun refreshPref() {
|
private fun refreshPref() {
|
||||||
// This pref may have change from troubleshoot pref fragment
|
// This pref may have change from troubleshoot pref fragment
|
||||||
if (!FcmHelper.isPushSupported()) {
|
if (!UPHelper.hasEndpoint(requireContext())) {
|
||||||
findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_START_ON_BOOT_PREFERENCE_KEY)
|
findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_START_ON_BOOT_PREFERENCE_KEY)
|
||||||
?.isChecked = vectorPreferences.autoStartOnBoot()
|
?.isChecked = vectorPreferences.autoStartOnBoot()
|
||||||
}
|
}
|
||||||
|
@ -294,13 +295,22 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
|
||||||
private fun updateEnabledForDevice(preference: Preference?) {
|
private fun updateEnabledForDevice(preference: Preference?) {
|
||||||
val switchPref = preference as SwitchPreference
|
val switchPref = preference as SwitchPreference
|
||||||
if (switchPref.isChecked) {
|
if (switchPref.isChecked) {
|
||||||
FcmHelper.getFcmToken(requireContext())?.let {
|
UPHelper.registerUnifiedPush(requireContext())
|
||||||
pushManager.registerPusherWithFcmKey(it)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
FcmHelper.getFcmToken(requireContext())?.let {
|
UPHelper.getUpEndpoint(requireContext())?.let {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
runCatching { pushManager.unregisterPusher(it) }
|
runCatching {
|
||||||
|
try {
|
||||||
|
pushManager.unregisterPusher(requireContext(), it)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.d("Probably unregistering a non existant pusher")
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
UPHelper.unregister(requireContext())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.d("Probably unregistering to a non-saved distributor")
|
||||||
|
}
|
||||||
|
}
|
||||||
.fold(
|
.fold(
|
||||||
{ session.refreshPushers() },
|
{ session.refreshPushers() },
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,14 +13,13 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package im.vector.app.fdroid.features.settings.troubleshoot
|
package im.vector.app.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2018 New Vector Ltd
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package im.vector.app.fdroid.features.settings.troubleshoot
|
package im.vector.app.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
|
@ -23,7 +23,6 @@ import androidx.core.content.getSystemService
|
||||||
import androidx.core.net.ConnectivityManagerCompat
|
import androidx.core.net.ConnectivityManagerCompat
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TestBackgroundRestrictions @Inject constructor(private val context: AppCompatActivity,
|
class TestBackgroundRestrictions @Inject constructor(private val context: AppCompatActivity,
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package im.vector.app.fdroid.features.settings.troubleshoot
|
package im.vector.app.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
@ -22,7 +22,6 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.core.utils.isIgnoringBatteryOptimizations
|
import im.vector.app.core.utils.isIgnoringBatteryOptimizations
|
||||||
import im.vector.app.core.utils.requestDisablingBatteryOptimization
|
import im.vector.app.core.utils.requestDisablingBatteryOptimization
|
||||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TestBatteryOptimization @Inject constructor(
|
class TestBatteryOptimization @Inject constructor(
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package im.vector.app.features.settings.troubleshoot
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.pushers.UPHelper
|
||||||
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test that app can successfully retrieve a new endpoint
|
||||||
|
*/
|
||||||
|
class TestNewEndpoint @Inject constructor(private val context: AppCompatActivity,
|
||||||
|
private val stringProvider: StringProvider
|
||||||
|
) : TroubleshootTest(R.string.settings_troubleshoot_test_endpoint_title) {
|
||||||
|
|
||||||
|
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||||
|
status = TestStatus.RUNNING
|
||||||
|
|
||||||
|
val endpoint = UPHelper.getUpEndpoint(context)
|
||||||
|
|
||||||
|
if (UPHelper.isEmbeddedDistributor(context)) {
|
||||||
|
if (!endpoint.isNullOrEmpty()) {
|
||||||
|
status = TestStatus.SUCCESS
|
||||||
|
description = stringProvider.getString(R.string.settings_troubleshoot_test_fcm_success, endpoint)
|
||||||
|
} else {
|
||||||
|
status = TestStatus.FAILED
|
||||||
|
description = stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!endpoint.isNullOrEmpty()) {
|
||||||
|
status = TestStatus.SUCCESS
|
||||||
|
description = stringProvider.getString(R.string.settings_troubleshoot_test_endpoint_success, endpoint)
|
||||||
|
} else {
|
||||||
|
status = TestStatus.FAILED
|
||||||
|
description = stringProvider.getString(R.string.settings_troubleshoot_test_endpoint_failed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2020 New Vector Ltd
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package im.vector.app.gplay.features.settings.troubleshoot
|
package im.vector.app.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
@ -24,8 +24,7 @@ import im.vector.app.core.error.ErrorFormatter
|
||||||
import im.vector.app.core.pushers.PushersManager
|
import im.vector.app.core.pushers.PushersManager
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.session.coroutineScope
|
import im.vector.app.features.session.coroutineScope
|
||||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
import im.vector.app.core.pushers.UPHelper
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -48,12 +47,12 @@ class TestPushFromPushGateway @Inject constructor(private val context: AppCompat
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||||
pushReceived = false
|
pushReceived = false
|
||||||
val fcmToken = FcmHelper.getFcmToken(context) ?: run {
|
UPHelper.getUpEndpoint(context) ?: run {
|
||||||
status = TestStatus.FAILED
|
status = TestStatus.FAILED
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
action = activeSessionHolder.getActiveSession().coroutineScope.launch {
|
action = activeSessionHolder.getActiveSession().coroutineScope.launch {
|
||||||
val result = runCatching { pushersManager.testPush(fcmToken) }
|
val result = runCatching { pushersManager.testPush(context) }
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
status = result
|
status = result
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package im.vector.app.gplay.features.settings.troubleshoot
|
package im.vector.app.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
@ -26,8 +26,7 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.pushers.PushersManager
|
import im.vector.app.core.pushers.PushersManager
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
import im.vector.app.core.pushers.UPHelper
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,11 +36,15 @@ class TestTokenRegistration @Inject constructor(private val context: AppCompatAc
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val pushersManager: PushersManager,
|
private val pushersManager: PushersManager,
|
||||||
private val activeSessionHolder: ActiveSessionHolder)
|
private val activeSessionHolder: ActiveSessionHolder)
|
||||||
: TroubleshootTest(R.string.settings_troubleshoot_test_token_registration_title) {
|
: TroubleshootTest(R.string.settings_troubleshoot_test_pusher_registration_title) {
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||||
// Check if we have a registered pusher for this token
|
// Check if we have a registered pusher for this token
|
||||||
val fcmToken = FcmHelper.getFcmToken(context) ?: run {
|
val pushToken = UPHelper.getUpEndpoint(context) ?: run {
|
||||||
|
status = TestStatus.FAILED
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val pushGateway = UPHelper.getPushGateway(context) ?: run {
|
||||||
status = TestStatus.FAILED
|
status = TestStatus.FAILED
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -50,14 +53,14 @@ class TestTokenRegistration @Inject constructor(private val context: AppCompatAc
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val pushers = session.getPushers().filter {
|
val pushers = session.getPushers().filter {
|
||||||
it.pushKey == fcmToken && it.state == PusherState.REGISTERED
|
it.pushKey == pushToken && it.state == PusherState.REGISTERED
|
||||||
}
|
}
|
||||||
if (pushers.isEmpty()) {
|
if (pushers.isEmpty()) {
|
||||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_token_registration_failed,
|
description = stringProvider.getString(R.string.settings_troubleshoot_test_pusher_registration_failed,
|
||||||
stringProvider.getString(R.string.sas_error_unknown))
|
stringProvider.getString(R.string.sas_error_unknown))
|
||||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_token_registration_quick_fix) {
|
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_token_registration_quick_fix) {
|
||||||
override fun doFix() {
|
override fun doFix() {
|
||||||
val workId = pushersManager.registerPusherWithFcmKey(fcmToken)
|
val workId = pushersManager.registerPusher(context, pushToken, pushGateway)
|
||||||
WorkManager.getInstance(context).getWorkInfoByIdLiveData(workId).observe(context, Observer { workInfo ->
|
WorkManager.getInstance(context).getWorkInfoByIdLiveData(workId).observe(context, Observer { workInfo ->
|
||||||
if (workInfo != null) {
|
if (workInfo != null) {
|
||||||
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
|
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
|
||||||
|
@ -72,7 +75,7 @@ class TestTokenRegistration @Inject constructor(private val context: AppCompatAc
|
||||||
|
|
||||||
status = TestStatus.FAILED
|
status = TestStatus.FAILED
|
||||||
} else {
|
} else {
|
||||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_token_registration_success)
|
description = stringProvider.getString(R.string.settings_troubleshoot_test_pusher_registration_success)
|
||||||
status = TestStatus.SUCCESS
|
status = TestStatus.SUCCESS
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,7 +14,11 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- Note: pusher_http_url should have path '/_matrix/push/v1/notify' -->
|
<!-- Note: pusher_http_url should have path '/_matrix/push/v1/notify' -->
|
||||||
|
<!-- It is the push gateway for FCM embedded distributor -->
|
||||||
<string name="pusher_http_url" translatable="false">https://matrix.org/_matrix/push/v1/notify</string>
|
<string name="pusher_http_url" translatable="false">https://matrix.org/_matrix/push/v1/notify</string>
|
||||||
|
<!-- Note: default_push_gateway_http_url should have path '/_matrix/push/v1/notify' -->
|
||||||
|
<!-- It is the push gateway for UnifiedPush -->
|
||||||
|
<string name="default_push_gateway_http_url" translatable="false">https://up.schildi.chat/_matrix/push/v1/notify</string>
|
||||||
<!-- Note: pusher_app_id cannot exceed 64 chars -->
|
<!-- Note: pusher_app_id cannot exceed 64 chars -->
|
||||||
<string name="pusher_app_id" translatable="false">im.vector.app.android</string>
|
<string name="pusher_app_id" translatable="false">im.vector.app.android</string>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<string name="up_pusher_app_id" translatable="false">de.spiritcroc.riotx.up</string>
|
||||||
|
|
||||||
|
</resources>
|
|
@ -1131,6 +1131,16 @@
|
||||||
<string name="template_settings_troubleshoot_test_play_services_failed">${app_name} uses Google Play Services to deliver push messages but it doesn’t seem to be configured correctly:\n%1$s</string>
|
<string name="template_settings_troubleshoot_test_play_services_failed">${app_name} uses Google Play Services to deliver push messages but it doesn’t seem to be configured correctly:\n%1$s</string>
|
||||||
<string name="settings_troubleshoot_test_play_services_quickfix">Fix Play Services</string>
|
<string name="settings_troubleshoot_test_play_services_quickfix">Fix Play Services</string>
|
||||||
|
|
||||||
|
<!-- Unifiedpush Endpoint -->
|
||||||
|
<string name="settings_troubleshoot_test_endpoint_title">Endpoint/FCM</string>
|
||||||
|
<string name="settings_troubleshoot_test_endpoint_success">Endpoint successfully retrieved:\n%1$s</string>
|
||||||
|
<string name="settings_troubleshoot_test_endpoint_failed">Failed to retrieved Endpoint.</string>
|
||||||
|
|
||||||
|
<!-- UnifiedPush Distributor Picker Dialog -->
|
||||||
|
<string name="unifiedpush_getdistributors_dialog_title">Choose a distributor</string>
|
||||||
|
<string name="unifiedpush_getdistributors_dialog_fcm_fallback">FCM Fallback</string>
|
||||||
|
|
||||||
|
<!-- FCM Token, not used anymore -->
|
||||||
<string name="settings_troubleshoot_test_fcm_title">Firebase Token</string>
|
<string name="settings_troubleshoot_test_fcm_title">Firebase Token</string>
|
||||||
<string name="settings_troubleshoot_test_fcm_success">FCM token successfully retrieved:\n%1$s</string>
|
<string name="settings_troubleshoot_test_fcm_success">FCM token successfully retrieved:\n%1$s</string>
|
||||||
<string name="settings_troubleshoot_test_fcm_failed">Failed to retrieved FCM token:\n%1$s</string>
|
<string name="settings_troubleshoot_test_fcm_failed">Failed to retrieved FCM token:\n%1$s</string>
|
||||||
|
@ -1142,6 +1152,12 @@
|
||||||
<string name="template_settings_troubleshoot_test_fcm_failed_account_missing">[%1$s]\nThis error is out of control of ${app_name}. There is no Google account on the phone. Please open the account manager and add a Google account.</string>
|
<string name="template_settings_troubleshoot_test_fcm_failed_account_missing">[%1$s]\nThis error is out of control of ${app_name}. There is no Google account on the phone. Please open the account manager and add a Google account.</string>
|
||||||
<string name="settings_troubleshoot_test_fcm_failed_account_missing_quick_fix">Add Account</string>
|
<string name="settings_troubleshoot_test_fcm_failed_account_missing_quick_fix">Add Account</string>
|
||||||
|
|
||||||
|
<!-- Pusher registration -->
|
||||||
|
<string name="settings_troubleshoot_test_pusher_registration_title">Pusher Registration</string>
|
||||||
|
<string name="settings_troubleshoot_test_pusher_registration_success">Pusher successfully registered to HomeServer.</string>
|
||||||
|
<string name="settings_troubleshoot_test_pusher_registration_failed">Failed to register pusher to HomeServer:\n%1$s</string>
|
||||||
|
|
||||||
|
<!-- FCM token, not used -->
|
||||||
<string name="settings_troubleshoot_test_token_registration_title">Token Registration</string>
|
<string name="settings_troubleshoot_test_token_registration_title">Token Registration</string>
|
||||||
<string name="settings_troubleshoot_test_token_registration_success">FCM token successfully registered to homeserver.</string>
|
<string name="settings_troubleshoot_test_token_registration_success">FCM token successfully registered to homeserver.</string>
|
||||||
<string name="settings_troubleshoot_test_token_registration_failed">Failed to register FCM token to homeserver:\n%1$s</string>
|
<string name="settings_troubleshoot_test_token_registration_failed">Failed to register FCM token to homeserver:\n%1$s</string>
|
||||||
|
|
Loading…
Reference in New Issue