diff --git a/lib/main.dart b/lib/main.dart index 8f5c38d..fb3a711 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,7 +19,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart'; // ignore: implementation_imports import 'package:easy_localization/src/localization.dart'; -const String currentVersion = '0.14.5'; +const String currentVersion = '0.14.6'; const String currentReleaseTag = 'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 5017e26..cad3b2f 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:math'; import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart'; import 'package:android_intent_plus/flag.dart'; @@ -116,16 +117,19 @@ moveStrToEnd(List arr, String str, {String? strB}) { return arr; } -moveStrToEndMapEntryWithCount( +List> moveStrToEndMapEntryWithCount( List> arr, MapEntry str, {MapEntry? strB}) { MapEntry? temp; arr.removeWhere((element) { - bool res = element.key == str.key || element.key == strB?.key; - if (res) { - temp = element; + bool resA = element.key == str.key; + bool resB = element.key == strB?.key; + if (resA) { + temp = str; + } else if (resB) { + temp = strB; } - return res; + return resA || resB; }); if (temp != null) { arr = [...arr, temp!]; @@ -364,6 +368,9 @@ class AppsProvider with ChangeNotifier { Future canInstallSilently( App app, SettingsProvider settingsProvider) async { + if (app.id == obtainiumId) { + return false; + } if (!settingsProvider.enableBackgroundUpdates) { return false; } @@ -393,7 +400,7 @@ class AppsProvider with ChangeNotifier { (await getInstalledInfo(app.id))?.applicationInfo?.targetSdkVersion; // The OS must also be new enough and the APK should target a new enough API - return osInfo.version.sdkInt >= 30 && + return osInfo.version.sdkInt >= 31 && targetSDK != null && targetSDK >= // https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int) (osInfo.version.sdkInt - 3); @@ -1331,67 +1338,75 @@ Future bgUpdateCheck(int taskId, Map? params) async { (netResult != ConnectivityResult.ethernet); } // Loop through all updates and check each - for (int i = 0; i < toCheck.length; i++) { - var appId = toCheck[i].key; - var retryCount = toCheck[i].value; - AppInMemory? app = appsProvider.apps[appId]; - if (app?.app.installedVersion != null) { - try { - notificationsProvider.notify( - notif = CheckingUpdatesNotification(app?.name ?? appId), - cancelExisting: true); - App? newApp = await appsProvider.checkUpdate(appId); - if (newApp != null) { - if (networkRestricted || - !(await appsProvider.canInstallSilently( - app!.app, settingsProvider))) { - notificationsProvider.notify( - UpdateNotification([newApp], id: newApp.id.hashCode - 1)); + List toNotify = []; + try { + for (int i = 0; i < toCheck.length; i++) { + var appId = toCheck[i].key; + var attemptCount = toCheck[i].value + 1; + AppInMemory? app = appsProvider.apps[appId]; + if (app?.app.installedVersion != null) { + try { + notificationsProvider.notify( + notif = CheckingUpdatesNotification(app?.name ?? appId), + cancelExisting: true); + App? newApp = await appsProvider.checkUpdate(appId); + if (newApp != null) { + if (networkRestricted || + !(await appsProvider.canInstallSilently( + app!.app, settingsProvider))) { + toNotify.add(newApp); + } else { + toInstall.add(MapEntry(appId, 0)); + } + } + if (i == (toCheck.length - 1)) { + didCompleteChecking = true; + } + } catch (e) { + // If you got an error, move the offender to the back of the line (increment their fail count) and schedule another task to continue checking shortly + logs.add( + 'BG update task $taskId: Got error on checking for $appId \'${e.toString()}\'.'); + if (attemptCount < maxAttempts) { + var remainingSeconds = e is RateLimitError + ? (i == 0 ? (e.remainingMinutes * 60) : (5 * 60)) + : e is ClientException + ? (15 * 60) + : pow(attemptCount, 2).toInt(); + logs.add( + 'BG update task $taskId: Will continue in $remainingSeconds seconds (with $appId moved to the end of the line).'); + var remainingToCheck = moveStrToEndMapEntryWithCount( + toCheck.sublist(i), MapEntry(appId, attemptCount)); + AndroidAlarmManager.oneShot(Duration(seconds: remainingSeconds), + taskId + 1, bgUpdateCheck, + params: { + 'toCheck': remainingToCheck + .map( + (entry) => {'key': entry.key, 'value': entry.value}) + .toList(), + 'toInstall': toInstall + .map( + (entry) => {'key': entry.key, 'value': entry.value}) + .toList(), + }); + break; } else { - toInstall.add(MapEntry(appId, 0)); + // If the offender has reached its fail limit, notify the user and remove it from the list (task can continue) + toCheck.removeAt(i); + i--; + notificationsProvider + .notify(ErrorCheckingUpdatesNotification(e.toString())); + } + } finally { + if (notif != null) { + notificationsProvider.cancel(notif.id); } } - if (i == (toCheck.length - 1)) { - didCompleteChecking = true; - } - } catch (e) { - // If you got an error, move the offender to the back of the line (increment their fail count) and schedule another task to continue checking shortly - logs.add( - 'BG update task $taskId: Got error on checking for $appId \'${e.toString()}\'.'); - if (retryCount < maxAttempts) { - var remainingSeconds = e is RateLimitError - ? (i == 0 ? (e.remainingMinutes * 60) : (5 * 60)) - : e is ClientException - ? (15 * 60) - : (retryCount ^ 2); - logs.add( - 'BG update task $taskId: Will continue in $remainingSeconds seconds (with $appId moved to the end of the line).'); - var remainingToCheck = moveStrToEndMapEntryWithCount( - toCheck.sublist(i), MapEntry(appId, retryCount + 1)); - AndroidAlarmManager.oneShot( - Duration(seconds: remainingSeconds), taskId + 1, bgUpdateCheck, - params: { - 'toCheck': remainingToCheck - .map((entry) => {'key': entry.key, 'value': entry.value}) - .toList(), - 'toInstall': toInstall - .map((entry) => {'key': entry.key, 'value': entry.value}) - .toList(), - }); - break; - } else { - // If the offender has reached its fail limit, notify the user and remove it from the list (task can continue) - toCheck.removeAt(i); - i--; - notificationsProvider - .notify(ErrorCheckingUpdatesNotification(e.toString())); - } - } finally { - if (notif != null) { - notificationsProvider.cancel(notif.id); - } } } + } finally { + if (toNotify.isNotEmpty) { + notificationsProvider.notify(UpdateNotification(toNotify)); + } } // If you're done checking and found some silently installable updates, schedule another task which will run in install mode if (didCompleteChecking && toInstall.isNotEmpty) { diff --git a/pubspec.yaml b/pubspec.yaml index c32228b..61b3d06 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.14.5+197 # When changing this, update the tag in main() accordingly +version: 0.14.6+198 # When changing this, update the tag in main() accordingly environment: sdk: '>=2.18.2 <3.0.0'