Skip to content

Commit 37f9110

Browse files
added updated URL
1 parent 354c530 commit 37f9110

7 files changed

Lines changed: 197 additions & 41 deletions

File tree

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ android {
1313
applicationId "com.kharagedition.tibetankeyboard"
1414
minSdkVersion 23
1515
targetSdkVersion 36
16-
versionCode 35
17-
versionName "2.1.5"
16+
versionCode 38
17+
versionName "2.1.8"
1818

1919
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
2020
multiDexEnabled true

app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
<uses-permission android:name="android.permission.INTERNET" />
77
<uses-permission android:name="android.permission.VIBRATE" />
88
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
9+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
10+
<uses-permission android:name="android.permission.WAKE_LOCK" />
11+
912

1013
<application
1114
android:name=".TibetanKeyboardApp"

app/src/main/java/com/kharagedition/tibetankeyboard/MyFirebaseMessagingService.kt

Lines changed: 174 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,53 @@ import com.google.firebase.messaging.RemoteMessage
1616

1717
class MyFirebaseMessagingService : FirebaseMessagingService() {
1818

19+
companion object {
20+
private const val TAG = "FCMService"
21+
private const val CHANNEL_ID = "app_update_channel"
22+
private const val NOTIFICATION_ID = 1001
23+
}
24+
1925
override fun onMessageReceived(remoteMessage: RemoteMessage) {
2026
super.onMessageReceived(remoteMessage)
2127

22-
// Check if message contains data payload for update notification
23-
remoteMessage.data.isNotEmpty().let {
24-
if (remoteMessage.data["type"] == "app_update") {
25-
handleUpdateNotification(remoteMessage.data)
28+
Log.d(TAG, "Message received from: ${remoteMessage.from}")
29+
30+
// Handle both notification and data payloads
31+
// This ensures the notification works in all app states
32+
33+
// Check if message contains a notification payload (background/terminated state)
34+
remoteMessage.notification?.let {
35+
Log.d(TAG, "Notification Title: ${it.title}")
36+
Log.d(TAG, "Notification Body: ${it.body}")
37+
38+
// When app is in background/terminated, system handles notification
39+
// but we can still process data payload
40+
if (remoteMessage.data.isNotEmpty()) {
41+
handleDataPayload(remoteMessage.data)
42+
}
43+
}
44+
45+
// Check if message contains a data payload (foreground state)
46+
if (remoteMessage.data.isNotEmpty()) {
47+
Log.d(TAG, "Data Payload: ${remoteMessage.data}")
48+
49+
// When app is in foreground, we must manually show notification
50+
if (isAppInForeground()) {
51+
handleDataPayload(remoteMessage.data)
52+
}
53+
}
54+
}
55+
56+
private fun handleDataPayload(data: Map<String, String>) {
57+
val type = data["type"]
58+
59+
when (type) {
60+
"app_update" -> handleUpdateNotification(data)
61+
"general" -> handleGeneralNotification(data)
62+
else -> {
63+
// Handle unknown notification types
64+
Log.w(TAG, "Unknown notification type: $type")
65+
handleGeneralNotification(data)
2666
}
2767
}
2868
}
@@ -31,46 +71,57 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
3171
val title = data["title"] ?: "Update Available"
3272
val message = data["message"] ?: "A new version of the app is available"
3373
val version = data["version"] ?: ""
74+
val updateUrl = data["update_url"] // Optional custom URL
75+
76+
showUpdateNotification(title, message, version, updateUrl)
77+
}
78+
79+
private fun handleGeneralNotification(data: Map<String, String>) {
80+
val title = data["title"] ?: "Notification"
81+
val message = data["message"] ?: ""
3482

35-
showUpdateNotification(title, message, version)
83+
showGeneralNotification(title, message)
3684
}
3785

38-
private fun showUpdateNotification(title: String, message: String, version: String) {
86+
private fun showUpdateNotification(
87+
title: String,
88+
message: String,
89+
version: String,
90+
customUrl: String? = null
91+
) {
3992
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
40-
val channelId = "app_update_channel"
4193

42-
// Create notification channel (for Android O and above)
43-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
44-
val channel = NotificationChannel(
45-
channelId,
46-
"App Updates",
47-
NotificationManager.IMPORTANCE_HIGH
48-
).apply {
49-
description = "Notifications for app updates"
50-
enableLights(true)
51-
lightColor = Color.BLUE
52-
enableVibration(true)
53-
}
54-
notificationManager.createNotificationChannel(channel)
94+
createNotificationChannel(notificationManager)
95+
96+
// Create intent to open Play Store or custom URL
97+
val intent = if (customUrl != null) {
98+
createCustomUrlIntent(customUrl)
99+
} else {
100+
createPlayStoreIntent()
55101
}
56102

57-
// Create intent to open Play Store
58-
val playStoreIntent = createPlayStoreIntent()
59103
val pendingIntent = PendingIntent.getActivity(
60104
this,
61105
0,
62-
playStoreIntent,
106+
intent,
63107
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
64108
)
65109

66-
// Build notification
67-
val notification = NotificationCompat.Builder(this, channelId)
68-
.setSmallIcon(R.drawable.ic_update) // Add your update icon
110+
// Build notification with full details
111+
val fullMessage = if (version.isNotEmpty()) {
112+
"$message\nVersion: $version"
113+
} else {
114+
message
115+
}
116+
117+
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
118+
.setSmallIcon(R.drawable.ic_update)
69119
.setContentTitle(title)
70120
.setContentText(message)
71-
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
121+
.setStyle(NotificationCompat.BigTextStyle().bigText(fullMessage))
72122
.setAutoCancel(true)
73123
.setPriority(NotificationCompat.PRIORITY_HIGH)
124+
.setDefaults(NotificationCompat.DEFAULT_ALL)
74125
.setContentIntent(pendingIntent)
75126
.addAction(
76127
R.drawable.ic_download,
@@ -79,30 +130,118 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
79130
)
80131
.build()
81132

82-
notificationManager.notify(1001, notification)
133+
notificationManager.notify(NOTIFICATION_ID, notification)
134+
}
135+
136+
private fun showGeneralNotification(title: String, message: String) {
137+
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
138+
139+
createNotificationChannel(notificationManager)
140+
141+
// Create intent to open the app
142+
val intent = packageManager.getLaunchIntentForPackage(packageName)?.apply {
143+
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
144+
}
145+
146+
val pendingIntent = PendingIntent.getActivity(
147+
this,
148+
0,
149+
intent,
150+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
151+
)
152+
153+
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
154+
.setSmallIcon(R.drawable.ic_notification)
155+
.setContentTitle(title)
156+
.setContentText(message)
157+
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
158+
.setAutoCancel(true)
159+
.setPriority(NotificationCompat.PRIORITY_HIGH)
160+
.setDefaults(NotificationCompat.DEFAULT_ALL)
161+
.setContentIntent(pendingIntent)
162+
.build()
163+
164+
notificationManager.notify(NOTIFICATION_ID + 1, notification)
165+
}
166+
167+
private fun createNotificationChannel(notificationManager: NotificationManager) {
168+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
169+
val channel = NotificationChannel(
170+
CHANNEL_ID,
171+
"App Updates & Notifications",
172+
NotificationManager.IMPORTANCE_HIGH
173+
).apply {
174+
description = "Notifications for app updates and important messages"
175+
enableLights(true)
176+
lightColor = Color.BLUE
177+
enableVibration(true)
178+
setShowBadge(true)
179+
}
180+
notificationManager.createNotificationChannel(channel)
181+
}
83182
}
84183

85184
private fun createPlayStoreIntent(): Intent {
86185
val packageName = packageName
87186

88-
// Try to open Play Store app first
89187
return try {
90-
Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$packageName"))
188+
Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$packageName")).apply {
189+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
190+
}
91191
} catch (e: ActivityNotFoundException) {
92-
// Fallback to Play Store website
93-
Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=$packageName"))
192+
Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=$packageName")).apply {
193+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
194+
}
195+
}
196+
}
197+
198+
private fun createCustomUrlIntent(url: String): Intent {
199+
return Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
200+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
201+
}
202+
}
203+
204+
private fun isAppInForeground(): Boolean {
205+
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as android.app.ActivityManager
206+
val appProcesses = activityManager.runningAppProcesses ?: return false
207+
208+
return appProcesses.any {
209+
it.importance == android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
210+
&& it.processName == packageName
94211
}
95212
}
96213

