update minSdk to 26

This commit is contained in:
Phillip Thelen 2025-01-31 11:59:41 +01:00
parent 2638001513
commit 6d062aa7b6
39 changed files with 136 additions and 345 deletions

View file

@ -156,12 +156,8 @@ abstract class HabiticaBaseApplication : Application(), Application.ActivityLife
val resources = resources val resources = resources
val configuration: Configuration = resources.configuration val configuration: Configuration = resources.configuration
val languageHelper = LanguageHelper(sharedPrefs.getString("language", "en")) val languageHelper = LanguageHelper(sharedPrefs.getString("language", "en"))
if (if (SDK_INT >= Build.VERSION_CODES.N) { if (
configuration.locales.isEmpty || configuration.locales[0] != languageHelper.locale configuration.locales.isEmpty || configuration.locales[0] != languageHelper.locale
} else {
@Suppress("DEPRECATION")
configuration.locale != languageHelper.locale
}
) { ) {
configuration.setLocale(languageHelper.locale) configuration.setLocale(languageHelper.locale)
resources.updateConfiguration(configuration, null) resources.updateConfiguration(configuration, null)

View file

@ -1,20 +0,0 @@
package com.habitrpg.android.habitica.extensions
import android.app.PendingIntent
import android.os.Build
fun withImmutableFlag(flags: Int): Int {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
flags + PendingIntent.FLAG_IMMUTABLE
} else {
flags
}
}
fun withMutableFlag(flags: Int): Int {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
flags + PendingIntent.FLAG_MUTABLE
} else {
flags
}
}

View file

@ -15,9 +15,7 @@ fun Resources.forceLocale(
Locale.setDefault(locale) Locale.setDefault(locale)
val configuration = Configuration() val configuration = Configuration()
configuration.setLocale(locale) configuration.setLocale(locale)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { activity.createConfigurationContext(configuration)
activity.createConfigurationContext(configuration)
}
updateConfiguration(configuration, displayMetrics) updateConfiguration(configuration, displayMetrics)
try { try {

View file

@ -13,12 +13,8 @@ fun Window.updateStatusBarColor(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return return
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { statusBarColor = color
statusBarColor = color @Suppress("DEPRECATION")
@Suppress("DEPRECATION") decorView.systemUiVisibility =
decorView.systemUiVisibility = if (isLight) View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR else View.SYSTEM_UI_FLAG_VISIBLE
if (isLight) View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR else View.SYSTEM_UI_FLAG_VISIBLE
} else {
statusBarColor = context.getThemeColor(R.attr.colorPrimaryDark)
}
} }

View file

@ -7,7 +7,6 @@ import android.content.Intent
import android.os.Build import android.os.Build
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.habitrpg.android.habitica.data.TaskRepository import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.models.tasks.RemindersItem import com.habitrpg.android.habitica.models.tasks.RemindersItem
import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.modules.AuthenticationHandler import com.habitrpg.android.habitica.modules.AuthenticationHandler
@ -166,7 +165,7 @@ class TaskAlarmManager(
context, context,
intentId, intentId,
intent, intent,
withImmutableFlag(PendingIntent.FLAG_NO_CREATE) PendingIntent.FLAG_NO_CREATE + PendingIntent.FLAG_IMMUTABLE
) )
if (previousSender != null) { if (previousSender != null) {
previousSender.cancel() previousSender.cancel()
@ -178,7 +177,7 @@ class TaskAlarmManager(
context, context,
intentId, intentId,
intent, intent,
withImmutableFlag(PendingIntent.FLAG_CANCEL_CURRENT) PendingIntent.FLAG_CANCEL_CURRENT + PendingIntent.FLAG_IMMUTABLE
) )
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
@ -209,7 +208,7 @@ class TaskAlarmManager(
context, context,
intentId, intentId,
intent, intent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABE
) )
val am = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager val am = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
sender.cancel() sender.cancel()
@ -250,7 +249,7 @@ class TaskAlarmManager(
context, context,
0, 0,
notificationIntent, notificationIntent,
withImmutableFlag(PendingIntent.FLAG_NO_CREATE) PendingIntent.FLAG_NO_CREATE + PendingIntent.FLAG_IMMUTABLE
) )
if (previousSender != null) { if (previousSender != null) {
previousSender.cancel() previousSender.cancel()
@ -262,7 +261,7 @@ class TaskAlarmManager(
context, context,
0, 0,
notificationIntent, notificationIntent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABE
) )
setAlarm(context, triggerTime, pendingIntent) setAlarm(context, triggerTime, pendingIntent)
@ -273,7 +272,7 @@ class TaskAlarmManager(
val notificationIntent = Intent(context, NotificationPublisher::class.java) val notificationIntent = Intent(context, NotificationPublisher::class.java)
val alarmManager = context?.getSystemService(Context.ALARM_SERVICE) as? AlarmManager val alarmManager = context?.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
val displayIntent = val displayIntent =
PendingIntent.getBroadcast(context, 0, notificationIntent, withImmutableFlag(0)) PendingIntent.getBroadcast(context, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE)
alarmManager?.cancel(displayIntent) alarmManager?.cancel(displayIntent)
} }
@ -289,45 +288,41 @@ class TaskAlarmManager(
} }
val notificationType = AlarmManager.RTC_WAKEUP val notificationType = AlarmManager.RTC_WAKEUP
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { try {
try { var canScheduleExact = true
var canScheduleExact = true if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { canScheduleExact = alarmManager.canScheduleExactAlarms()
canScheduleExact = alarmManager.canScheduleExactAlarms() }
} if (canScheduleExact) {
if (canScheduleExact) { alarmManager.setExactAndAllowWhileIdle(notificationType, time, pendingIntent)
alarmManager.setExactAndAllowWhileIdle(notificationType, time, pendingIntent) HLogger.log(
HLogger.log( LogLevel.DEBUG,
LogLevel.DEBUG, "TaskAlarmManager",
"TaskAlarmManager", "setAlarm: Scheduling for $time using setExact ${Date().time}"
"setAlarm: Scheduling for $time using setExact ${Date().time}" )
) } else {
} else { alarmManager.setAndAllowWhileIdle(notificationType, time, pendingIntent)
alarmManager.setAndAllowWhileIdle(notificationType, time, pendingIntent) HLogger.log(
HLogger.log( LogLevel.DEBUG,
LogLevel.DEBUG, "TaskAlarmManager",
"TaskAlarmManager", "setAlarm: Scheduling for $time using setAndAllowWhileIdle"
"setAlarm: Scheduling for $time using setAndAllowWhileIdle" )
}
} catch (ex: Exception) {
when (ex) {
is IllegalStateException, is SecurityException -> {
alarmManager.setWindow(
notificationType,
time,
600000,
pendingIntent
) )
} }
} catch (ex: Exception) {
when (ex) {
is IllegalStateException, is SecurityException -> {
alarmManager.setWindow(
notificationType,
time,
600000,
pendingIntent
)
}
else -> { else -> {
throw ex throw ex
}
} }
} }
} else {
alarmManager.set(notificationType, time, pendingIntent)
} }
} }
} }

