mirror of
https://github.com/bitwarden/android.git
synced 2024-11-26 11:26:09 +03:00
Process push notification to display auth request notification (#919)
This commit is contained in:
parent
77913805ab
commit
ce3066dd54
7 changed files with 155 additions and 1 deletions
|
@ -44,6 +44,10 @@
|
|||
<data android:mimeType="video/*" />
|
||||
<data android:mimeType="text/*" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.x8bit.bitwarden.data.auth.manager.AUTH_REQUEST" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden
|
||||
|
||||
import android.app.Application
|
||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestNotificationManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.CrashLogsManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.NetworkConfigManager
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
@ -18,4 +19,7 @@ class BitwardenApplication : Application() {
|
|||
|
||||
@Inject
|
||||
lateinit var crashLogsManager: CrashLogsManager
|
||||
|
||||
@Inject
|
||||
lateinit var authRequestNotificationManager: AuthRequestNotificationManager
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package com.x8bit.bitwarden.data.auth.manager
|
||||
|
||||
/**
|
||||
* Manages the auth request push notifications and handles displaying notifications.
|
||||
*/
|
||||
interface AuthRequestNotificationManager
|
|
@ -0,0 +1,109 @@
|
|||
package com.x8bit.bitwarden.data.auth.manager
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.core.app.NotificationChannelCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.x8bit.bitwarden.MainActivity
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.autofill.util.toPendingIntentMutabilityFlag
|
||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||
import com.x8bit.bitwarden.data.platform.manager.PushManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.PasswordlessRequestData
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
/**
|
||||
* The default implementation of the [AuthRequestNotificationManager].
|
||||
*/
|
||||
@OmitFromCoverage
|
||||
class AuthRequestNotificationManagerImpl(
|
||||
private val context: Context,
|
||||
private val authDiskSource: AuthDiskSource,
|
||||
pushManager: PushManager,
|
||||
dispatchers: DispatcherManager,
|
||||
) : AuthRequestNotificationManager {
|
||||
private val ioScope = CoroutineScope(dispatchers.io)
|
||||
|
||||
init {
|
||||
pushManager
|
||||
.passwordlessRequestFlow
|
||||
.onEach(::handlePasswordlessRequestData)
|
||||
.launchIn(ioScope)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun handlePasswordlessRequestData(data: PasswordlessRequestData) {
|
||||
val notificationManager = NotificationManagerCompat.from(context)
|
||||
if (notificationManager.areNotificationsEnabled(NOTIFICATION_CHANNEL_ID)) return
|
||||
// Construct the channel, calling this more than once is safe
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannelCompat
|
||||
.Builder(
|
||||
NOTIFICATION_CHANNEL_ID,
|
||||
NotificationManagerCompat.IMPORTANCE_DEFAULT,
|
||||
)
|
||||
.setName(context.getString(R.string.pending_log_in_requests))
|
||||
.build(),
|
||||
)
|
||||
// Create the notification
|
||||
val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
|
||||
.setContentIntent(createContentIntent(data))
|
||||
.setContentTitle(context.getString(R.string.log_in_requested))
|
||||
.setContentText(
|
||||
authDiskSource
|
||||
.userState
|
||||
?.accounts
|
||||
?.get(data.userId)
|
||||
?.profile
|
||||
?.email
|
||||
?.let { context.getString(R.string.confim_log_in_attemp_for_x, it) }
|
||||
?: context.getString(R.string.confirm_log_in),
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_launcher_foreground)
|
||||
.setColor(Color.White.value.toInt())
|
||||
.setAutoCancel(true)
|
||||
.setTimeoutAfter(NOTIFICATION_DEFAULT_TIMEOUT_MILLIS)
|
||||
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
|
||||
private fun createContentIntent(data: PasswordlessRequestData): PendingIntent =
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
NOTIFICATION_REQUEST_CODE,
|
||||
Intent(context, MainActivity::class.java)
|
||||
.setAction(NOTIFICATION_ACTION)
|
||||
.putExtra(NOTIFICATION_DATA, data),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT.toPendingIntentMutabilityFlag(),
|
||||
)
|
||||
|
||||
private fun NotificationManagerCompat.areNotificationsEnabled(
|
||||
channelId: String,
|
||||
): Boolean = areNotificationsEnabled() && isChannelEnabled(channelId)
|
||||
|
||||
private fun NotificationManagerCompat.isChannelEnabled(
|
||||
channelId: String,
|
||||
): Boolean = getChannelImportance(channelId) != NotificationManagerCompat.IMPORTANCE_NONE
|
||||
|
||||
private fun NotificationManagerCompat.getChannelImportance(
|
||||
channelId: String,
|
||||
): Int = this
|
||||
.getNotificationChannelCompat(channelId)
|
||||
?.importance
|
||||
?: NotificationManagerCompat.IMPORTANCE_DEFAULT
|
||||
}
|
||||
|
||||
const val NOTIFICATION_ACTION: String = "com.x8bit.bitwarden.data.auth.manager.AUTH_REQUEST"
|
||||
private const val NOTIFICATION_CHANNEL_ID: String = "general_notification_channel"
|
||||
private const val NOTIFICATION_ID: Int = 2_6072_022
|
||||
private const val NOTIFICATION_DATA: String = "notificationData"
|
||||
private const val NOTIFICATION_REQUEST_CODE: Int = 20220801
|
||||
private const val NOTIFICATION_DEFAULT_TIMEOUT_MILLIS: Long = 15L * 60L * 1_000L
|
|
@ -1,10 +1,14 @@
|
|||
package com.x8bit.bitwarden.data.auth.manager.di
|
||||
|
||||
import android.content.Context
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestNotificationManager
|
||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestNotificationManagerImpl
|
||||
import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager
|
||||
import com.x8bit.bitwarden.data.auth.manager.UserLogoutManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.PushDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.PushManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.GeneratorDiskSource
|
||||
import com.x8bit.bitwarden.data.tools.generator.datasource.disk.PasswordHistoryDiskSource
|
||||
|
@ -12,6 +16,7 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource
|
|||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -22,6 +27,21 @@ import javax.inject.Singleton
|
|||
@InstallIn(SingletonComponent::class)
|
||||
object AuthManagerModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAuthRequestNotificationManager(
|
||||
@ApplicationContext context: Context,
|
||||
authDiskSource: AuthDiskSource,
|
||||
pushManager: PushManager,
|
||||
dispatchers: DispatcherManager,
|
||||
): AuthRequestNotificationManager =
|
||||
AuthRequestNotificationManagerImpl(
|
||||
context = context,
|
||||
authDiskSource = authDiskSource,
|
||||
pushManager = pushManager,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUserLogoutManager(
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
/**
|
||||
* Required data for passwordless requests.
|
||||
*
|
||||
* @property loginRequestId The login request ID.
|
||||
* @property userId The user ID.
|
||||
*/
|
||||
@Parcelize
|
||||
data class PasswordlessRequestData(
|
||||
val loginRequestId: String,
|
||||
val userId: String,
|
||||
)
|
||||
) : Parcelable
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application tools:ignore="MissingApplicationIcon">
|
||||
<service
|
||||
android:name="com.x8bit.bitwarden.data.push.BitwardenFirebaseMessagingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<!-- Disable Crashlytics for debug builds -->
|
||||
<meta-data
|
||||
android:name="firebase_crashlytics_collection_enabled"
|
||||
|
|
Loading…
Reference in a new issue