97214
override fun onNewToken(token: String) {
98215
super.onNewToken(token)
216+
Log.d(TAG, "New FCM token: $token")
217+
99218
// Send token to your server
100219
sendTokenToServer(token)
220+
221+
// Store token locally
222+
saveTokenLocally(token)
101223
}
102224

103225
private fun sendTokenToServer(token: String) {
104-
// Implement your server communication here
105-
// This is where you'd send the FCM token to your backend
106-
Log.d("FCM", "New token: $token")
226+
// TODO: Implement your server communication here
227+
// Example: Use Retrofit or OkHttp to send token to your backend
228+
Log.d(TAG, "Sending token to server: $token")
229+
230+
// Example implementation:
231+
// RetrofitClient.instance.updateFcmToken(token)
232+
// .enqueue(object : Callback<Response> {
233+
// override fun onResponse(call: Call<Response>, response: Response<Response>) {
234+
// Log.d(TAG, "Token sent successfully")
235+
// }
236+
// override fun onFailure(call: Call<Response>, t: Throwable) {
237+
// Log.e(TAG, "Failed to send token", t)
238+
// }
239+
// })
240+
}
241+
242+
private fun saveTokenLocally(token: String) {
243+
val sharedPreferences = getSharedPreferences("FCM_PREFS", Context.MODE_PRIVATE)
244+
sharedPreferences.edit().putString("FCM_TOKEN", token).apply()
245+
Log.d(TAG, "Token saved locally")
107246
}
108247
}