View file

@ -130,12 +130,8 @@ class TaskDescriptionBuilder(private val context: Context) {
} }
private fun withOrdinal(day: Int): String { private fun withOrdinal(day: Int): String {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { val formatter = MessageFormat("{0,ordinal}", LanguageHelper.systemLocale)
val formatter = MessageFormat("{0,ordinal}", LanguageHelper.systemLocale) return formatter.format(arrayOf(day))
formatter.format(arrayOf(day))
} else {
day.toString()
}
} }
private fun describeRepeatInterval( private fun describeRepeatInterval(

View file

@ -11,7 +11,6 @@ import androidx.core.app.Person
import androidx.core.app.RemoteInput import androidx.core.app.RemoteInput
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.withMutableFlag
import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver
import com.habitrpg.common.habitica.helpers.EmojiParser import com.habitrpg.common.habitica.helpers.EmojiParser
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -35,11 +34,7 @@ class GroupActivityNotification(context: Context, identifier: String?) :
val notificationManager = val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
val existingNotifications = val existingNotifications =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { notificationManager?.activeNotifications?.filter { it.id == getNotificationID(data) }
notificationManager?.activeNotifications?.filter { it.id == getNotificationID(data) }
} else {
null
}
val oldMessages = val oldMessages =
existingNotifications?.firstOrNull()?.notification?.extras?.getBundle("messages") existingNotifications?.firstOrNull()?.notification?.extras?.getBundle("messages")
?.get("messages") as? ArrayList<Map<String, String>> ?: arrayListOf() ?.get("messages") as? ArrayList<Map<String, String>> ?: arrayListOf()
@ -89,7 +84,7 @@ class GroupActivityNotification(context: Context, identifier: String?) :
context, context,
groupID.hashCode(), groupID.hashCode(),
intent, intent,
withMutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_MUTABLE
) )
val action: NotificationCompat.Action = val action: NotificationCompat.Action =

View file

@ -4,12 +4,8 @@ import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver
/**
* Created by keithholliday on 7/1/16.
*/
class GuildInviteLocalNotification(context: Context, identifier: String?) : class GuildInviteLocalNotification(context: Context, identifier: String?) :
HabiticaLocalNotification(context, identifier) { HabiticaLocalNotification(context, identifier) {
override fun configureMainIntent(intent: Intent) { override fun configureMainIntent(intent: Intent) {
@ -34,7 +30,7 @@ class GuildInviteLocalNotification(context: Context, identifier: String?) :
context, context,
groupID.hashCode(), groupID.hashCode(),
acceptInviteIntent, acceptInviteIntent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE
) )
notificationBuilder.addAction(0, "Accept", pendingIntentAccept) notificationBuilder.addAction(0, "Accept", pendingIntentAccept)
@ -47,7 +43,7 @@ class GuildInviteLocalNotification(context: Context, identifier: String?) :
context, context,
groupID.hashCode() + 1, groupID.hashCode() + 1,
rejectInviteIntent, rejectInviteIntent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE
) )
notificationBuilder.addAction(0, "Reject", pendingIntentReject) notificationBuilder.addAction(0, "Reject", pendingIntentReject)
} }

View file

@ -9,7 +9,6 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.activities.MainActivity
import java.util.Date import java.util.Date
@ -81,7 +80,7 @@ abstract class HabiticaLocalNotification(
context, context,
3000, 3000,
intent, intent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABE
) )
notificationBuilder.setContentIntent(pendingIntent) notificationBuilder.setContentIntent(pendingIntent)
} }

View file

@ -4,12 +4,8 @@ import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver
/**
* Created by keithholliday on 6/28/16.
*/
class PartyInviteLocalNotification(context: Context, identifier: String?) : class PartyInviteLocalNotification(context: Context, identifier: String?) :
HabiticaLocalNotification(context, identifier) { HabiticaLocalNotification(context, identifier) {
override fun setNotificationActions( override fun setNotificationActions(
@ -29,7 +25,7 @@ class PartyInviteLocalNotification(context: Context, identifier: String?) :
context, context,
groupID.hashCode(), groupID.hashCode(),
acceptInviteIntent, acceptInviteIntent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE
) )
notificationBuilder.addAction(0, context.getString(R.string.accept), pendingIntentAccept) notificationBuilder.addAction(0, context.getString(R.string.accept), pendingIntentAccept)
@ -42,7 +38,7 @@ class PartyInviteLocalNotification(context: Context, identifier: String?) :
context, context,
groupID.hashCode() + 1, groupID.hashCode() + 1,
rejectInviteIntent, rejectInviteIntent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE
) )
notificationBuilder.addAction(0, context.getString(R.string.reject), pendingIntentReject) notificationBuilder.addAction(0, context.getString(R.string.reject), pendingIntentReject)
} }

View file

@ -2,8 +2,5 @@ package com.habitrpg.android.habitica.helpers.notifications
import android.content.Context import android.content.Context
/**
* Created by keithholliday on 7/1/16.
*/
class QuestBegunLocalNotification(context: Context, identifier: String?) : class QuestBegunLocalNotification(context: Context, identifier: String?) :
HabiticaLocalNotification(context, identifier) HabiticaLocalNotification(context, identifier)

View file

