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

View file

@ -177,13 +177,6 @@ class WeatherContentProvider : ContentProvider() {
selectionArgs: Array<String>?,
sortOrder: String?,
): 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()) {
Log.w(TAG, "Content provider is disabled for this app")
return null

View file

@ -38,10 +38,10 @@ class AppUpdateChecker @Inject constructor(
forceCheck: Boolean = false,
): GetApplicationRelease.Result {
// 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()
return GetApplicationRelease.Result.OsTooOld
}
}*/
return withIOContext {
val result = getApplicationRelease.await(

View file

@ -128,10 +128,10 @@ class WeatherUpdateJob @AssistedInject constructor(
}
} finally {
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
) {
) {*/
if (BuildConfig.FLAVOR != "freenet" && SettingsManager.getInstance(context).isAppUpdateCheckEnabled) {
try {
updateChecker.checkForUpdate(context, forceCheck = false)
} catch (e: Exception) {

View file

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

View file

@ -21,7 +21,6 @@ import android.content.Intent
import android.os.Build
import android.view.ActionMode
import android.view.View
import androidx.annotation.RequiresApi
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.platform.TextToolbar
import androidx.compose.ui.platform.TextToolbarStatus
@ -49,8 +48,7 @@ internal class BreezyTextToolbar(
textActionModeCallback.rect = rect
textActionModeCallback.onCopyRequested = onCopyRequested
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
val clipboardManager = view.context.clipboardManager
val previousClipboard = clipboardManager.primaryClip
@ -81,9 +79,6 @@ internal class BreezyTextToolbar(
SnackbarHelper.showSnackbar(view.context.getString(R.string.action_translate_no_app))
}
}
} else {
null
}
textActionModeCallback.onShareRequested = {
// Get selected text by copying it, then restore the previous clip
val clipboardManager = view.context.clipboardManager
@ -112,16 +107,11 @@ internal class BreezyTextToolbar(
}
if (actionMode == null) {
status = TextToolbarStatus.Shown
actionMode =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
TextToolbarHelperMethods.startActionMode(
actionMode = TextToolbarHelperMethods.startActionMode(
view,
BreezyFloatingTextActionModeCallback(textActionModeCallback),
ActionMode.TYPE_FLOATING
)
} else {
view.startActionMode(BreezyPrimaryTextActionModeCallback(textActionModeCallback))
}
} else {
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
* this method will pass.
*/
@RequiresApi(Build.VERSION_CODES.M)
internal object TextToolbarHelperMethods {
@RequiresApi(Build.VERSION_CODES.M)
fun startActionMode(
view: View,
actionModeCallback: ActionMode.Callback,
@ -166,7 +154,6 @@ internal object TextToolbarHelperMethods {
return view.startActionMode(actionModeCallback, type)
}
@RequiresApi(Build.VERSION_CODES.M)
fun invalidateContentRect(actionMode: ActionMode) {
actionMode.invalidateContentRect()
}

View file

@ -222,10 +222,6 @@ fun Window.setSystemBarStyle(
val colorSystemBarDark = Color.argb(0x80, 0x1b, 0x1b, 0x1b)
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
navigationBarColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && lightStatus) {

View file

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

View file

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

View file

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

View file

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

View file

@ -362,8 +362,7 @@ class MainActivity : BreezyActivity(), HomeFragment.Callback, ManagementFragment
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.locationPermissionsRequest.collect {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
it != null &&
if (it != null &&
it.permissionList.isNotEmpty() &&
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
SettingsManager.getInstance(getApplication())
.weatherManualUpdateLastTimestamp = Date().time

View file

@ -235,7 +235,6 @@ fun BackgroundSettingsScreen(
largeSeparatorItem()
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 ->
PreferenceViewWithCard(
titleId = id,
@ -266,7 +265,6 @@ fun BackgroundSettingsScreen(
}
}
}
}
smallSeparatorItem()
clickablePreferenceItem(R.string.settings_background_updates_dont_kill_my_app_title) { id ->
PreferenceViewWithCard(

View file

@ -171,7 +171,6 @@ fun LocationSettingsScreen(
sectionFooterItem(R.string.settings_location_section_general)
largeSeparatorItem()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
sectionHeaderItem(R.string.location_service_native)
clickablePreferenceItem(R.string.settings_location_access_switch_title) { id ->
PreferenceViewWithCard(
@ -271,7 +270,6 @@ fun LocationSettingsScreen(
}
}
sectionFooterItem(R.string.location_service_native)
}
// TODO: Duplicate code from weather sources
locationSources.filterIsInstance<ConfigurableSource>().forEach { preferenceSource ->

View file

@ -324,7 +324,6 @@ fun ModulesSettingsScreen(
nameArrayId = R.array.notification_styles,
enabled = notificationEnabled && hasNotificationPermission,
card = true,
isLast = Build.VERSION.SDK_INT < Build.VERSION_CODES.M,
onValueChanged = {
SettingsManager
.getInstance(context)
@ -333,7 +332,6 @@ fun ModulesSettingsScreen(
}
)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
smallSeparatorItem()
switchPreferenceItem(R.string.settings_modules_notification_temp_icon_switch) { id ->
SwitchPreferenceView(
@ -373,7 +371,6 @@ fun ModulesSettingsScreen(
}
)
}
}
sectionFooterItem(R.string.settings_modules_section_notification_widget)
largeSeparatorItem()

View file

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

View file

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

View file

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

View file

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

View file

@ -50,7 +50,6 @@ abstract class ResourceProvider {
abstract fun getWeatherAnimators(code: WeatherCode?, dayTime: Boolean): Array<Animator?>
// minimal icon.
@RequiresApi(Build.VERSION_CODES.M)
abstract fun getMinimalIcon(code: WeatherCode?, dayTime: Boolean): Icon
abstract fun getMinimalLightIcon(code: WeatherCode?, dayTime: Boolean): Drawable
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 {
const val COMPILE_SDK = 36
const val MIN_SDK = 21
const val MIN_SDK = 23
const val TARGET_SDK = 36
const val BUILD_TOOLS = "35.0.1"