app/src/main/java/com/kharagedition/tibetankeyboard/ui/ChatActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ class ChatActivity : AppCompatActivity(), RevenueCatManager.SubscriptionCallback
299299
return
300300
premiumAlertDialog = MaterialAlertDialogBuilder(this)
301301
.setTitle("Premium Required")
302-
.setMessage("This feature is available only for Premium users.\n\nUpgrade now to unlock all features!\n1.AI Chat\n2.Google Translate\n3.Tibetan Icon\n4.Ad-free Experience\n5.Priority Support")
302+
.setMessage("This feature is available only for Premium users.\n\nUpgrade now to unlock all features!\n1.AI Chat\n2.Google Translate\n3.Ad-free Experience\n4.Priority Support")
303303
.setIcon(R.drawable.baseline_generating_tokens_24)
304304
.setPositiveButton("Upgrade") { dialog, _ ->
305305

app/src/main/java/com/kharagedition/tibetankeyboard/ui/HomeActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class HomeActivity : InputMethodActivity() {
7373
}
7474

7575
private fun subscribeToAllUsersTopic() {
76-
FirebaseMessaging.getInstance().subscribeToTopic("all-users")
76+
FirebaseMessaging.getInstance().subscribeToTopic("test-users")
7777
.addOnCompleteListener { task ->
7878
var msg = "Subscribed to all-users topic"
7979
if (!task.isSuccessful) {
@@ -244,7 +244,7 @@ class HomeActivity : InputMethodActivity() {
244244
isPremiumUser = isPremium;
245245
if (authManager.isUserAuthenticated() && isPremium) {
246246
homeBinding.nativeAdsLayout.visibility = GONE
247-
homeBinding.bottomBtnLayout.visibility = VISIBLE
247+
homeBinding.bottomBtnLayout.visibility = GONE // For now
248248
/* homeBinding.chatIcon.setColorFilter(getColor(R.color.premium_yellow))
249249
homeBinding.shareIcon.setColorFilter(getColor(R.color.premium_yellow))
250250
homeBinding.rateIcon.setColorFilter(getColor(R.color.premium_yellow))
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!-- res/drawable/ic_notification.xml -->
2+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:width="24dp"
4+
android:height="24dp"
5+
android:viewportWidth="24"
6+
android:viewportHeight="24"
7+
android:tint="@android:color/white">
8+
9+
<!-- Notification bell shape -->
10+
<path
11+
android:fillColor="@android:color/white"
12+
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM18,16v-5c0,-3.07 -1.63,-5.64 -4.5,-6.32V4c0,-0.83 -0.67,-1.5 -1.5,-1.5S10.5,3.17 10.5,4v0.68C7.63,5.36 6,7.92 6,11v5l-1.7,1.7c-0.14,0.14 -0.3,0.3 -0.3,0.6 0,0.5 0.4,0.7 0.8,0.7h14.4c0.4,0 0.8,-0.2 0.8,-0.7 0,-0.3 -0.16,-0.46 -0.3,-0.6L18,16z"/>
13+
</vector>

app/src/main/res/layout/activity_home.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,8 @@
479479
android:scrollHorizontally="true"
480480
android:text="Manage Subscription"
481481
android:textColor="@color/white"
482-
android:textSize="16sp" />
482+
android:textSize="16sp"
483+
android:visibility="gone"/>
483484
</LinearLayout>
484485

485486
</com.google.android.material.card.MaterialCardView>

0 commit comments

Comments
 (0)