@ -7,9 +7,6 @@ import android.os.Build
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver
/**
* Created by keithholliday on 7/1/16.
*/
class QuestInviteLocalNotification(context: Context, identifier: String?) : class QuestInviteLocalNotification(context: Context, identifier: String?) :
HabiticaLocalNotification(context, identifier) { HabiticaLocalNotification(context, identifier) {
override fun getNotificationID(data: MutableMap<String, String>): Int { override fun getNotificationID(data: MutableMap<String, String>): Int {
@ -27,11 +24,7 @@ class QuestInviteLocalNotification(context: Context, identifier: String?) :
acceptInviteIntent.action = res.getString(R.string.accept_quest_invite) acceptInviteIntent.action = res.getString(R.string.accept_quest_invite)
acceptInviteIntent.putExtra("NOTIFICATION_ID", notificationId) acceptInviteIntent.putExtra("NOTIFICATION_ID", notificationId)
val flags = val flags =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE
PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
val pendingIntentAccept = val pendingIntentAccept =
PendingIntent.getBroadcast( PendingIntent.getBroadcast(
context, context,

View file

@ -2,8 +2,5 @@ package com.habitrpg.android.habitica.helpers.notifications
import android.content.Context import android.content.Context
/**
* Created by keithholliday on 7/1/16.
*/
class ReceivedGemsGiftLocalNotification(context: Context, identifier: String?) : class ReceivedGemsGiftLocalNotification(context: Context, identifier: String?) :
HabiticaLocalNotification(context, identifier) HabiticaLocalNotification(context, identifier)

View file

@ -10,7 +10,6 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.RemoteInput import androidx.core.app.RemoteInput
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.withMutableFlag
import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver
import com.habitrpg.common.habitica.helpers.EmojiParser import com.habitrpg.common.habitica.helpers.EmojiParser
@ -20,11 +19,7 @@ class ReceivedPrivateMessageLocalNotification(context: Context, identifier: Stri
val notificationManager = val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
val existingNotifications = val existingNotifications =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { notificationManager?.activeNotifications?.filter { it.id == getNotificationID(data) }
notificationManager?.activeNotifications?.filter { it.id == getNotificationID(data) }
} else {
null
}
val messageText = EmojiParser.parseEmojis(data["message"]?.trim { it <= ' ' }) val messageText = EmojiParser.parseEmojis(data["message"]?.trim { it <= ' ' })
val oldMessages = val oldMessages =
existingNotifications?.firstOrNull()?.notification?.extras?.getStringArrayList("messages") existingNotifications?.firstOrNull()?.notification?.extras?.getStringArrayList("messages")
@ -100,7 +95,7 @@ class ReceivedPrivateMessageLocalNotification(context: Context, identifier: Stri
context, context,
senderID.hashCode(), senderID.hashCode(),
intent, intent,
withMutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_MUTABLE
) )
val action: NotificationCompat.Action = val action: NotificationCompat.Action =

View file

@ -2,8 +2,5 @@ package com.habitrpg.android.habitica.helpers.notifications
import android.content.Context import android.content.Context
/**
* Created by keithholliday on 7/1/16.
*/
class ReceivedSubscriptionGiftLocalNotification(context: Context, identifier: String?) : class ReceivedSubscriptionGiftLocalNotification(context: Context, identifier: String?) :
HabiticaLocalNotification(context, identifier) HabiticaLocalNotification(context, identifier)

View file

@ -13,7 +13,6 @@ import androidx.core.content.edit
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.TaskRepository import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.helpers.TaskAlarmManager import com.habitrpg.android.habitica.helpers.TaskAlarmManager
import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.common.habitica.helpers.launchCatching import com.habitrpg.common.habitica.helpers.launchCatching
@ -142,7 +141,7 @@ class NotificationPublisher : BroadcastReceiver() {
thisContext, thisContext,
0, 0,
notificationIntent, notificationIntent,
withImmutableFlag(0) PendingIntent.FLAG_IMMUTABLE
) )
builder.setContentIntent(intent) builder.setContentIntent(intent)

View file

@ -15,7 +15,6 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.TaskRepository import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.helpers.TaskAlarmManager import com.habitrpg.android.habitica.helpers.TaskAlarmManager
import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.activities.MainActivity
@ -73,7 +72,7 @@ class TaskReceiver : BroadcastReceiver() {
context, context,
System.currentTimeMillis().toInt(), System.currentTimeMillis().toInt(),
intent, intent,
withImmutableFlag(0) PendingIntent.FLAG_IMMUTABLE
) )
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
@ -91,9 +90,7 @@ class TaskReceiver : BroadcastReceiver() {
.setAutoCancel(true) .setAutoCancel(true)
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { notificationBuilder = notificationBuilder.setCategory(Notification.CATEGORY_REMINDER)
notificationBuilder = notificationBuilder.setCategory(Notification.CATEGORY_REMINDER)
}
if (task.type == TaskType.DAILY || task.type == TaskType.TODO) { if (task.type == TaskType.DAILY || task.type == TaskType.TODO) {
val completeIntent = val completeIntent =
@ -107,7 +104,7 @@ class TaskReceiver : BroadcastReceiver() {
context, context,
task.id.hashCode(), task.id.hashCode(),
completeIntent, completeIntent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABE
) )
notificationBuilder.addAction( notificationBuilder.addAction(
0, 0,

View file

@ -87,9 +87,7 @@ class AdventureGuideActivity : BaseActivity() {
val completed = achievements.count { it.earned } val completed = achievements.count { it.earned }
binding.progressBar.max = achievements.size binding.progressBar.max = achievements.size
binding.progressBar.progress = completed binding.progressBar.progress = completed
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { binding.progressBar.progressBackgroundTintMode = PorterDuff.Mode.SRC_OVER
binding.progressBar.progressBackgroundTintMode = PorterDuff.Mode.SRC_OVER
}
if (completed > 0) { if (completed > 0) {
binding.progressTextview.text = binding.progressTextview.text =

View file

@ -186,10 +186,8 @@ class LoginActivity : BaseActivity() {
private fun configureForRegistering() { private fun configureForRegistering() {
binding.submitButton.text = getString(R.string.register_btn) binding.submitButton.text = getString(R.string.register_btn)
binding.username.setHint(R.string.username) binding.username.setHint(R.string.username)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { binding.username.setAutofillHints("newUsername")
binding.username.setAutofillHints("newUsername") binding.password.setAutofillHints("newPassword")
binding.password.setAutofillHints("newPassword")
}
binding.password.imeOptions = EditorInfo.IME_ACTION_NEXT binding.password.imeOptions = EditorInfo.IME_ACTION_NEXT
binding.googleLoginButton.setText(R.string.register_btn_google) binding.googleLoginButton.setText(R.string.register_btn_google)
@ -199,10 +197,8 @@ class LoginActivity : BaseActivity() {
private fun configureForLogin() { private fun configureForLogin() {
binding.submitButton.text = getString(R.string.login_btn) binding.submitButton.text = getString(R.string.login_btn)
binding.username.setHint(R.string.email_username) binding.username.setHint(R.string.email_username)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { binding.username.setAutofillHints("username")
binding.username.setAutofillHints("username") binding.password.setAutofillHints("password")
binding.password.setAutofillHints("password")
}
binding.password.imeOptions = EditorInfo.IME_ACTION_DONE binding.password.imeOptions = EditorInfo.IME_ACTION_DONE
binding.googleLoginButton.setText(R.string.login_btn_google) binding.googleLoginButton.setText(R.string.login_btn_google)
this.resetLayout() this.resetLayout()
@ -409,9 +405,7 @@ class LoginActivity : BaseActivity() {
private fun onForgotPasswordClicked() { private fun onForgotPasswordClicked() {
val input = EditText(this) val input = EditText(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { input.setAutofillHints(EditText.AUTOFILL_HINT_EMAIL_ADDRESS)
input.setAutofillHints(EditText.AUTOFILL_HINT_EMAIL_ADDRESS)
}
input.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS input.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
input.hint = getString(R.string.forgot_password_hint_example) input.hint = getString(R.string.forgot_password_hint_example)
input.textSize = 16f input.textSize = 16f

View file

@ -114,6 +114,7 @@ import java.util.Date
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.DurationUnit import kotlin.time.DurationUnit
import kotlin.time.toDuration import kotlin.time.toDuration
import androidx.core.view.isVisible
var mainActivityCreatedAt: Date? = null var mainActivityCreatedAt: Date? = null
@ -458,22 +459,20 @@ open class MainActivity : BaseActivity(), SnackbarActivity {
} }
private fun setupNotifications() { private fun setupNotifications() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channelId = "default"
val channelId = "default" val channel =
val channel = NotificationChannel(
NotificationChannel( channelId,
channelId, "Habitica Notifications",
"Habitica Notifications", NotificationManager.IMPORTANCE_DEFAULT
NotificationManager.IMPORTANCE_DEFAULT )
) val manager = getSystemService(NotificationManager::class.java)
val manager = getSystemService(NotificationManager::class.java) manager?.createNotificationChannel(channel)
manager?.createNotificationChannel(channel)
}
} }
private fun setupBottomnavigationLayoutListener() { private fun setupBottomnavigationLayoutListener() {
binding.content.bottomNavigation.viewTreeObserver.addOnGlobalLayoutListener { binding.content.bottomNavigation.viewTreeObserver.addOnGlobalLayoutListener {
if (binding.content.bottomNavigation.visibility == View.VISIBLE) { if (binding.content.bottomNavigation.isVisible) {
snackbarContainer.setPadding( snackbarContainer.setPadding(
0, 0,
0, 0,

View file

@ -118,32 +118,17 @@ class ReportMessageActivity : BaseActivity() {
private fun setStatusBarDim(dim: Boolean) { private fun setStatusBarDim(dim: Boolean) {
if (dim) { if (dim) {
binding.appbar.elevation = 0f binding.appbar.elevation = 0f
window.statusBarColor = getThemeColor(R.attr.colorPrimaryDark)
binding.closeButton.visibility = View.GONE binding.closeButton.visibility = View.GONE
binding.toolbarTitle.setTypeface(null, Typeface.BOLD) binding.toolbarTitle.setTypeface(null, Typeface.BOLD)
} else { } else {
binding.appbar.elevation = 8f binding.appbar.elevation = 8f
window.statusBarColor = ContextCompat.getColor(this, R.color.offset_background)
binding.closeButton.visibility = View.VISIBLE binding.closeButton.visibility = View.VISIBLE
binding.toolbarTitle.setTypeface(null, Typeface.NORMAL) binding.toolbarTitle.setTypeface(null, Typeface.NORMAL)
} }
if (Build.VERSION.SDK_INT >= VERSION_CODES.M) {
setSystemBarTheme(dim)
}
} }
override fun finish() { override fun finish() {
dismissKeyboard() dismissKeyboard()
super.finish() super.finish()
} }
@RequiresApi(api = VERSION_CODES.M)
fun setSystemBarTheme(isDark: Boolean) {
// Fetch the current flags.
val lFlags = window.decorView.systemUiVisibility
// Update the SystemUiVisibility dependening on whether we want a Light or Dark theme.
window.decorView.systemUiVisibility =
if (isDark) lFlags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() else lFlags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
} }

View file

@ -135,13 +135,9 @@ class TaskFormActivity : BaseActivity() {
alert.setMessage(R.string.push_notification_system_settings_description) alert.setMessage(R.string.push_notification_system_settings_description)
alert.addButton(R.string.settings, isPrimary = true, isDestructive = false) { _, _ -> alert.addButton(R.string.settings, isPrimary = true, isDestructive = false) { _, _ ->
val notifSettingIntent: Intent = val notifSettingIntent: Intent =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .putExtra(Settings.EXTRA_APP_PACKAGE, applicationContext?.packageName)
.putExtra(Settings.EXTRA_APP_PACKAGE, applicationContext?.packageName)
} else {
return@addButton
}
startActivity(notifSettingIntent) startActivity(notifSettingIntent)
} }
alert.addButton(R.string.cancel, false) { _, _ -> alert.addButton(R.string.cancel, false) { _, _ ->

View file

@ -80,9 +80,7 @@ class HabiticaAccountDialog(private var thisContext: Context) :
private fun showForgotPasswordDialog() { private fun showForgotPasswordDialog() {
val input = EditText(requireContext()) val input = EditText(requireContext())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { input.setAutofillHints(EditText.AUTOFILL_HINT_EMAIL_ADDRESS)
input.setAutofillHints(EditText.AUTOFILL_HINT_EMAIL_ADDRESS)
}
input.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS input.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
input.hint = getString(R.string.forgot_password_hint_example) input.hint = getString(R.string.forgot_password_hint_example)
input.textSize = 16f input.textSize = 16f

View file

@ -271,17 +271,15 @@ class PreferencesFragment :
val alert = context?.let { HabiticaAlertDialog(it) } val alert = context?.let { HabiticaAlertDialog(it) }
alert?.setTitle(R.string.push_notification_system_settings_title) alert?.setTitle(R.string.push_notification_system_settings_title)
alert?.setMessage(R.string.push_notification_system_settings_description) alert?.setMessage(R.string.push_notification_system_settings_description)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { alert?.addButton(R.string.open_settings, true, false) { _, _ ->
alert?.addButton(R.string.open_settings, true, false) { _, _ -> val notifSettingIntent: Intent =
val notifSettingIntent: Intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .putExtra(
.putExtra( Settings.EXTRA_APP_PACKAGE,
Settings.EXTRA_APP_PACKAGE, context?.applicationContext?.packageName
context?.applicationContext?.packageName )
) startActivity(notifSettingIntent)
startActivity(notifSettingIntent)
}
} }
alert?.addButton(R.string.cancel, false) { _, _ -> alert?.addButton(R.string.cancel, false) { _, _ ->
alert.dismiss() alert.dismiss()

View file

@ -22,15 +22,8 @@ class TimePreferenceDialogFragment : PreferenceDialogFragmentCompat() {
get() { get() {
val lastHour: Int val lastHour: Int
val lastMinute: Int val lastMinute: Int
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { lastHour = picker.hour
lastHour = picker.hour lastMinute = picker.minute
lastMinute = picker.minute
} else {
@Suppress("DEPRECATION")
lastHour = picker.currentHour
@Suppress("DEPRECATION")
lastMinute = picker.currentMinute
}
return lastHour.toString() + ":" + String.format(Locale.UK, "%02d", lastMinute) return lastHour.toString() + ":" + String.format(Locale.UK, "%02d", lastMinute)
} }
@ -46,15 +39,8 @@ class TimePreferenceDialogFragment : PreferenceDialogFragmentCompat() {
val preference = timePreference val preference = timePreference
val lastHour = preference.lastHour val lastHour = preference.lastHour
val lastMinute = preference.lastMinute val lastMinute = preference.lastMinute
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { picker.hour = lastHour
picker.hour = lastHour picker.minute = lastMinute
picker.minute = lastMinute
} else {
@Suppress("DEPRECATION")
picker.currentHour = lastHour
@Suppress("DEPRECATION")
picker.currentMinute = lastMinute
}
} }
override fun onDialogClosed(positiveResult: Boolean) { override fun onDialogClosed(positiveResult: Boolean) {

View file

@ -50,9 +50,6 @@ object ToolbarColorHelper {
backgroundColor ?: activity.getThemeColor(R.attr.headerBackgroundColor) backgroundColor ?: activity.getThemeColor(R.attr.headerBackgroundColor)
) )
val toolbarIconsColor = iconColor ?: activity.getThemeColor(R.attr.headerTextColor) val toolbarIconsColor = iconColor ?: activity.getThemeColor(R.attr.headerTextColor)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
activity.window.statusBarColor = activity.getThemeColor(R.attr.colorPrimaryDark)
}
val colorFilter = PorterDuffColorFilter(toolbarIconsColor, PorterDuff.Mode.MULTIPLY) val colorFilter = PorterDuffColorFilter(toolbarIconsColor, PorterDuff.Mode.MULTIPLY)
for (i in 0 until toolbar.childCount) { for (i in 0 until toolbar.childCount) {
when (val v = toolbar.getChildAt(i)) { when (val v = toolbar.getChildAt(i)) {

View file

@ -20,6 +20,7 @@ import com.habitrpg.common.habitica.extensions.DataBindingUtils
import com.habitrpg.common.habitica.extensions.inflate import com.habitrpg.common.habitica.extensions.inflate
import com.habitrpg.shared.habitica.models.responses.FeedResponse import com.habitrpg.shared.habitica.models.responses.FeedResponse
import dagger.hilt.android.internal.managers.ViewComponentManager import dagger.hilt.android.internal.managers.ViewComponentManager
import androidx.core.graphics.drawable.toDrawable
class PetViewHolder( class PetViewHolder(
parent: ViewGroup, parent: ViewGroup,
@ -92,9 +93,7 @@ class PetViewHolder(
binding.imageView.alpha = 0.2f binding.imageView.alpha = 0.2f
} }
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) { binding.trainedProgressBar.progressBackgroundTintMode = PorterDuff.Mode.SRC_OVER
binding.trainedProgressBar.progressBackgroundTintMode = PorterDuff.Mode.SRC_OVER
}
binding.imageView.background = null binding.imageView.background = null
binding.activeIndicator.visibility = binding.activeIndicator.visibility =
if (currentPet.equals(animal?.key)) View.VISIBLE else View.GONE if (currentPet.equals(animal?.key)) View.VISIBLE else View.GONE
@ -103,10 +102,7 @@ class PetViewHolder(
val resources = itemView.context.resources ?: return@loadImage val resources = itemView.context.resources ?: return@loadImage
val drawable = val drawable =
if (trained == 0 && canRaiseToMount) { if (trained == 0 && canRaiseToMount) {
BitmapDrawable( it.toBitmap().extractAlpha().toDrawable(resources)
resources,
it.toBitmap().extractAlpha()
)
} else { } else {
it it
} }

View file

@ -157,7 +157,7 @@ class AuthenticationViewModel @Inject constructor(
sharedPrefs.edit { sharedPrefs.edit {
putString("UserID", user) putString("UserID", user)
val encryptedKey = val encryptedKey =
if (keyHelper != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (keyHelper != null) {
try { try {
keyHelper.encrypt(api) keyHelper.encrypt(api)
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -179,10 +179,8 @@ class SubscriptionOptionView(context: Context, attrs: AttributeSet) : FrameLayou
binding.priceLabel.setTextColor(textColor) binding.priceLabel.setTextColor(textColor)
} }
binding.descriptionTextView.setTextColor(textColor) binding.descriptionTextView.setTextColor(textColor)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { TextViewCompat.setCompoundDrawableTintList(binding.gemCapTextView, ContextCompat.getColorStateList(context, R.color.yellow_100))
TextViewCompat.setCompoundDrawableTintList(binding.gemCapTextView, ContextCompat.getColorStateList(context, R.color.yellow_100)) TextViewCompat.setCompoundDrawableTintList(binding.hourglassTextView, ContextCompat.getColorStateList(context, R.color.yellow_100))
TextViewCompat.setCompoundDrawableTintList(binding.hourglassTextView, ContextCompat.getColorStateList(context, R.color.yellow_100))
}
} else { } else {
binding.selectedIndicator.animate() binding.selectedIndicator.animate()
.alpha(0f) .alpha(0f)
@ -215,10 +213,8 @@ class SubscriptionOptionView(context: Context, attrs: AttributeSet) : FrameLayou
R.color.brand_600 R.color.brand_600
) )
) )
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { TextViewCompat.setCompoundDrawableTintList(binding.gemCapTextView, ContextCompat.getColorStateList(context, R.color.brand_400))
TextViewCompat.setCompoundDrawableTintList(binding.gemCapTextView, ContextCompat.getColorStateList(context, R.color.brand_400)) TextViewCompat.setCompoundDrawableTintList(binding.hourglassTextView, ContextCompat.getColorStateList(context, R.color.brand_400))
TextViewCompat.setCompoundDrawableTintList(binding.hourglassTextView, ContextCompat.getColorStateList(context, R.color.brand_400))
}
} }
} }
} }

View file

@ -420,23 +420,13 @@ constructor(
weekdays = weekdays =
if (daysOfMonth?.isNotEmpty() == true) { if (daysOfMonth?.isNotEmpty() == true) {
val date = startDateCalendar.get(Calendar.DATE) val date = startDateCalendar.get(Calendar.DATE)
val formattedDate = val formatter = MessageFormat("{0,ordinal}", LanguageHelper.systemLocale)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { val formattedDate = formatter.format(arrayOf(date))
val formatter = MessageFormat("{0,ordinal}", LanguageHelper.systemLocale)
formatter.format(arrayOf(date))
} else {
date.toString()
}
" on the $formattedDate" " on the $formattedDate"
} else { } else {
val week = startDateCalendar.get(Calendar.WEEK_OF_MONTH) val week = startDateCalendar.get(Calendar.WEEK_OF_MONTH)
val formattedWeek = val formatter = MessageFormat("{0,ordinal}", LanguageHelper.systemLocale)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { val formattedWeek = formatter.format(arrayOf(week))
val formatter = MessageFormat("{0,ordinal}", LanguageHelper.systemLocale)
formatter.format(arrayOf(week))
} else {
week.toString()
}
val dayLongName = val dayLongName =
startDateCalendar.getDisplayName( startDateCalendar.getDisplayName(
Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK,

View file

@ -23,11 +23,7 @@ class DateDeserializer : JsonDeserializer<Date>, JsonSerializer<Date> {
addFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") addFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
addFormat("E MMM dd yyyy HH:mm:ss zzzz") addFormat("E MMM dd yyyy HH:mm:ss zzzz")
addFormat("yyyy-MM-dd'T'HH:mm:sszzz") addFormat("yyyy-MM-dd'T'HH:mm:sszzz")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { addFormat("yyyy-MM-dd'T'HH:mmX")
addFormat("yyyy-MM-dd'T'HH:mmX")
} else {
addFormat("yyyy-MM-dd'T'HH:mm")
}
addFormat("yyyy-MM-dd") addFormat("yyyy-MM-dd")
} }

View file

@ -8,7 +8,6 @@ import android.content.Intent
import android.view.View import android.view.View
import android.widget.RemoteViews import android.widget.RemoteViews
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
@ -203,7 +202,7 @@ class AvatarStatsWidgetProvider : BaseWidgetProvider() {
context, context,
0, 0,
openAppIntent, openAppIntent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABE
) )
remoteViews.setOnClickPendingIntent(android.R.id.background, openApp) remoteViews.setOnClickPendingIntent(android.R.id.background, openApp)

View file

@ -14,7 +14,6 @@ import android.widget.RemoteViews
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.TaskRepository import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.common.habitica.helpers.ExceptionHandler import com.habitrpg.common.habitica.helpers.ExceptionHandler
import com.habitrpg.common.habitica.helpers.MarkdownParser import com.habitrpg.common.habitica.helpers.MarkdownParser
@ -144,7 +143,7 @@ class HabitButtonWidgetService : Service() {
context, context,
widgetId + direction.hashCode(), widgetId + direction.hashCode(),
taskIntent, taskIntent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABE
) )
} }
} }

View file

@ -9,8 +9,6 @@ import android.net.Uri
import android.widget.RemoteViews import android.widget.RemoteViews
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.TaskRepository import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.extensions.withMutableFlag
import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.common.habitica.helpers.ExceptionHandler import com.habitrpg.common.habitica.helpers.ExceptionHandler
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -95,7 +93,7 @@ abstract class TaskListWidgetProvider : BaseWidgetProvider() {
context, context,
0, 0,
openAppIntent, openAppIntent,
withImmutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABE
) )
rv.setOnClickPendingIntent(R.id.widget_title, openApp) rv.setOnClickPendingIntent(R.id.widget_title, openApp)
@ -108,7 +106,7 @@ abstract class TaskListWidgetProvider : BaseWidgetProvider() {
context, context,
0, 0,
taskIntent, taskIntent,
withMutableFlag(PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_MUTABLE
) )
rv.setPendingIntentTemplate(R.id.list_view, toastPendingIntent) rv.setPendingIntentTemplate(R.id.list_view, toastPendingIntent)

View file

@ -54,7 +54,7 @@ class HostConfig {
} }
} else { } else {
val key = sharedPreferences.getString("APIToken", null) val key = sharedPreferences.getString("APIToken", null)
if (key?.isNotBlank() == true && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (key?.isNotBlank() == true) {
val encryptedKey = keyHelper?.encrypt(key) val encryptedKey = keyHelper?.encrypt(key)
sharedPreferences.edit { sharedPreferences.edit {
putString(userID, encryptedKey) putString(userID, encryptedKey)

View file

@ -9,12 +9,7 @@ import android.util.Patterns
import java.util.Locale import java.util.Locale
fun String.fromHtml(): CharSequence { fun String.fromHtml(): CharSequence {
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { return Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)
Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)
} else {
@Suppress("DEPRECATION")
Html.fromHtml(this)
}
} }
fun String.addZeroWidthSpace(): CharSequence { fun String.addZeroWidthSpace(): CharSequence {

View file

@ -34,9 +34,5 @@ object HealthFormatter {
} }
private fun getDefaultLocale() = private fun getDefaultLocale() =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Locale.getDefault(Locale.Category.FORMAT)
Locale.getDefault(Locale.Category.FORMAT)
} else {
Locale.getDefault()
}
} }

View file

@ -49,55 +49,26 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
} }
init { init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { this.generateEncryptKey(ctx)
this.generateEncryptKey(ctx)
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
try {
this.generateAESKey()
} catch (e: Exception) {
HLogger.logException("KeyHelper", "Error initializing", e)
}
}
} }
@Throws(NoSuchProviderException::class, NoSuchAlgorithmException::class, InvalidAlgorithmParameterException::class, KeyStoreException::class, CertificateException::class, IOException::class) @Throws(NoSuchProviderException::class, NoSuchAlgorithmException::class, InvalidAlgorithmParameterException::class, KeyStoreException::class, CertificateException::class, IOException::class)
private fun generateEncryptKey(ctx: Context) { private fun generateEncryptKey(ctx: Context) {
keyStore?.load(null) keyStore?.load(null)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (keyStore?.containsAlias(KEY_ALIAS) == false) {
if (keyStore?.containsAlias(KEY_ALIAS) == false) { val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE)
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE) keyGenerator.init(
keyGenerator.init( KeyGenParameterSpec.Builder(
KeyGenParameterSpec.Builder( KEY_ALIAS,
KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(false)
.build()
) )
keyGenerator.generateKey() .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
} .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
} else { .setRandomizedEncryptionRequired(false)
if (keyStore?.containsAlias(KEY_ALIAS) == false) { .build()
// Generate a key pair for encryption )
val start = Calendar.getInstance() keyGenerator.generateKey()
val end = Calendar.getInstance()
end.add(Calendar.YEAR, 30)
val spec =
KeyPairGeneratorSpec.Builder(ctx)
.setAlias(KEY_ALIAS)
.setSubject(X500Principal("CN=$KEY_ALIAS"))
.setSerialNumber(BigInteger.TEN)
.setStartDate(start.time)
.setEndDate(end.time)
.build()
val kpg = KeyPairGenerator.getInstance("RSA", ANDROID_KEY_STORE)
kpg.initialize(spec)
kpg.generateKeyPair()
}
} }
} }
@ -158,20 +129,11 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
val c: Cipher val c: Cipher
val publicIV = getRandomIV() val publicIV = getRandomIV()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { c = Cipher.getInstance(AES_MODE_M)
c = Cipher.getInstance(AES_MODE_M) try {
try { c.init(Cipher.ENCRYPT_MODE, aesKeyFromKS, GCMParameterSpec(128, Base64.decode(publicIV, Base64.DEFAULT)))
c.init(Cipher.ENCRYPT_MODE, aesKeyFromKS, GCMParameterSpec(128, Base64.decode(publicIV, Base64.DEFAULT))) } catch (e: Exception) {
} catch (e: Exception) { HLogger.logException("KeyHelper", "Error encrypting", e)
HLogger.logException("KeyHelper", "Error encrypting", e)
}
} else {
c = Cipher.getInstance(AES_MODE_M)
try {
c.init(Cipher.ENCRYPT_MODE, getSecretKey(), GCMParameterSpec(128, Base64.decode(publicIV, Base64.DEFAULT)))
} catch (e: Exception) {
HLogger.logException("KeyHelper", "Error encrypting", e)
}
} }
val encodedBytes = c.doFinal(input.toByteArray(charset("UTF-8"))) val encodedBytes = c.doFinal(input.toByteArray(charset("UTF-8")))
return Base64.encodeToString(encodedBytes, Base64.DEFAULT) return Base64.encodeToString(encodedBytes, Base64.DEFAULT)
@ -182,20 +144,11 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
val c: Cipher val c: Cipher
val publicIV = getRandomIV() val publicIV = getRandomIV()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { c = Cipher.getInstance(AES_MODE_M)
c = Cipher.getInstance(AES_MODE_M) try {
try { c.init(Cipher.DECRYPT_MODE, aesKeyFromKS, GCMParameterSpec(128, Base64.decode(publicIV, Base64.DEFAULT)))
c.init(Cipher.DECRYPT_MODE, aesKeyFromKS, GCMParameterSpec(128, Base64.decode(publicIV, Base64.DEFAULT))) } catch (e: Exception) {
} catch (e: Exception) { HLogger.logException("KeyHelper", "Error decrypting", e)
HLogger.logException("KeyHelper", "Error decrypting", e)
}
} else {
c = Cipher.getInstance(AES_MODE_M)
try {
c.init(Cipher.DECRYPT_MODE, getSecretKey(), GCMParameterSpec(128, Base64.decode(publicIV, Base64.DEFAULT)))
} catch (e: Exception) {
HLogger.logException("KeyHelper", "Error decrypting", e)
}
} }
return try { return try {

View file

@ -1,5 +1,5 @@
[versions] [versions]
minSdk = "21" minSdk = "26"
targetSdk = "35" targetSdk = "35"
wearOsTargetSdk = "34" wearOsTargetSdk = "34"