Drop support for Android Lollipop

This commit is contained in:
Julien Papasian 2025-11-11 11:08:13 +01:00
parent 89dd380c7a
commit 9e4a5fe2e5
22 changed files with 189 additions and 238 deletions

View file

@ -19,7 +19,6 @@ package org.breezyweather.background.forecast
import android.app.Notification import android.app.Notification
import android.content.Context import android.content.Context
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.os.Build
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import breezyweather.domain.location.model.Location import breezyweather.domain.location.model.Location
import breezyweather.domain.weather.model.Daily import breezyweather.domain.weather.model.Daily
@ -130,9 +129,7 @@ class ForecastNotificationNotifier(
) )
}.build() }.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && if (weather.current?.weatherCode != null) {
weather.current?.weatherCode != null
) {
try { try {
notification.javaClass notification.javaClass
.getMethod("setSmallIcon", Icon::class.java) .getMethod("setSmallIcon", Icon::class.java)
@ -144,7 +141,7 @@ class ForecastNotificationNotifier(
daytime daytime
) )
) )
} catch (ignore: Exception) { } catch (_: Exception) {
// do nothing. // do nothing.
} }
} }

View file

@ -177,13 +177,6 @@ class WeatherContentProvider : ContentProvider() {
selectionArgs: Array<String>?, selectionArgs: Array<String>?,
sortOrder: String?, sortOrder: String?,
): Cursor? { ): Cursor? {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// Disable the content provider on SDK < 23 since it grants dangerous
// permissions at install-time
Log.w(TAG, "Content provider read is only available for SDK >= 23")
return null
}
if (!isAllowedPackage()) { if (!isAllowedPackage()) {
Log.w(TAG, "Content provider is disabled for this app") Log.w(TAG, "Content provider is disabled for this app")
return null return null

View file

@ -38,10 +38,10 @@ class AppUpdateChecker @Inject constructor(
forceCheck: Boolean = false, forceCheck: Boolean = false,
): GetApplicationRelease.Result { ): GetApplicationRelease.Result {
// Disable app update checks for older Android versions that we're going to drop support for // Disable app update checks for older Android versions that we're going to drop support for
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { /*if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
AppUpdateNotifier(context).promptOldAndroidVersion() AppUpdateNotifier(context).promptOldAndroidVersion()
return GetApplicationRelease.Result.OsTooOld return GetApplicationRelease.Result.OsTooOld
} }*/
return withIOContext { return withIOContext {
val result = getApplicationRelease.await( val result = getApplicationRelease.await(

View file

@ -128,10 +128,10 @@ class WeatherUpdateJob @AssistedInject constructor(
} }
} finally { } finally {
notifier.cancelProgressNotification() notifier.cancelProgressNotification()
// if (BuildConfig.FLAVOR != "freenet" && SettingsManager.getInstance(context).isAppUpdateCheckEnabled) { /*if ((BuildConfig.FLAVOR != "freenet" && SettingsManager.getInstance(context).isAppUpdateCheckEnabled) ||
if ((BuildConfig.FLAVOR != "freenet" && SettingsManager.getInstance(context).isAppUpdateCheckEnabled) ||
Build.VERSION.SDK_INT < Build.VERSION_CODES.M Build.VERSION.SDK_INT < Build.VERSION_CODES.M
) { ) {*/
if (BuildConfig.FLAVOR != "freenet" && SettingsManager.getInstance(context).isAppUpdateCheckEnabled) {
try { try {
updateChecker.checkForUpdate(context, forceCheck = false) updateChecker.checkForUpdate(context, forceCheck = false)
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -17,14 +17,11 @@
package org.breezyweather.common.actionmodecallback package org.breezyweather.common.actionmodecallback
import android.graphics.Rect import android.graphics.Rect
import android.os.Build
import android.view.ActionMode import android.view.ActionMode
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.annotation.RequiresApi
@RequiresApi(Build.VERSION_CODES.M)
internal class BreezyFloatingTextActionModeCallback( internal class BreezyFloatingTextActionModeCallback(
private val callback: BreezyTextActionModeCallback, private val callback: BreezyTextActionModeCallback,
) : ActionMode.Callback2() { ) : ActionMode.Callback2() {

View file

@ -21,7 +21,6 @@ import android.content.Intent
import android.os.Build import android.os.Build
import android.view.ActionMode import android.view.ActionMode
import android.view.View import android.view.View
import androidx.annotation.RequiresApi
import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.platform.TextToolbar import androidx.compose.ui.platform.TextToolbar
import androidx.compose.ui.platform.TextToolbarStatus import androidx.compose.ui.platform.TextToolbarStatus
@ -49,40 +48,36 @@ internal class BreezyTextToolbar(
textActionModeCallback.rect = rect textActionModeCallback.rect = rect
textActionModeCallback.onCopyRequested = onCopyRequested textActionModeCallback.onCopyRequested = onCopyRequested
textActionModeCallback.onSelectAllRequested = onSelectAllRequested textActionModeCallback.onSelectAllRequested = onSelectAllRequested
textActionModeCallback.onTranslateRequested = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { textActionModeCallback.onTranslateRequested = {
{ // Get selected text by copying it, then restore the previous clip
// Get selected text by copying it, then restore the previous clip val clipboardManager = view.context.clipboardManager
val clipboardManager = view.context.clipboardManager val previousClipboard = clipboardManager.primaryClip
val previousClipboard = clipboardManager.primaryClip onCopyRequested?.invoke()
onCopyRequested?.invoke() val text = clipboardManager.text
val text = clipboardManager.text if (previousClipboard != null) {
if (previousClipboard != null) { clipboardManager.setPrimaryClip(previousClipboard)
clipboardManager.setPrimaryClip(previousClipboard) } else {
} else { clipboardManager.setPrimaryClip(ClipData.newPlainText(null, " "))
clipboardManager.setPrimaryClip(ClipData.newPlainText(null, " ")) }
}
val intent = Intent().apply {
val intent = Intent().apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { action = Intent.ACTION_TRANSLATE
action = Intent.ACTION_TRANSLATE putExtra(Intent.EXTRA_TEXT, text.trim())
putExtra(Intent.EXTRA_TEXT, text.trim()) } else {
} else { action = Intent.ACTION_PROCESS_TEXT
action = Intent.ACTION_PROCESS_TEXT type = "text/plain"
type = "text/plain" putExtra(Intent.EXTRA_PROCESS_TEXT, text.trim())
putExtra(Intent.EXTRA_PROCESS_TEXT, text.trim()) putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, true)
putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, true) }
} flags = Intent.FLAG_ACTIVITY_NEW_TASK
flags = Intent.FLAG_ACTIVITY_NEW_TASK }
}
try {
try { view.context.startActivity(Intent.createChooser(intent, ""))
view.context.startActivity(Intent.createChooser(intent, "")) } catch (e: Exception) {
} catch (e: Exception) { SnackbarHelper.showSnackbar(view.context.getString(R.string.action_translate_no_app))
SnackbarHelper.showSnackbar(view.context.getString(R.string.action_translate_no_app))
}
} }
} else {
null
} }
textActionModeCallback.onShareRequested = { textActionModeCallback.onShareRequested = {
// Get selected text by copying it, then restore the previous clip // Get selected text by copying it, then restore the previous clip
@ -112,16 +107,11 @@ internal class BreezyTextToolbar(
} }
if (actionMode == null) { if (actionMode == null) {
status = TextToolbarStatus.Shown status = TextToolbarStatus.Shown
actionMode = actionMode = TextToolbarHelperMethods.startActionMode(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { view,
TextToolbarHelperMethods.startActionMode( BreezyFloatingTextActionModeCallback(textActionModeCallback),
view, ActionMode.TYPE_FLOATING
BreezyFloatingTextActionModeCallback(textActionModeCallback), )
ActionMode.TYPE_FLOATING
)
} else {
view.startActionMode(BreezyPrimaryTextActionModeCallback(textActionModeCallback))
}
} else { } else {
actionMode?.invalidate() actionMode?.invalidate()
} }
@ -155,9 +145,7 @@ internal class BreezyTextToolbar(
* compiled. It is expected that this class will soft-fail verification, but the classes which use * compiled. It is expected that this class will soft-fail verification, but the classes which use
* this method will pass. * this method will pass.
*/ */
@RequiresApi(Build.VERSION_CODES.M)
internal object TextToolbarHelperMethods { internal object TextToolbarHelperMethods {
@RequiresApi(Build.VERSION_CODES.M)
fun startActionMode( fun startActionMode(
view: View, view: View,
actionModeCallback: ActionMode.Callback, actionModeCallback: ActionMode.Callback,
@ -166,7 +154,6 @@ internal object TextToolbarHelperMethods {
return view.startActionMode(actionModeCallback, type) return view.startActionMode(actionModeCallback, type)
} }
@RequiresApi(Build.VERSION_CODES.M)
fun invalidateContentRect(actionMode: ActionMode) { fun invalidateContentRect(actionMode: ActionMode) {
actionMode.invalidateContentRect() actionMode.invalidateContentRect()
} }

View file

@ -222,10 +222,6 @@ fun Window.setSystemBarStyle(
val colorSystemBarDark = Color.argb(0x80, 0x1b, 0x1b, 0x1b) val colorSystemBarDark = Color.argb(0x80, 0x1b, 0x1b, 0x1b)
val colorSystemBarLight = Color.argb(0xe6, 0xFF, 0xFF, 0xFF) val colorSystemBarLight = Color.argb(0xe6, 0xFF, 0xFF, 0xFF)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// Always apply a dark shader as a light or transparent status bar is not supported
newLightStatus = false
}
statusBarColor = Color.TRANSPARENT statusBarColor = Color.TRANSPARENT
navigationBarColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && lightStatus) { navigationBarColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && lightStatus) {

View file

@ -655,7 +655,7 @@ abstract class AbstractWidgetConfigActivity : BreezyActivity() {
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
private fun bindWallpaper(checkPermissions: Boolean) { private fun bindWallpaper(checkPermissions: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkPermissions) { if (checkPermissions) {
val hasPermission = checkPermissions(0) val hasPermission = checkPermissions(0)
if (!hasPermission) { if (!hasPermission) {
return return
@ -674,7 +674,6 @@ abstract class AbstractWidgetConfigActivity : BreezyActivity() {
* @return true : already got permissions. * @return true : already got permissions.
* false: request permissions. * false: request permissions.
*/ */
@RequiresApi(Build.VERSION_CODES.M)
private fun checkPermissions(requestCode: Int): Boolean { private fun checkPermissions(requestCode: Int): Boolean {
if (!hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) { if (!hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), requestCode) requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), requestCode)
@ -779,10 +778,7 @@ abstract class AbstractWidgetConfigActivity : BreezyActivity() {
updateHostView() updateHostView()
return return
} }
var hasPermission = true val hasPermission = checkPermissions(1)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
hasPermission = checkPermissions(1)
}
if (hasPermission) { if (hasPermission) {
updateHostView() updateHostView()
} }

View file

@ -72,7 +72,7 @@ object MultiCityWidgetNotificationIMP : AbstractRemoteViewsPresenter() {
val notification = context.notificationBuilder(Notifications.CHANNEL_WIDGET).apply { val notification = context.notificationBuilder(Notifications.CHANNEL_WIDGET).apply {
priority = NotificationCompat.PRIORITY_MAX priority = NotificationCompat.PRIORITY_MAX
setVisibility(NotificationCompat.VISIBILITY_PUBLIC) setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
if (temperature != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (temperature != null) {
setSmallIcon( setSmallIcon(
IconCompat.createWithBitmap( IconCompat.createWithBitmap(
ResourceHelper.createTempBitmap(context, temperature, temperatureUnit) ResourceHelper.createTempBitmap(context, temperature, temperatureUnit)
@ -110,7 +110,7 @@ object MultiCityWidgetNotificationIMP : AbstractRemoteViewsPresenter() {
setOnlyAlertOnce(true) setOnlyAlertOnce(true)
}.build() }.build()
if (!tempIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!tempIcon) {
current.weatherCode?.let { weatherCode -> current.weatherCode?.let { weatherCode ->
try { try {
notification.javaClass notification.javaClass

View file

@ -87,7 +87,7 @@ object NativeWidgetNotificationIMP : AbstractRemoteViewsPresenter() {
val notification = context.notificationBuilder(Notifications.CHANNEL_WIDGET).apply { val notification = context.notificationBuilder(Notifications.CHANNEL_WIDGET).apply {
priority = NotificationCompat.PRIORITY_MAX priority = NotificationCompat.PRIORITY_MAX
setVisibility(NotificationCompat.VISIBILITY_PUBLIC) setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
if (temperature != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (temperature != null) {
setSmallIcon( setSmallIcon(
IconCompat.createWithBitmap( IconCompat.createWithBitmap(
ResourceHelper.createTempBitmap(context, temperature, temperatureUnit) ResourceHelper.createTempBitmap(context, temperature, temperatureUnit)
@ -123,7 +123,7 @@ object NativeWidgetNotificationIMP : AbstractRemoteViewsPresenter() {
setContentIntent(getWeatherPendingIntent(context, null, Notifications.ID_WIDGET)) setContentIntent(getWeatherPendingIntent(context, null, Notifications.ID_WIDGET))
}.build() }.build()
if (!tempIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!tempIcon) {
current.weatherCode?.let { weatherCode -> current.weatherCode?.let { weatherCode ->
try { try {
notification.javaClass notification.javaClass

View file

@ -100,7 +100,7 @@ object WidgetNotificationIMP : AbstractRemoteViewsPresenter() {
val notification = context.notificationBuilder(Notifications.CHANNEL_WIDGET).apply { val notification = context.notificationBuilder(Notifications.CHANNEL_WIDGET).apply {
priority = NotificationCompat.PRIORITY_MAX priority = NotificationCompat.PRIORITY_MAX
setVisibility(NotificationCompat.VISIBILITY_PUBLIC) setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
if (temperature != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (temperature != null) {
setSmallIcon( setSmallIcon(
IconCompat.createWithBitmap( IconCompat.createWithBitmap(
ResourceHelper.createTempBitmap(context, temperature, temperatureUnit) ResourceHelper.createTempBitmap(context, temperature, temperatureUnit)
@ -139,7 +139,7 @@ object WidgetNotificationIMP : AbstractRemoteViewsPresenter() {
setOnlyAlertOnce(true) setOnlyAlertOnce(true)
}.build() }.build()
if (!tempIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!tempIcon) {
current.weatherCode?.let { weatherCode -> current.weatherCode?.let { weatherCode ->
try { try {
notification.javaClass notification.javaClass

View file

@ -362,8 +362,7 @@ class MainActivity : BreezyActivity(), HomeFragment.Callback, ManagementFragment
lifecycleScope.launch { lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) { repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.locationPermissionsRequest.collect { viewModel.locationPermissionsRequest.collect {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && if (it != null &&
it != null &&
it.permissionList.isNotEmpty() && it.permissionList.isNotEmpty() &&
it.consume() it.consume()
) { ) {

View file

@ -348,7 +348,7 @@ class MainActivityViewModel @Inject constructor(
} }
} }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || !checkPermissions) { if (!checkPermissions) {
updating = true updating = true
SettingsManager.getInstance(getApplication()) SettingsManager.getInstance(getApplication())
.weatherManualUpdateLastTimestamp = Date().time .weatherManualUpdateLastTimestamp = Date().time

View file

@ -235,35 +235,33 @@ fun BackgroundSettingsScreen(
largeSeparatorItem() largeSeparatorItem()
sectionHeaderItem(R.string.settings_background_updates_section_troubleshoot) sectionHeaderItem(R.string.settings_background_updates_section_troubleshoot)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { clickablePreferenceItem(R.string.settings_background_updates_battery_optimization) { id ->
clickablePreferenceItem(R.string.settings_background_updates_battery_optimization) { id -> PreferenceViewWithCard(
PreferenceViewWithCard( titleId = id,
titleId = id, summaryId = R.string.settings_background_updates_battery_optimization_summary,
summaryId = R.string.settings_background_updates_battery_optimization_summary, isFirst = true
isFirst = true ) {
) { val packageName: String = context.packageName
val packageName: String = context.packageName if (!context.powerManager.isIgnoringBatteryOptimizations(packageName)) {
if (!context.powerManager.isIgnoringBatteryOptimizations(packageName)) { try {
try { @SuppressLint("BatteryLife")
@SuppressLint("BatteryLife") val intent = Intent().apply {
val intent = Intent().apply { action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS data = "package:$packageName".toUri()
data = "package:$packageName".toUri() addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
SnackbarHelper.showSnackbar(
context.getString(
R.string.settings_background_updates_battery_optimization_activity_not_found
)
)
} }
} else { context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
SnackbarHelper.showSnackbar( SnackbarHelper.showSnackbar(
context.getString(R.string.settings_background_updates_battery_optimization_disabled) context.getString(
R.string.settings_background_updates_battery_optimization_activity_not_found
)
) )
} }
} else {
SnackbarHelper.showSnackbar(
context.getString(R.string.settings_background_updates_battery_optimization_disabled)
)
} }
} }
} }

View file

@ -171,28 +171,59 @@ fun LocationSettingsScreen(
sectionFooterItem(R.string.settings_location_section_general) sectionFooterItem(R.string.settings_location_section_general)
largeSeparatorItem() largeSeparatorItem()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { sectionHeaderItem(R.string.location_service_native)
sectionHeaderItem(R.string.location_service_native) clickablePreferenceItem(R.string.settings_location_access_switch_title) { id ->
clickablePreferenceItem(R.string.settings_location_access_switch_title) { id -> PreferenceViewWithCard(
titleId = id,
summaryId = if (accessCoarseLocationPermissionState.status == PermissionStatus.Granted) {
R.string.settings_location_access_switch_summaryOn
} else {
R.string.settings_location_access_switch_summaryOff
},
isFirst = true,
isLast = accessBackgroundLocationPermissionState == null &&
Build.VERSION.SDK_INT < Build.VERSION_CODES.S,
onClick = {
if (accessCoarseLocationPermissionState.status != PermissionStatus.Granted) {
if (
ActivityCompat.shouldShowRequestPermissionRationale(
context,
Manifest.permission.ACCESS_COARSE_LOCATION
)
) {
accessCoarseLocationPermissionState.launchPermissionRequest()
} else {
context.openApplicationDetailsSettings()
}
} else {
SnackbarHelper.showSnackbar(
context.getString(R.string.settings_location_access_permission_already_granted)
)
}
}
)
}
accessBackgroundLocationPermissionState?.let {
smallSeparatorItem()
clickablePreferenceItem(R.string.settings_location_access_background_title) { id ->
PreferenceViewWithCard( PreferenceViewWithCard(
titleId = id, titleId = id,
summaryId = if (accessCoarseLocationPermissionState.status == PermissionStatus.Granted) { summaryId = if (it.status == PermissionStatus.Granted) {
R.string.settings_location_access_switch_summaryOn R.string.settings_location_access_background_summaryOn
} else { } else {
R.string.settings_location_access_switch_summaryOff R.string.settings_location_access_background_summaryOff
}, },
isFirst = true, enabled = accessCoarseLocationPermissionState.status == PermissionStatus.Granted,
isLast = accessBackgroundLocationPermissionState == null && isLast = Build.VERSION.SDK_INT < Build.VERSION_CODES.S,
Build.VERSION.SDK_INT < Build.VERSION_CODES.S,
onClick = { onClick = {
if (accessCoarseLocationPermissionState.status != PermissionStatus.Granted) { if (it.status != PermissionStatus.Granted) {
if ( if (
ActivityCompat.shouldShowRequestPermissionRationale( ActivityCompat.shouldShowRequestPermissionRationale(
context, context,
Manifest.permission.ACCESS_COARSE_LOCATION Manifest.permission.ACCESS_BACKGROUND_LOCATION
) )
) { ) {
accessCoarseLocationPermissionState.launchPermissionRequest() it.launchPermissionRequest()
} else { } else {
context.openApplicationDetailsSettings() context.openApplicationDetailsSettings()
} }
@ -204,74 +235,41 @@ fun LocationSettingsScreen(
} }
) )
} }
accessBackgroundLocationPermissionState?.let {
smallSeparatorItem()
clickablePreferenceItem(R.string.settings_location_access_background_title) { id ->
PreferenceViewWithCard(
titleId = id,
summaryId = if (it.status == PermissionStatus.Granted) {
R.string.settings_location_access_background_summaryOn
} else {
R.string.settings_location_access_background_summaryOff
},
enabled = accessCoarseLocationPermissionState.status == PermissionStatus.Granted,
isLast = Build.VERSION.SDK_INT < Build.VERSION_CODES.S,
onClick = {
if (it.status != PermissionStatus.Granted) {
if (
ActivityCompat.shouldShowRequestPermissionRationale(
context,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
)
) {
it.launchPermissionRequest()
} else {
context.openApplicationDetailsSettings()
}
} else {
SnackbarHelper.showSnackbar(
context.getString(R.string.settings_location_access_permission_already_granted)
)
}
}
)
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
smallSeparatorItem()
clickablePreferenceItem(R.string.settings_location_access_precise_title) { id ->
PreferenceViewWithCard(
titleId = id,
summaryId = if (accessFineLocationPermissionState.status == PermissionStatus.Granted) {
R.string.settings_location_access_precise_summaryOn
} else {
R.string.settings_location_access_precise_summaryOff
},
enabled = accessCoarseLocationPermissionState.status == PermissionStatus.Granted,
isLast = true,
onClick = {
if (accessFineLocationPermissionState.status != PermissionStatus.Granted) {
if (
ActivityCompat.shouldShowRequestPermissionRationale(
context,
Manifest.permission.ACCESS_FINE_LOCATION
)
) {
accessFineLocationPermissionState.launchPermissionRequest()
} else {
context.openApplicationDetailsSettings()
}
} else {
SnackbarHelper.showSnackbar(
context.getString(R.string.settings_location_access_permission_already_granted)
)
}
}
)
}
}
sectionFooterItem(R.string.location_service_native)
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
smallSeparatorItem()
clickablePreferenceItem(R.string.settings_location_access_precise_title) { id ->
PreferenceViewWithCard(
titleId = id,
summaryId = if (accessFineLocationPermissionState.status == PermissionStatus.Granted) {
R.string.settings_location_access_precise_summaryOn
} else {
R.string.settings_location_access_precise_summaryOff
},
enabled = accessCoarseLocationPermissionState.status == PermissionStatus.Granted,
isLast = true,
onClick = {
if (accessFineLocationPermissionState.status != PermissionStatus.Granted) {
if (
ActivityCompat.shouldShowRequestPermissionRationale(
context,
Manifest.permission.ACCESS_FINE_LOCATION
)
) {
accessFineLocationPermissionState.launchPermissionRequest()
} else {
context.openApplicationDetailsSettings()
}
} else {
SnackbarHelper.showSnackbar(
context.getString(R.string.settings_location_access_permission_already_granted)
)
}
}
)
}
}
sectionFooterItem(R.string.location_service_native)
// TODO: Duplicate code from weather sources // TODO: Duplicate code from weather sources
locationSources.filterIsInstance<ConfigurableSource>().forEach { preferenceSource -> locationSources.filterIsInstance<ConfigurableSource>().forEach { preferenceSource ->

View file

@ -324,7 +324,6 @@ fun ModulesSettingsScreen(
nameArrayId = R.array.notification_styles, nameArrayId = R.array.notification_styles,
enabled = notificationEnabled && hasNotificationPermission, enabled = notificationEnabled && hasNotificationPermission,
card = true, card = true,
isLast = Build.VERSION.SDK_INT < Build.VERSION_CODES.M,
onValueChanged = { onValueChanged = {
SettingsManager SettingsManager
.getInstance(context) .getInstance(context)
@ -333,46 +332,44 @@ fun ModulesSettingsScreen(
} }
) )
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { smallSeparatorItem()
smallSeparatorItem() switchPreferenceItem(R.string.settings_modules_notification_temp_icon_switch) { id ->
switchPreferenceItem(R.string.settings_modules_notification_temp_icon_switch) { id -> SwitchPreferenceView(
SwitchPreferenceView( titleId = id,
titleId = id, summaryOnId = R.string.settings_enabled,
summaryOnId = R.string.settings_enabled, summaryOffId = R.string.settings_disabled,
summaryOffId = R.string.settings_disabled, checked = SettingsManager
checked = SettingsManager .getInstance(context)
.isWidgetNotificationTemperatureIconEnabled,
enabled = notificationEnabled && hasNotificationPermission,
onValueChanged = {
SettingsManager
.getInstance(context) .getInstance(context)
.isWidgetNotificationTemperatureIconEnabled, .isWidgetNotificationTemperatureIconEnabled = it
enabled = notificationEnabled && hasNotificationPermission, updateNotificationIfNecessary(context)
onValueChanged = { }
SettingsManager )
.getInstance(context) }
.isWidgetNotificationTemperatureIconEnabled = it smallSeparatorItem()
updateNotificationIfNecessary(context) switchPreferenceItem(R.string.settings_modules_notification_feels_like_switch) { id ->
} SwitchPreferenceView(
) titleId = id,
} summaryOnId = R.string.settings_enabled,
smallSeparatorItem() summaryOffId = R.string.settings_disabled,
switchPreferenceItem(R.string.settings_modules_notification_feels_like_switch) { id -> checked = SettingsManager
SwitchPreferenceView( .getInstance(context)
titleId = id, .isWidgetNotificationUsingFeelsLike,
summaryOnId = R.string.settings_enabled, enabled = notificationEnabled &&
summaryOffId = R.string.settings_disabled, hasNotificationPermission &&
checked = SettingsManager notificationTemperatureIconEnabled,
isLast = true,
onValueChanged = {
SettingsManager
.getInstance(context) .getInstance(context)
.isWidgetNotificationUsingFeelsLike, .isWidgetNotificationUsingFeelsLike = it
enabled = notificationEnabled && updateNotificationIfNecessary(context)
hasNotificationPermission && }
notificationTemperatureIconEnabled, )
isLast = true,
onValueChanged = {
SettingsManager
.getInstance(context)
.isWidgetNotificationUsingFeelsLike = it
updateNotificationIfNecessary(context)
}
)
}
} }
sectionFooterItem(R.string.settings_modules_section_notification_widget) sectionFooterItem(R.string.settings_modules_section_notification_widget)

View file

@ -121,7 +121,6 @@ object ResourceHelper {
return provider.getMinimalXmlIcon(code, daytime) return provider.getMinimalXmlIcon(code, daytime)
} }
@RequiresApi(Build.VERSION_CODES.M)
fun getMinimalIcon( fun getMinimalIcon(
provider: ResourceProvider, provider: ResourceProvider,
code: WeatherCode, code: WeatherCode,

View file

@ -155,7 +155,6 @@ class ChronusResourceProvider(
return mDefaultProvider.getMinimalXmlIcon(code, dayTime) return mDefaultProvider.getMinimalXmlIcon(code, dayTime)
} }
@RequiresApi(Build.VERSION_CODES.M)
override fun getMinimalIcon(code: WeatherCode?, dayTime: Boolean): Icon { override fun getMinimalIcon(code: WeatherCode?, dayTime: Boolean): Icon {
return mDefaultProvider.getMinimalIcon(code, dayTime) return mDefaultProvider.getMinimalIcon(code, dayTime)
} }

View file

@ -179,7 +179,6 @@ class DefaultResourceProvider : ResourceProvider() {
return getDrawable(getMiniXmlIconName(code, dayTime))!! return getDrawable(getMiniXmlIconName(code, dayTime))!!
} }
@RequiresApi(Build.VERSION_CODES.M)
override fun getMinimalIcon(code: WeatherCode?, dayTime: Boolean): Icon { override fun getMinimalIcon(code: WeatherCode?, dayTime: Boolean): Icon {
return Objects.requireNonNull( return Objects.requireNonNull(
Icon.createWithResource( Icon.createWithResource(

View file

@ -24,9 +24,7 @@ import android.content.pm.PackageManager
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.net.Uri import android.net.Uri
import android.os.Build
import androidx.annotation.IntRange import androidx.annotation.IntRange
import androidx.annotation.RequiresApi
import androidx.annotation.Size import androidx.annotation.Size
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import breezyweather.domain.weather.reference.WeatherCode import breezyweather.domain.weather.reference.WeatherCode
@ -338,12 +336,11 @@ open class IconPackResourcesProvider(
if (mConfig.hasMinimalIcons) { if (mConfig.hasMinimalIcons) {
return getDrawable(getMiniXmlIconName(code, dayTime))!! return getDrawable(getMiniXmlIconName(code, dayTime))!!
} }
} catch (ignore: Exception) { } catch (_: Exception) {
} }
return mDefaultProvider.getMinimalXmlIcon(code, dayTime) return mDefaultProvider.getMinimalXmlIcon(code, dayTime)
} }
@RequiresApi(Build.VERSION_CODES.M)
override fun getMinimalIcon(code: WeatherCode?, dayTime: Boolean): Icon { override fun getMinimalIcon(code: WeatherCode?, dayTime: Boolean): Icon {
try { try {
if (mConfig.hasMinimalIcons) { if (mConfig.hasMinimalIcons) {

View file

@ -50,7 +50,6 @@ abstract class ResourceProvider {
abstract fun getWeatherAnimators(code: WeatherCode?, dayTime: Boolean): Array<Animator?> abstract fun getWeatherAnimators(code: WeatherCode?, dayTime: Boolean): Array<Animator?>
// minimal icon. // minimal icon.
@RequiresApi(Build.VERSION_CODES.M)
abstract fun getMinimalIcon(code: WeatherCode?, dayTime: Boolean): Icon abstract fun getMinimalIcon(code: WeatherCode?, dayTime: Boolean): Icon
abstract fun getMinimalLightIcon(code: WeatherCode?, dayTime: Boolean): Drawable abstract fun getMinimalLightIcon(code: WeatherCode?, dayTime: Boolean): Drawable
abstract fun getMinimalLightIconUri(code: WeatherCode?, dayTime: Boolean): Uri abstract fun getMinimalLightIconUri(code: WeatherCode?, dayTime: Boolean): Uri

View file

@ -5,7 +5,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget as KotlinJvmTarget
object AndroidConfig { object AndroidConfig {
const val COMPILE_SDK = 36 const val COMPILE_SDK = 36
const val MIN_SDK = 21 const val MIN_SDK = 23
const val TARGET_SDK = 36 const val TARGET_SDK = 36
const val BUILD_TOOLS = "35.0.1" const val BUILD_TOOLS = "35.0.1"