diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8543f355d..b4bb5f9a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
- add and remove tags to JPEG/GIF/PNG/TIFF images
- French translation
+- restored support for Android KitKat (without Google Maps)
## [v1.5.6] - 2021-11-12
diff --git a/README.md b/README.md
index 4cfec3aa7..43e10ab02 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ It scans your media collection to identify **motion photos**, **panoramas** (aka
**Navigation and search** is an important part of Aves. The goal is for users to easily flow from albums to photos to tags to maps, etc.
-Aves integrates with Android (from **API 20 to 31**, i.e. from Lollipop to S) with features such as **app shortcuts** and **global search** handling. It also works as a **media viewer and picker**.
+Aves integrates with Android (from **API 19 to 31**, i.e. from KitKat to S) with features such as **app shortcuts** and **global search** handling. It also works as a **media viewer and picker**.
## Screenshots
@@ -82,5 +82,10 @@ To run the app:
# flutter run -t lib/main_play.dart --flavor play
```
+To run the app on API 19 emulators:
+```
+# flutter run -t lib/main_play.dart --flavor play --enable-software-rendering
+```
+
[Version badge]: https://img.shields.io/github/v/release/deckerst/aves?include_prereleases&sort=semver
[Build badge]: https://img.shields.io/github/workflow/status/deckerst/aves/Quality%20check
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 69f477b13..5f39c6960 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -55,9 +55,9 @@ android {
applicationId appId
// minSdkVersion constraints:
// - Flutter & other plugins: 16
- // - google_maps_flutter v2.0.5: 20
+ // - google_maps_flutter v2.1.1: 20
// - Aves native: 19
- minSdkVersion 20
+ minSdkVersion 19
targetSdkVersion 31
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 0546ae2a0..90111d4fd 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -4,21 +4,12 @@
android:installLocation="auto">
-
+
+
+
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AccessibilityHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AccessibilityHandler.kt
index 77b5e015b..ebd55045c 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AccessibilityHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AccessibilityHandler.kt
@@ -27,7 +27,7 @@ class AccessibilityHandler(private val activity: Activity) : MethodCallHandler {
try {
removed = Settings.Global.getFloat(activity.contentResolver, Settings.Global.TRANSITION_ANIMATION_SCALE) == 0f
} catch (e: Exception) {
- Log.w(LOG_TAG, "failed to get settings", e)
+ Log.w(LOG_TAG, "failed to get settings with error=${e.message}", null)
}
result.success(removed)
}
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/WindowHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/WindowHandler.kt
index 2494977f9..528e70941 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/WindowHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/WindowHandler.kt
@@ -45,7 +45,7 @@ class WindowHandler(private val activity: Activity) : MethodCallHandler {
try {
locked = Settings.System.getInt(activity.contentResolver, Settings.System.ACCELEROMETER_ROTATION) == 0
} catch (e: Exception) {
- Log.w(LOG_TAG, "failed to get settings", e)
+ Log.w(LOG_TAG, "failed to get settings with error=${e.message}", null)
}
result.success(locked)
}
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/SettingsChangeStreamHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/SettingsChangeStreamHandler.kt
index 26c15805a..60cb1f800 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/SettingsChangeStreamHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/SettingsChangeStreamHandler.kt
@@ -56,7 +56,7 @@ class SettingsChangeStreamHandler(private val context: Context) : EventChannel.S
}
} catch (e: Exception) {
- Log.w(LOG_TAG, "failed to get settings", e)
+ Log.w(LOG_TAG, "failed to get settings with error=${e.message}", null)
}
return changed
}
diff --git a/fastlane/metadata/android/de/full_description.txt b/fastlane/metadata/android/de/full_description.txt
index 15d681520..8e7929a6f 100644
--- a/fastlane/metadata/android/de/full_description.txt
+++ b/fastlane/metadata/android/de/full_description.txt
@@ -2,4 +2,4 @@
Navigation und Suche ist ein wichtiger Bestandteil von Aves. Das Ziel besteht darin, dass Benutzer problemlos von Alben zu Fotos zu Tags zu Karten usw. wechseln können.
-Aves lässt sich mit Android (von API 20 bis 31, d. h. von Lollipop bis S) mit Funktionen wie App-Verknüpfungen und globaler Suche integrieren. Es funktioniert auch als Medienbetrachter und -auswahl.
\ No newline at end of file
+Aves lässt sich mit Android (von API 19 bis 31, d. h. von KitKat bis S) mit Funktionen wie App-Verknüpfungen und globaler Suche integrieren. Es funktioniert auch als Medienbetrachter und -auswahl.
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt
index c7ccffdc9..8a74c8d0b 100644
--- a/fastlane/metadata/android/en-US/full_description.txt
+++ b/fastlane/metadata/android/en-US/full_description.txt
@@ -2,4 +2,4 @@
Navigation and search is an important part of Aves. The goal is for users to easily flow from albums to photos to tags to maps, etc.
-Aves integrates with Android (from API 20 to 31, i.e. from Lollipop to S) with features such as app shortcuts and global search handling. It also works as a media viewer and picker.
\ No newline at end of file
+Aves integrates with Android (from API 19 to 31, i.e. from KitKat to S) with features such as app shortcuts and global search handling. It also works as a media viewer and picker.
\ No newline at end of file
diff --git a/lib/model/availability.dart b/lib/model/availability.dart
index 828fda49e..2ba3c216f 100644
--- a/lib/model/availability.dart
+++ b/lib/model/availability.dart
@@ -1,6 +1,7 @@
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/durations.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
+import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:github/github.dart';
@@ -17,6 +18,8 @@ abstract class AvesAvailability {
Future get canLocatePlaces;
+ Future get canUseGoogleMaps;
+
Future get isNewVersionAvailable;
}
@@ -59,6 +62,13 @@ class LiveAvesAvailability implements AvesAvailability {
@override
Future get canLocatePlaces => Future.wait([isConnected, hasPlayServices]).then((results) => results.every((result) => result));
+ // as of google_maps_flutter v2.1.1, minSDK is 20 because of default PlatformView usage,
+ // but using hybrid composition would make it usable on 19 too, cf https://github.com/flutter/flutter/issues/23728
+ Future get _isUseGoogleMapRenderingSupported => DeviceInfoPlugin().androidInfo.then((androidInfo) => (androidInfo.version.sdkInt ?? 0) >= 20);
+
+ @override
+ Future get canUseGoogleMaps => Future.wait([_isUseGoogleMapRenderingSupported, hasPlayServices]).then((results) => results.every((result) => result));
+
@override
Future get isNewVersionAvailable async {
if (_isNewVersionAvailable != null) return SynchronousFuture(_isNewVersionAvailable!);
diff --git a/lib/model/settings/settings.dart b/lib/model/settings/settings.dart
index 62f76fd1c..25522d64f 100644
--- a/lib/model/settings/settings.dart
+++ b/lib/model/settings/settings.dart
@@ -152,8 +152,8 @@ class Settings extends ChangeNotifier {
enableOverlayBlurEffect = performanceClass >= 29;
// availability
- final hasPlayServices = await availability.hasPlayServices;
- if (hasPlayServices) {
+ final canUseGoogleMaps = await availability.canUseGoogleMaps;
+ if (canUseGoogleMaps) {
infoMapStyle = EntryMapStyle.googleNormal;
} else {
final styles = EntryMapStyle.values.whereNot((v) => v.isGoogleMaps).toList();
diff --git a/lib/widgets/common/map/buttons.dart b/lib/widgets/common/map/buttons.dart
index 0745868a2..dc5156dcd 100644
--- a/lib/widgets/common/map/buttons.dart
+++ b/lib/widgets/common/map/buttons.dart
@@ -135,8 +135,8 @@ class MapButtonPanel extends StatelessWidget {
child: MapOverlayButton(
icon: const Icon(AIcons.layers),
onPressed: () async {
- final hasPlayServices = await availability.hasPlayServices;
- final availableStyles = EntryMapStyle.values.where((style) => !style.isGoogleMaps || hasPlayServices);
+ final canUseGoogleMaps = await availability.canUseGoogleMaps;
+ final availableStyles = EntryMapStyle.values.where((style) => !style.isGoogleMaps || canUseGoogleMaps);
final preferredStyle = settings.infoMapStyle;
final initialStyle = availableStyles.contains(preferredStyle) ? preferredStyle : availableStyles.first;
final style = await showDialog(
diff --git a/pubspec.lock b/pubspec.lock
index 01702bd34..95ebebf7c 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -119,14 +119,14 @@ packages:
name: connectivity_plus
url: "https://pub.dartlang.org"
source: hosted
- version: "2.0.2"
+ version: "2.0.3"
connectivity_plus_linux:
dependency: transitive
description:
name: connectivity_plus_linux
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
+ version: "1.1.1"
connectivity_plus_macos:
dependency: transitive
description:
@@ -140,7 +140,7 @@ packages:
name: connectivity_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
+ version: "1.1.1"
connectivity_plus_web:
dependency: transitive
description:
@@ -196,7 +196,7 @@ packages:
name: dbus
url: "https://pub.dartlang.org"
source: hosted
- version: "0.5.6"
+ version: "0.6.6"
decorated_icon:
dependency: "direct main"
description:
@@ -340,7 +340,7 @@ packages:
name: flex_color_picker
url: "https://pub.dartlang.org"
source: hosted
- version: "2.1.2"
+ version: "2.2.0"
fluster:
dependency: "direct main"
description:
@@ -404,7 +404,7 @@ packages:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
- version: "2.0.4"
+ version: "2.0.5"
flutter_staggered_animations:
dependency: "direct main"
description:
@@ -468,7 +468,7 @@ packages:
name: google_maps_flutter
url: "https://pub.dartlang.org"
source: hosted
- version: "2.1.0"
+ version: "2.1.1"
google_maps_flutter_platform_interface:
dependency: transitive
description:
@@ -573,7 +573,7 @@ packages:
name: markdown
url: "https://pub.dartlang.org"
source: hosted
- version: "4.0.0"
+ version: "4.0.1"
matcher:
dependency: transitive
description:
@@ -629,7 +629,7 @@ packages:
name: nm
url: "https://pub.dartlang.org"
source: hosted
- version: "0.3.0"
+ version: "0.4.1"
node_preamble:
dependency: transitive
description:
@@ -727,7 +727,7 @@ packages:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
- version: "2.1.0"
+ version: "2.1.2"
path_provider_platform_interface:
dependency: transitive
description:
@@ -741,14 +741,14 @@ packages:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
- version: "2.0.3"
+ version: "2.0.4"
pdf:
dependency: "direct main"
description:
name: pdf
url: "https://pub.dartlang.org"
source: hosted
- version: "3.6.1"
+ version: "3.6.3"
pedantic:
dependency: transitive
description:
@@ -769,7 +769,7 @@ packages:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
- version: "8.2.6"
+ version: "8.3.0"
permission_handler_platform_interface:
dependency: transitive
description:
@@ -818,7 +818,7 @@ packages:
name: printing
url: "https://pub.dartlang.org"
source: hosted
- version: "5.6.0"
+ version: "5.6.3"
process:
dependency: transitive
description:
@@ -867,6 +867,20 @@ packages:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
+ version: "2.0.9"
+ shared_preferences_android:
+ dependency: transitive
+ description:
+ name: shared_preferences_android
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.9"
+ shared_preferences_ios:
+ dependency: transitive
+ description:
+ name: shared_preferences_ios
+ url: "https://pub.dartlang.org"
+ source: hosted
version: "2.0.8"
shared_preferences_linux:
dependency: transitive
@@ -874,7 +888,7 @@ packages:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
- version: "2.0.2"
+ version: "2.0.3"
shared_preferences_macos:
dependency: transitive
description:
@@ -902,7 +916,7 @@ packages:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
- version: "2.0.2"
+ version: "2.0.3"
shelf:
dependency: transitive
description:
@@ -1084,7 +1098,7 @@ packages:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
- version: "6.0.12"
+ version: "6.0.15"
url_launcher_linux:
dependency: transitive
description:
@@ -1175,7 +1189,7 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
- version: "2.2.10"
+ version: "2.3.0"
wkt_parser:
dependency: transitive
description: