Updated on 2026-08-14
This commit is contained in:
parent
5a11a6109f
commit
bc7d7ea7b6
18 changed files with 357 additions and 84 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -9,6 +9,10 @@ local.properties
|
||||||
|
|
||||||
# Google services
|
# Google services
|
||||||
|
|
||||||
|
|
||||||
|
# Huawei services
|
||||||
|
app/agconnect-services.json
|
||||||
|
|
||||||
app/src/debug/google-services.json
|
app/src/debug/google-services.json
|
||||||
app/src/internal/google-services.json
|
app/src/internal/google-services.json
|
||||||
app/src/external/google-services.json
|
app/src/external/google-services.json
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,14 @@ plugins {
|
||||||
alias(deps.plugins.firebase.crashlytics)
|
alias(deps.plugins.firebase.crashlytics)
|
||||||
alias(deps.plugins.firebase.perf)
|
alias(deps.plugins.firebase.perf)
|
||||||
alias(deps.plugins.ksp)
|
alias(deps.plugins.ksp)
|
||||||
|
id(deps.plugins.agconnect.get().pluginId)
|
||||||
id("configuration")
|
id("configuration")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
agcp {
|
||||||
|
manifest = false
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.tangem.wallet"
|
namespace = "com.tangem.wallet"
|
||||||
testOptions {
|
testOptions {
|
||||||
|
|
@ -53,12 +58,35 @@ android {
|
||||||
keyPassword = keystoreProperties["key_password"] as String
|
keyPassword = keystoreProperties["key_password"] as String
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flavorDimensions += "services"
|
||||||
|
|
||||||
|
productFlavors {
|
||||||
|
create("google") {
|
||||||
|
dimension = "services"
|
||||||
|
buildConfigField("String", "FLAVOR_NAME", "\"google\"")
|
||||||
|
}
|
||||||
|
create("huawei") {
|
||||||
|
dimension = "services"
|
||||||
|
buildConfigField("String", "FLAVOR_NAME", "\"huawei\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
debug {
|
||||||
|
buildConfigField("String", "BUILD_TYPE", "\"debug\"")
|
||||||
|
}
|
||||||
|
release {
|
||||||
|
buildConfigField("String", "BUILD_TYPE", "\"release\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations.all {
|
configurations.all {
|
||||||
exclude(group = "org.bouncycastle", module = "bcprov-jdk15to18")
|
exclude(group = "org.bouncycastle", module = "bcprov-jdk15to18")
|
||||||
exclude(group = "com.github.komputing.kethereum")
|
exclude(group = "com.github.komputing.kethereum")
|
||||||
|
exclude(group = "com.android.tools.build", module = "gradle")
|
||||||
|
|
||||||
resolutionStrategy {
|
resolutionStrategy {
|
||||||
dependencySubstitution {
|
dependencySubstitution {
|
||||||
|
|
@ -379,4 +407,9 @@ dependencies {
|
||||||
// excludes version 9999.0-empty-to-avoid-conflict-with-guava
|
// excludes version 9999.0-empty-to-avoid-conflict-with-guava
|
||||||
exclude(group = "com.google.guava", module = "listenablefuture")
|
exclude(group = "com.google.guava", module = "listenablefuture")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Huawei flavor-specific dependencies */
|
||||||
|
"huaweiImplementation"(deps.huawei.push)
|
||||||
|
"huaweiImplementation"(deps.agconnect.agcp)
|
||||||
|
"huaweiImplementation"(deps.agconnect.core)
|
||||||
}
|
}
|
||||||
7
app/proguard-rules.pro
vendored
7
app/proguard-rules.pro
vendored
|
|
@ -7,6 +7,13 @@
|
||||||
-keep class com.google.android.gms.internal.** { *; }
|
-keep class com.google.android.gms.internal.** { *; }
|
||||||
-keepclasseswithmembers class com.google.firebase.FirebaseException
|
-keepclasseswithmembers class com.google.firebase.FirebaseException
|
||||||
|
|
||||||
|
# huawei push kit
|
||||||
|
-ignorewarnings
|
||||||
|
-keepattributes SourceFile,LineNumberTable
|
||||||
|
-keep class com.huawei.hianalytics.**{*;}
|
||||||
|
-keep class com.huawei.updatesdk.**{*;}
|
||||||
|
-keep class com.huawei.hms.**{*;}
|
||||||
|
|
||||||
# hedera sdk
|
# hedera sdk
|
||||||
-keep class com.hedera.hashgraph.sdk.** { *; }
|
-keep class com.hedera.hashgraph.sdk.** { *; }
|
||||||
-keep interface com.hedera.hashgraph.sdk.** { *; }
|
-keep interface com.hedera.hashgraph.sdk.** { *; }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.tap.data
|
package com.tangem.tap
|
||||||
|
|
||||||
import com.google.firebase.messaging.FirebaseMessaging
|
import com.google.firebase.messaging.FirebaseMessaging
|
||||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.tangem.tap.di.data
|
package com.tangem.tap.di
|
||||||
|
|
||||||
import com.tangem.tap.data.FirebasePushNotificationsTokenProvider
|
import com.tangem.tap.FirebasePushNotificationsTokenProvider
|
||||||
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||||
import dagger.Binds
|
import dagger.Binds
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
|
|
@ -10,7 +10,7 @@ import javax.inject.Singleton
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
internal interface PushNotificationsModule {
|
internal interface GooglePushModule {
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@Singleton
|
@Singleton
|
||||||
17
app/src/huawei/AndroidManifest.xml
Normal file
17
app/src/huawei/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<application>
|
||||||
|
<service
|
||||||
|
android:name="com.tangem.tap.HuaweiPushService"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.huawei.push.action.MESSAGING_EVENT" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="push_kit_auto_init_enabled"
|
||||||
|
android:value="true" />
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package com.tangem.tap
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.google.firebase.messaging.FirebaseMessaging
|
||||||
|
import com.huawei.agconnect.AGConnectOptionsBuilder
|
||||||
|
import com.huawei.hms.aaid.HmsInstanceId
|
||||||
|
import com.huawei.hms.common.ApiException
|
||||||
|
import com.tangem.google.GoogleServicesHelper
|
||||||
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import kotlinx.coroutines.tasks.await
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal class HuaweiPushNotificationsTokenProvider @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val coroutineDispatcherProvider: CoroutineDispatcherProvider,
|
||||||
|
) : PushNotificationsTokenProvider {
|
||||||
|
|
||||||
|
override suspend fun getToken(): String {
|
||||||
|
val isGoogleServicesAvailable = GoogleServicesHelper.checkGoogleServicesAvailability(context)
|
||||||
|
return if (isGoogleServicesAvailable) {
|
||||||
|
try {
|
||||||
|
FirebaseMessaging.getInstance().token.await()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Timber.e(ex)
|
||||||
|
""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
withContext(coroutineDispatcherProvider.io) {
|
||||||
|
try {
|
||||||
|
val appId = AGConnectOptionsBuilder().build(context).getString(APP_ID_KEY)
|
||||||
|
val token = HmsInstanceId.getInstance(context).getToken(appId, TOKEN_REQUEST_MODE)
|
||||||
|
Timber.i("Requested token from HuaweiService: $token")
|
||||||
|
token
|
||||||
|
} catch (e: ApiException) {
|
||||||
|
Timber.i("Fetching token from HuaweiService failed cause: ${e.message}")
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val APP_ID_KEY = "client/app_id"
|
||||||
|
private const val TOKEN_REQUEST_MODE = "HCM"
|
||||||
|
}
|
||||||
|
}
|
||||||
47
app/src/huawei/java/com/tangem/tap/HuaweiPushService.kt
Normal file
47
app/src/huawei/java/com/tangem/tap/HuaweiPushService.kt
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.tangem.tap
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.huawei.hms.push.HmsMessageService
|
||||||
|
import com.huawei.hms.push.RemoteMessage
|
||||||
|
import com.tangem.google.GoogleServicesHelper
|
||||||
|
import com.tangem.tap.common.pushes.PushNotificationDelegate
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class HuaweiPushService : HmsMessageService() {
|
||||||
|
|
||||||
|
private val pushNotificationDelegate: PushNotificationDelegate by lazy {
|
||||||
|
PushNotificationDelegate(applicationContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewToken(token: String?, bundle: Bundle?) {
|
||||||
|
super.onNewToken(token, bundle)
|
||||||
|
Timber.i("HuaweiPushService: On new token from HuaweiService: $token")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTokenError(e: Exception?, bundle: Bundle?) {
|
||||||
|
super.onTokenError(e, bundle)
|
||||||
|
Timber.i("HuaweiPushService: Fetching token from HuaweiService failed cause: ${e?.message}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMessageReceived(message: RemoteMessage?) {
|
||||||
|
super.onMessageReceived(message)
|
||||||
|
val isGoogleServicesAvailable = GoogleServicesHelper.checkGoogleServicesAvailability(this)
|
||||||
|
if (isGoogleServicesAvailable) return
|
||||||
|
val notification = message?.notification ?: return
|
||||||
|
val channelId = notification.channelId ?: TANGEM_CHANNEL_ID
|
||||||
|
|
||||||
|
pushNotificationDelegate.showNotification(
|
||||||
|
dataMap = message.dataOfMap,
|
||||||
|
title = notification.title,
|
||||||
|
body = notification.body,
|
||||||
|
channelId = channelId,
|
||||||
|
priority = message.urgency,
|
||||||
|
imageUrl = notification.imageUrl,
|
||||||
|
vibratePattern = notification.vibrateConfig,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val TANGEM_CHANNEL_ID = "Tangem General" // General channel for notifications
|
||||||
|
}
|
||||||
|
}
|
||||||
18
app/src/huawei/java/com/tangem/tap/di/HuaweiPushModule.kt
Normal file
18
app/src/huawei/java/com/tangem/tap/di/HuaweiPushModule.kt
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.tangem.tap.di
|
||||||
|
|
||||||
|
import com.tangem.tap.HuaweiPushNotificationsTokenProvider
|
||||||
|
import com.tangem.utils.notifications.PushNotificationsTokenProvider
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
internal interface HuaweiPushModule {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun bindPushNotificationsTokenProvider(impl: HuaweiPushNotificationsTokenProvider): PushNotificationsTokenProvider
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.tangem.tap.common.buildconfig
|
||||||
|
|
||||||
|
import com.tangem.utils.buildConfig.AppConfigurationProvider
|
||||||
|
import com.tangem.wallet.BuildConfig
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
internal class AppConfigurationProviderImpl @Inject constructor() : AppConfigurationProvider {
|
||||||
|
|
||||||
|
override fun isDebug(): Boolean = BuildConfig.BUILD_TYPE == "debug"
|
||||||
|
override fun isHuawei(): Boolean = BuildConfig.FLAVOR_NAME == "huawei"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
package com.tangem.tap.common.pushes
|
||||||
|
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import coil.executeBlocking
|
||||||
|
import coil.request.ImageRequest
|
||||||
|
import com.tangem.domain.common.LogConfig
|
||||||
|
import com.tangem.tap.MainActivity
|
||||||
|
import com.tangem.tap.common.images.createCoilImageLoader
|
||||||
|
import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler
|
||||||
|
import com.tangem.wallet.R
|
||||||
|
|
||||||
|
class PushNotificationDelegate(private val context: Context) {
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
|
fun showNotification(
|
||||||
|
dataMap: Map<String, String>,
|
||||||
|
title: String?,
|
||||||
|
body: String?,
|
||||||
|
channelId: String,
|
||||||
|
priority: Int,
|
||||||
|
imageUrl: Uri? = null,
|
||||||
|
vibratePattern: LongArray?,
|
||||||
|
) {
|
||||||
|
val intent = Intent(context, MainActivity::class.java).apply {
|
||||||
|
dataMap.forEach { (key, value) ->
|
||||||
|
putExtra(key, value)
|
||||||
|
}
|
||||||
|
putExtra(OnPushClickedIntentHandler.OPENED_FROM_GCM_PUSH, true)
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
}
|
||||||
|
|
||||||
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
|
/* context = */ context,
|
||||||
|
/* requestCode = */ PUSH_NOTIFICATION_REQUEST_CODE,
|
||||||
|
/* intent = */ intent,
|
||||||
|
/* flags = */ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE,
|
||||||
|
)
|
||||||
|
|
||||||
|
val notificationBuilder = NotificationCompat.Builder(context, channelId)
|
||||||
|
.setSmallIcon(R.drawable.ic_tangem_24)
|
||||||
|
.setContentTitle(title)
|
||||||
|
.setContentText(body)
|
||||||
|
.setPriority(priority)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setVibrate(vibratePattern)
|
||||||
|
.apply {
|
||||||
|
imageUrl?.let { uri ->
|
||||||
|
val bitmap = getBitmapImageFromUrl(uri)
|
||||||
|
setStyle(
|
||||||
|
NotificationCompat
|
||||||
|
.BigPictureStyle()
|
||||||
|
.bigPicture(bitmap),
|
||||||
|
).setLargeIcon(bitmap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val notificationChannel = NotificationChannel(
|
||||||
|
channelId,
|
||||||
|
ContextCompat.getString(context, R.string.tangem_app_name),
|
||||||
|
NotificationManager.IMPORTANCE_HIGH,
|
||||||
|
)
|
||||||
|
notificationManager.createNotificationChannel(notificationChannel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generating unique notification id
|
||||||
|
val uniqueId = (System.currentTimeMillis() % Integer.MAX_VALUE).toInt()
|
||||||
|
|
||||||
|
notificationManager.notify(
|
||||||
|
/* id = */ uniqueId,
|
||||||
|
/* notification = */ notificationBuilder.build(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBitmapImageFromUrl(url: Uri): Bitmap? {
|
||||||
|
return createCoilImageLoader(
|
||||||
|
context,
|
||||||
|
logEnabled = LogConfig.imageLoader,
|
||||||
|
).executeBlocking(
|
||||||
|
ImageRequest.Builder(context)
|
||||||
|
.data(url)
|
||||||
|
.build(),
|
||||||
|
).drawable?.toBitmap()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val PUSH_NOTIFICATION_REQUEST_CODE = 123
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,30 +1,17 @@
|
||||||
package com.tangem.tap.common.pushes
|
package com.tangem.tap.common.pushes
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.NotificationChannel
|
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
|
||||||
import coil.executeBlocking
|
|
||||||
import coil.request.ImageRequest
|
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService
|
import com.google.firebase.messaging.FirebaseMessagingService
|
||||||
import com.google.firebase.messaging.RemoteMessage
|
import com.google.firebase.messaging.RemoteMessage
|
||||||
import com.tangem.domain.common.LogConfig
|
|
||||||
import com.tangem.tap.MainActivity
|
|
||||||
import com.tangem.tap.common.images.createCoilImageLoader
|
|
||||||
import com.tangem.tap.features.intentHandler.handlers.OnPushClickedIntentHandler
|
|
||||||
import com.tangem.wallet.R
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
@SuppressLint("MissingFirebaseInstanceTokenRefresh")
|
@SuppressLint("MissingFirebaseInstanceTokenRefresh")
|
||||||
internal class TangemPushNotificationService : FirebaseMessagingService() {
|
internal class TangemPushNotificationService : FirebaseMessagingService() {
|
||||||
|
|
||||||
|
private val pushNotificationDelegate: PushNotificationDelegate by lazy {
|
||||||
|
PushNotificationDelegate(applicationContext)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onNewToken(token: String) {
|
override fun onNewToken(token: String) {
|
||||||
super.onNewToken(token)
|
super.onNewToken(token)
|
||||||
Timber.d("New FCM token received: $token")
|
Timber.d("New FCM token received: $token")
|
||||||
|
|
@ -36,73 +23,18 @@ internal class TangemPushNotificationService : FirebaseMessagingService() {
|
||||||
val notification = message.notification ?: return
|
val notification = message.notification ?: return
|
||||||
val channelId = notification.channelId ?: TANGEM_CHANNEL_ID
|
val channelId = notification.channelId ?: TANGEM_CHANNEL_ID
|
||||||
|
|
||||||
val intent = Intent(applicationContext, MainActivity::class.java).apply {
|
pushNotificationDelegate.showNotification(
|
||||||
message.data.forEach {
|
dataMap = message.data,
|
||||||
putExtra(it.key, it.value)
|
title = notification.title,
|
||||||
}
|
body = notification.body,
|
||||||
putExtra(OnPushClickedIntentHandler.OPENED_FROM_GCM_PUSH, true)
|
channelId = channelId,
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
priority = message.priority,
|
||||||
}
|
imageUrl = notification.imageUrl,
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
vibratePattern = notification.vibrateTimings,
|
||||||
/* context = */ this,
|
|
||||||
/* requestCode = */ PUSH_NOTIFICATION_REQUEST_CODE,
|
|
||||||
/* intent = */ intent,
|
|
||||||
/* flags = */ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val notificationBuilder =
|
|
||||||
NotificationCompat.Builder(applicationContext, channelId)
|
|
||||||
.setSmallIcon(R.drawable.ic_tangem_24)
|
|
||||||
.setContentTitle(notification.title)
|
|
||||||
.setContentText(notification.body)
|
|
||||||
.setPriority(message.priority)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.setVibrate(notification.vibrateTimings)
|
|
||||||
.apply {
|
|
||||||
notification.imageUrl?.let { uri ->
|
|
||||||
val bitmap = getBitmapImageFromUrl(uri)
|
|
||||||
setStyle(
|
|
||||||
NotificationCompat
|
|
||||||
.BigPictureStyle()
|
|
||||||
.bigPicture(bitmap),
|
|
||||||
).setLargeIcon(bitmap)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val notificationManager = applicationContext.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val notificationChannel = NotificationChannel(
|
|
||||||
channelId,
|
|
||||||
ContextCompat.getString(applicationContext, R.string.tangem_app_name),
|
|
||||||
NotificationManager.IMPORTANCE_HIGH,
|
|
||||||
)
|
|
||||||
notificationManager.createNotificationChannel(notificationChannel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generating unique notification id
|
|
||||||
val uniqueId = (System.currentTimeMillis() % Integer.MAX_VALUE).toInt()
|
|
||||||
|
|
||||||
notificationManager.notify(
|
|
||||||
/* id = */ uniqueId,
|
|
||||||
/* notification = */ notificationBuilder.build(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getBitmapImageFromUrl(url: Uri): Bitmap? {
|
|
||||||
return createCoilImageLoader(
|
|
||||||
applicationContext,
|
|
||||||
logEnabled = LogConfig.imageLoader,
|
|
||||||
).executeBlocking(
|
|
||||||
ImageRequest.Builder(applicationContext)
|
|
||||||
.data(url)
|
|
||||||
.build(),
|
|
||||||
).drawable?.toBitmap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val TANGEM_CHANNEL_ID = "Tangem General" // General channel for notifications
|
const val TANGEM_CHANNEL_ID = "Tangem General" // General channel for notifications
|
||||||
const val PUSH_NOTIFICATION_REQUEST_CODE = 123
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.tangem.tap.di
|
||||||
|
|
||||||
|
import com.tangem.tap.common.buildconfig.AppConfigurationProviderImpl
|
||||||
|
import com.tangem.utils.buildConfig.AppConfigurationProvider
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
internal interface AppConfigurationModule {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun bindAppConfigurationProvider(impl: AppConfigurationProviderImpl): AppConfigurationProvider
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,13 @@ plugins {
|
||||||
alias(deps.plugins.ksp) apply false
|
alias(deps.plugins.ksp) apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
dependencies {
|
||||||
|
classpath(deps.gradle.android)
|
||||||
|
classpath(deps.agconnect.agcp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val clean by tasks.registering {
|
val clean by tasks.registering {
|
||||||
delete(rootProject.buildDir)
|
delete(rootProject.buildDir)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.tangem.utils.buildConfig
|
||||||
|
|
||||||
|
interface AppConfigurationProvider {
|
||||||
|
fun isDebug(): Boolean
|
||||||
|
fun isHuawei(): Boolean
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,12 @@ ksp = "2.1.10-1.0.30"
|
||||||
firebasePerf = "1.4.2"
|
firebasePerf = "1.4.2"
|
||||||
# endregion Classpath
|
# endregion Classpath
|
||||||
|
|
||||||
|
# region AppGallery
|
||||||
|
agconnect = "1.9.1.304"
|
||||||
|
huaweiServices = "6.9.0.301"
|
||||||
|
huaweiPush = "6.11.0.300"
|
||||||
|
# endregion AppGallery
|
||||||
|
|
||||||
# region AndroidX
|
# region AndroidX
|
||||||
androidxActivityCompose = "1.8.0"
|
androidxActivityCompose = "1.8.0"
|
||||||
androidxAppCompat = "1.5.1"
|
androidxAppCompat = "1.5.1"
|
||||||
|
|
@ -130,6 +136,7 @@ detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
|
||||||
room = { id = "androidx.room", version.ref = "room" }
|
room = { id = "androidx.room", version.ref = "room" }
|
||||||
kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
||||||
|
agconnect = { id = "com.huawei.agconnect", version.ref = "agconnect" }
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
# region Classpath
|
# region Classpath
|
||||||
|
|
@ -190,6 +197,15 @@ firebase-messaging = { module = "com.google.firebase:firebase-messaging-ktx" }
|
||||||
firebase-perf = { module = "com.google.firebase:firebase-perf" }
|
firebase-perf = { module = "com.google.firebase:firebase-perf" }
|
||||||
# endregion Firebase
|
# endregion Firebase
|
||||||
|
|
||||||
|
# region AppGallery
|
||||||
|
agconnect-agcp = { module = "com.huawei.agconnect:agcp", version.ref = "agconnect" }
|
||||||
|
agconnect-core = { module = "com.huawei.agconnect:agconnect-core", version.ref = "agconnect" }
|
||||||
|
agconnect-crash = { module = "com.huawei.agconnect:agconnect-crash", version.ref = "agconnect" }
|
||||||
|
huawei-base = { module = "com.huawei.hms:base", version.ref = "huaweiServices" }
|
||||||
|
huawei-analytics = { module = "com.huawei.hms:hianalytics", version.ref = "huaweiServices" }
|
||||||
|
huawei-push = { module = "com.huawei.hms:push", version.ref = "huaweiPush" }
|
||||||
|
# endregion AppGallery
|
||||||
|
|
||||||
# region Detekt
|
# region Detekt
|
||||||
detekt-compose = { module = "ru.kode:detekt-rules-compose", version.ref = "detektComposeRules" }
|
detekt-compose = { module = "ru.kode:detekt-rules-compose", version.ref = "detektComposeRules" }
|
||||||
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
|
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ private fun AndroidBuildType.configureBuildVariant(appExtension: AppExtension, b
|
||||||
}
|
}
|
||||||
BuildType.Debug -> {
|
BuildType.Debug -> {
|
||||||
isDebuggable = true
|
isDebuggable = true
|
||||||
|
signingConfig = appExtension.signingConfigs.getByName(BuildType.Debug.id)
|
||||||
}
|
}
|
||||||
BuildType.Internal,
|
BuildType.Internal,
|
||||||
BuildType.External
|
BuildType.External
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ pluginManagement {
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url = uri("https://developer.huawei.com/repo/") }
|
||||||
}
|
}
|
||||||
|
|
||||||
includeBuild("plugins/configuration")
|
includeBuild("plugins/configuration")
|
||||||
|
|
@ -35,6 +36,7 @@ dependencyResolutionManagement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url = uri("https://developer.huawei.com/repo/") }
|
||||||
mavenLocal {
|
mavenLocal {
|
||||||
content {
|
content {
|
||||||
includeGroupAndSubgroups("com.tangem.tangem-sdk-kotlin")
|
includeGroupAndSubgroups("com.tangem.tangem-sdk-kotlin")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue