Compare commits
14 Commits
update_doc
...
fdroid-v0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
417621b17c | ||
|
|
8322540732 | ||
|
|
2d61be37bb | ||
|
|
2a10aa7d61 | ||
|
|
1c1c9bb0d7 | ||
|
|
b96e7341e3 | ||
|
|
163c5de1cc | ||
|
|
124ef86054 | ||
|
|
004eb310b3 | ||
|
|
ccb6a4a283 | ||
|
|
a3c80556d2 | ||
|
|
851ce5de73 | ||
|
|
f8d956d47f | ||
|
|
7543dc6b57 |
2
.github/workflows/mobile-release.yml
vendored
2
.github/workflows/mobile-release.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
|||||||
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD_PHOTOS }}
|
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD_PHOTOS }}
|
||||||
|
|
||||||
- name: Checksum
|
- name: Checksum
|
||||||
run: sha256sum build/app/outputs/flutter-apk/ente.apk > build/app/outputs/flutter-apk/sha256sum
|
run: sha256sum build/app/outputs/flutter-apk/ente-${{ github.ref_name }}.apk > build/app/outputs/flutter-apk/sha256sum
|
||||||
|
|
||||||
- name: Create a draft GitHub release
|
- name: Create a draft GitHub release
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
|
|||||||
13
.gitmodules
vendored
13
.gitmodules
vendored
@@ -9,16 +9,9 @@
|
|||||||
[submodule "auth/assets/simple-icons"]
|
[submodule "auth/assets/simple-icons"]
|
||||||
path = auth/assets/simple-icons
|
path = auth/assets/simple-icons
|
||||||
url = https://github.com/simple-icons/simple-icons.git
|
url = https://github.com/simple-icons/simple-icons.git
|
||||||
[submodule "mobile/thirdparty/flutter"]
|
|
||||||
path = mobile/thirdparty/flutter
|
|
||||||
url = https://github.com/flutter/flutter.git
|
|
||||||
branch = stable
|
|
||||||
[submodule "mobile/plugins/clip_ggml"]
|
[submodule "mobile/plugins/clip_ggml"]
|
||||||
path = mobile/plugins/clip_ggml
|
path = mobile/plugins/clip_ggml
|
||||||
url = https://github.com/ente-io/clip-ggml.git
|
url = https://github.com/ente-io/clip-ggml.git
|
||||||
[submodule "mobile/thirdparty/isar"]
|
|
||||||
path = mobile/thirdparty/isar
|
|
||||||
url = https://github.com/isar/isar
|
|
||||||
[submodule "web/apps/photos/thirdparty/ffmpeg-wasm"]
|
[submodule "web/apps/photos/thirdparty/ffmpeg-wasm"]
|
||||||
path = web/apps/photos/thirdparty/ffmpeg-wasm
|
path = web/apps/photos/thirdparty/ffmpeg-wasm
|
||||||
url = https://github.com/abhinavkgrd/ffmpeg.wasm.git
|
url = https://github.com/abhinavkgrd/ffmpeg.wasm.git
|
||||||
@@ -27,3 +20,9 @@
|
|||||||
path = web/apps/photos/thirdparty/photoswipe
|
path = web/apps/photos/thirdparty/photoswipe
|
||||||
url = https://github.com/ente-io/PhotoSwipe.git
|
url = https://github.com/ente-io/PhotoSwipe.git
|
||||||
branch = single-thread
|
branch = single-thread
|
||||||
|
[submodule "mobile/thirdparty/isar"]
|
||||||
|
path = mobile/thirdparty/isar
|
||||||
|
url = https://github.com/isar/isar
|
||||||
|
[submodule "mobile/thirdparty/flutter"]
|
||||||
|
path = mobile/thirdparty/flutter
|
||||||
|
url = https://github.com/flutter/flutter
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ configure the endpoint the app should be connecting to.
|
|||||||
|
|
||||||
# CLI
|
# CLI
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> The new version of CLI that supports connecting to custom server is still in beta.
|
||||||
|
> You can download the beta version from [here](https://github.com/ente-io/ente/releases?q=tag%3Acli-v0&expanded=true)
|
||||||
|
|
||||||
Define a config.yaml and put it either in the same directory as CLI or path defined in env variable `ENTE_CLI_CONFIG_PATH`
|
Define a config.yaml and put it either in the same directory as CLI or path defined in env variable `ENTE_CLI_CONFIG_PATH`
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ You can alternatively install the build from PlayStore or F-Droid.
|
|||||||
|
|
||||||
## 🧑💻 Building from source
|
## 🧑💻 Building from source
|
||||||
|
|
||||||
1. [Install Flutter v3.13.4](https://flutter.dev/docs/get-started/install) or
|
1. [Install Flutter v3.13.4](https://flutter.dev/docs/get-started/install).
|
||||||
set the Path of Flutter SDK to `thirdparty/flutter/bin`.
|
|
||||||
|
|
||||||
2. Pull in all submodules with `git submodule update --init --recursive`
|
2. Pull in all submodules with `git submodule update --init --recursive`
|
||||||
|
|
||||||
|
|||||||
@@ -18,10 +18,7 @@ allprojects {
|
|||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
// mavenLocal() // for FDroid
|
mavenLocal() // for FDroid
|
||||||
maven {
|
|
||||||
url "${project(':background_fetch').projectDir}/libs"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"dart.flutterSdkPath": "thirdparty/flutter/bin"
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ import 'dart:io';
|
|||||||
import "package:adaptive_theme/adaptive_theme.dart";
|
import "package:adaptive_theme/adaptive_theme.dart";
|
||||||
import 'package:background_fetch/background_fetch.dart';
|
import 'package:background_fetch/background_fetch.dart';
|
||||||
import "package:computer/computer.dart";
|
import "package:computer/computer.dart";
|
||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import "package:flutter/rendering.dart";
|
import "package:flutter/rendering.dart";
|
||||||
@@ -34,7 +33,6 @@ import "package:photos/services/location_service.dart";
|
|||||||
import "package:photos/services/machine_learning/machine_learning_controller.dart";
|
import "package:photos/services/machine_learning/machine_learning_controller.dart";
|
||||||
import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart';
|
import 'package:photos/services/machine_learning/semantic_search/semantic_search_service.dart';
|
||||||
import 'package:photos/services/memories_service.dart';
|
import 'package:photos/services/memories_service.dart';
|
||||||
import 'package:photos/services/push_service.dart';
|
|
||||||
import 'package:photos/services/remote_sync_service.dart';
|
import 'package:photos/services/remote_sync_service.dart';
|
||||||
import 'package:photos/services/search_service.dart';
|
import 'package:photos/services/search_service.dart';
|
||||||
import "package:photos/services/storage_bonus_service.dart";
|
import "package:photos/services/storage_bonus_service.dart";
|
||||||
@@ -216,14 +214,6 @@ Future<void> _init(bool isBackground, {String via = ''}) async {
|
|||||||
unawaited(HomeWidgetService.instance.initHomeWidget());
|
unawaited(HomeWidgetService.instance.initHomeWidget());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Platform.isIOS) {
|
|
||||||
// ignore: unawaited_futures
|
|
||||||
PushService.instance.init().then((_) {
|
|
||||||
FirebaseMessaging.onBackgroundMessage(
|
|
||||||
_firebaseMessagingBackgroundHandler,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
unawaited(FeatureFlagService.instance.init());
|
unawaited(FeatureFlagService.instance.init());
|
||||||
unawaited(SemanticSearchService.instance.init());
|
unawaited(SemanticSearchService.instance.init());
|
||||||
MachineLearningController.instance.init();
|
MachineLearningController.instance.init();
|
||||||
@@ -334,35 +324,6 @@ Future<void> _killBGTask([String? taskId]) async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
|
||||||
final bool isRunningInFG = await _isRunningInForeground(); // hb
|
|
||||||
final bool isInForeground = AppLifecycleService.instance.isForeground;
|
|
||||||
if (_isProcessRunning) {
|
|
||||||
_logger.info(
|
|
||||||
"Background push received when app is alive and runningInFS: $isRunningInFG inForeground: $isInForeground",
|
|
||||||
);
|
|
||||||
if (PushService.shouldSync(message)) {
|
|
||||||
await _sync('firebaseBgSyncActiveProcess');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// App is dead
|
|
||||||
// ignore: unawaited_futures
|
|
||||||
_runWithLogs(
|
|
||||||
() async {
|
|
||||||
_logger.info("Background push received");
|
|
||||||
if (Platform.isIOS) {
|
|
||||||
_scheduleSuicide(kBGPushTimeout); // To prevent OS from punishing us
|
|
||||||
}
|
|
||||||
await _init(true, via: 'firebasePush');
|
|
||||||
if (PushService.shouldSync(message)) {
|
|
||||||
await _sync('firebaseBgSyncNoActiveProcess');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
prefix: "[fbg]",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _logFGHeartBeatInfo() async {
|
Future<void> _logFGHeartBeatInfo() async {
|
||||||
final bool isRunningInFG = await _isRunningInForeground();
|
final bool isRunningInFG = await _isRunningInForeground();
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import 'package:dio/dio.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
// import 'package:flutter/foundation.dart';
|
// import 'package:flutter/foundation.dart';
|
||||||
// import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
|
// import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
|
||||||
import 'package:in_app_purchase/in_app_purchase.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:photos/core/errors.dart';
|
import 'package:photos/core/errors.dart';
|
||||||
import 'package:photos/core/network/network.dart';
|
import 'package:photos/core/network/network.dart';
|
||||||
@@ -35,6 +34,7 @@ class BillingService {
|
|||||||
final _logger = Logger("BillingService");
|
final _logger = Logger("BillingService");
|
||||||
final _enteDio = NetworkClient.instance.enteDio;
|
final _enteDio = NetworkClient.instance.enteDio;
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
bool _isOnSubscriptionPage = false;
|
bool _isOnSubscriptionPage = false;
|
||||||
|
|
||||||
Future<BillingPlans>? _future;
|
Future<BillingPlans>? _future;
|
||||||
@@ -44,23 +44,6 @@ class BillingService {
|
|||||||
// await FlutterInappPurchase.instance.initConnection;
|
// await FlutterInappPurchase.instance.initConnection;
|
||||||
// FlutterInappPurchase.instance.clearTransactionIOS();
|
// FlutterInappPurchase.instance.clearTransactionIOS();
|
||||||
// }
|
// }
|
||||||
InAppPurchase.instance.purchaseStream.listen((purchases) {
|
|
||||||
if (_isOnSubscriptionPage) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (final purchase in purchases) {
|
|
||||||
if (purchase.status == PurchaseStatus.purchased) {
|
|
||||||
verifySubscription(
|
|
||||||
purchase.productID,
|
|
||||||
purchase.verificationData.serverVerificationData,
|
|
||||||
).then((response) {
|
|
||||||
InAppPurchase.instance.completePurchase(purchase);
|
|
||||||
});
|
|
||||||
} else if (Platform.isIOS && purchase.pendingCompletePurchase) {
|
|
||||||
InAppPurchase.instance.completePurchase(purchase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearCache() {
|
void clearCache() {
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import "package:photos/ui/payment/store_subscription_page.dart";
|
|||||||
import 'package:photos/ui/payment/stripe_subscription_page.dart';
|
import 'package:photos/ui/payment/stripe_subscription_page.dart';
|
||||||
|
|
||||||
StatefulWidget getSubscriptionPage({bool isOnBoarding = false}) {
|
StatefulWidget getSubscriptionPage({bool isOnBoarding = false}) {
|
||||||
if (UpdateService.instance.isIndependentFlavor()) {
|
if (UpdateService.instance.isIndependentFlavor() ||
|
||||||
|
UpdateService.instance.isFdroidFlavor()) {
|
||||||
return StripeSubscriptionPage(isOnboarding: isOnBoarding);
|
return StripeSubscriptionPage(isOnboarding: isOnBoarding);
|
||||||
}
|
}
|
||||||
if (FeatureFlagService.instance.enableStripe() &&
|
if (FeatureFlagService.instance.enableStripe() &&
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ description: ente photos application
|
|||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
|
|
||||||
version: 0.8.68+588
|
version: 0.8.70+590
|
||||||
publish_to: none
|
publish_to: none
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
@@ -64,8 +64,6 @@ dependencies:
|
|||||||
file_saver:
|
file_saver:
|
||||||
# Use forked version till this PR is merged: https://github.com/incrediblezayed/file_saver/pull/87
|
# Use forked version till this PR is merged: https://github.com/incrediblezayed/file_saver/pull/87
|
||||||
git: https://github.com/jesims/file_saver.git
|
git: https://github.com/jesims/file_saver.git
|
||||||
firebase_core: ^2.13.1
|
|
||||||
firebase_messaging: ^14.6.2
|
|
||||||
fk_user_agent: ^2.0.1
|
fk_user_agent: ^2.0.1
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
@@ -99,7 +97,6 @@ dependencies:
|
|||||||
http: ^1.1.0
|
http: ^1.1.0
|
||||||
image: ^4.0.17
|
image: ^4.0.17
|
||||||
image_editor: ^1.3.0
|
image_editor: ^1.3.0
|
||||||
in_app_purchase: ^3.0.7
|
|
||||||
intl: ^0.18.0
|
intl: ^0.18.0
|
||||||
isar: ^3.1.0+1
|
isar: ^3.1.0+1
|
||||||
isar_flutter_libs: ^3.1.0+1
|
isar_flutter_libs: ^3.1.0+1
|
||||||
@@ -207,7 +204,7 @@ flutter_icons:
|
|||||||
android: "launcher_icon"
|
android: "launcher_icon"
|
||||||
adaptive_icon_foreground: "assets/launcher_icon/ente-icon-foreground.png"
|
adaptive_icon_foreground: "assets/launcher_icon/ente-icon-foreground.png"
|
||||||
adaptive_icon_background: "#ffffff"
|
adaptive_icon_background: "#ffffff"
|
||||||
ios: true
|
ios: false # F-Droid
|
||||||
image_path: "assets/icon-light.png"
|
image_path: "assets/icon-light.png"
|
||||||
|
|
||||||
flutter_native_splash:
|
flutter_native_splash:
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
# TODO: add `rustup@1.25.2` to `srclibs`
|
|
||||||
# TODO: verify if `gcc-multilib` or `libc-dev` is needed
|
|
||||||
$$rustup$$/rustup-init.sh -y
|
|
||||||
source $HOME/.cargo/env
|
|
||||||
cd thirdparty/isar/
|
cd thirdparty/isar/
|
||||||
bash tool/build_android.sh x86
|
bash tool/build_android.sh x86
|
||||||
bash tool/build_android.sh x64
|
bash tool/build_android.sh x64
|
||||||
@@ -15,3 +11,4 @@ mv libisar_android_x64.so libisar.so
|
|||||||
mv libisar.so $PUB_CACHE/hosted/pub.dev/isar_flutter_libs-*/android/src/main/jniLibs/x86_64/
|
mv libisar.so $PUB_CACHE/hosted/pub.dev/isar_flutter_libs-*/android/src/main/jniLibs/x86_64/
|
||||||
mv libisar_android_x86.so libisar.so
|
mv libisar_android_x86.so libisar.so
|
||||||
mv libisar.so $PUB_CACHE/hosted/pub.dev/isar_flutter_libs-*/android/src/main/jniLibs/x86/
|
mv libisar.so $PUB_CACHE/hosted/pub.dev/isar_flutter_libs-*/android/src/main/jniLibs/x86/
|
||||||
|
cd ../../
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
# Eclipse
|
|
||||||
.metadata
|
|
||||||
|
|
||||||
# Xcode
|
|
||||||
#
|
|
||||||
.DS_Store
|
|
||||||
build/
|
|
||||||
*.pbxuser
|
|
||||||
!default.pbxuser
|
|
||||||
*.mode1v3
|
|
||||||
!default.mode1v3
|
|
||||||
*.mode2v3
|
|
||||||
!default.mode2v3
|
|
||||||
*.perspectivev3
|
|
||||||
!default.perspectivev3
|
|
||||||
xcuserdata
|
|
||||||
*.xccheckout
|
|
||||||
*.moved-aside
|
|
||||||
DerivedData
|
|
||||||
*.hmap
|
|
||||||
*.ipa
|
|
||||||
*.xcuserstate
|
|
||||||
|
|
||||||
# CocoaPods
|
|
||||||
#
|
|
||||||
# We recommend against adding the Pods directory to your .gitignore. However
|
|
||||||
# you should judge for yourself, the pros and cons are mentioned at:
|
|
||||||
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
|
|
||||||
#
|
|
||||||
#Pods/
|
|
||||||
|
|
||||||
# Eclipse
|
|
||||||
|
|
||||||
# built application files
|
|
||||||
*.apk
|
|
||||||
*.ap_
|
|
||||||
|
|
||||||
# files for the dex VM
|
|
||||||
*.dex
|
|
||||||
|
|
||||||
# Java class files
|
|
||||||
*.class
|
|
||||||
|
|
||||||
# generated files
|
|
||||||
bin/
|
|
||||||
gen/
|
|
||||||
|
|
||||||
# Local configuration file (sdk path, etc)
|
|
||||||
local.properties
|
|
||||||
|
|
||||||
# Eclipse project files
|
|
||||||
.classpath
|
|
||||||
.project
|
|
||||||
|
|
||||||
# Proguard folder generated by Eclipse
|
|
||||||
proguard/
|
|
||||||
|
|
||||||
# Intellij project files
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
*.iws
|
|
||||||
.idea/
|
|
||||||
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 26
|
compileSdkVersion 30
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.transistorsoft.backgroundfetch"
|
applicationId "com.transistorsoft.backgroundfetch"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 26
|
targetSdkVersion 30
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
@@ -24,6 +24,5 @@ dependencies {
|
|||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
|
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation 'com.android.support:appcompat-v7:26.1.0'
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||||
|
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
@@ -18,7 +18,7 @@ buildscript {
|
|||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,8 +27,8 @@ task clean(type: Delete) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
compileSdkVersion = 29
|
compileSdkVersion = 32
|
||||||
targetSdkVersion = 29
|
targetSdkVersion = 31
|
||||||
buildToolsVersion = "29.0.6"
|
buildToolsVersion = "29.0.6"
|
||||||
appCompatVersion = "1.1.0"
|
appCompatVersion = "1.4.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ org.gradle.jvmargs=-Xmx1536m
|
|||||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
# org.gradle.parallel=true
|
# org.gradle.parallel=true
|
||||||
|
|
||||||
VERSION_NAME=0.5.0
|
VERSION_NAME=0.5.6
|
||||||
VERSION_CODE=15
|
VERSION_CODE=21
|
||||||
|
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#Thu Feb 09 18:40:48 IST 2023
|
#Thu Jul 15 09:21:17 EDT 2021
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
distributionSha256Sum=10065868c78f1207afb3a92176f99a37d753a513dff453abb6b5cceda4058cda
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ android {
|
|||||||
mavenLocal()
|
mavenLocal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -40,15 +44,14 @@ dependencies {
|
|||||||
|
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
|
||||||
|
implementation "androidx.lifecycle:lifecycle-runtime:2.5.1"
|
||||||
|
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
|
||||||
//implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion"
|
//implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build Release
|
// Build Release
|
||||||
task buildRelease { task ->
|
task buildRelease { task ->
|
||||||
task.dependsOn 'cordovaRelease'
|
|
||||||
task.dependsOn 'reactNativeRelease'
|
|
||||||
task.dependsOn 'nativeScriptRelease'
|
|
||||||
task.dependsOn 'flutterRelease'
|
task.dependsOn 'flutterRelease'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ task publishRelease { task ->
|
|||||||
tasks["publishRelease"].mustRunAfter("assembleRelease")
|
tasks["publishRelease"].mustRunAfter("assembleRelease")
|
||||||
tasks["publishRelease"].finalizedBy("publish")
|
tasks["publishRelease"].finalizedBy("publish")
|
||||||
|
|
||||||
def WORKSPACE_PATH = "/Volumes/Glyph2TB/Users/chris/workspace"
|
def WORKSPACE_PATH = "/Users/chris/workspace"
|
||||||
|
|
||||||
// Build local maven repo.
|
// Build local maven repo.
|
||||||
def LIBRARY_PATH = "com/transistorsoft/tsbackgroundfetch"
|
def LIBRARY_PATH = "com/transistorsoft/tsbackgroundfetch"
|
||||||
@@ -78,7 +81,7 @@ task buildLocalRepository { task ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def cordovaDir = "$WORKSPACE_PATH/cordova/background-geolocation/cordova-plugin-background-fetch"
|
def cordovaDir = "$WORKSPACE_PATH/background-geolocation/cordova/cordova-plugin-background-fetch"
|
||||||
task cordovaRelease { task ->
|
task cordovaRelease { task ->
|
||||||
task.dependsOn 'buildLocalRepository'
|
task.dependsOn 'buildLocalRepository'
|
||||||
doLast {
|
doLast {
|
||||||
@@ -95,7 +98,7 @@ task cordovaRelease { task ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def reactNativeDir = "$WORKSPACE_PATH/react/background-geolocation/react-native-background-fetch"
|
def reactNativeDir = "$WORKSPACE_PATH/background-geolocation/react/react-native-background-fetch"
|
||||||
task reactNativeRelease { task ->
|
task reactNativeRelease { task ->
|
||||||
task.dependsOn 'buildLocalRepository'
|
task.dependsOn 'buildLocalRepository'
|
||||||
doLast {
|
doLast {
|
||||||
@@ -129,6 +132,19 @@ task flutterRelease { task ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def capacitorDir = "$WORKSPACE_PATH/background-geolocation/capacitor/capacitor-background-fetch"
|
||||||
|
task capacitorRelease { task ->
|
||||||
|
task.dependsOn 'buildLocalRepository'
|
||||||
|
doLast {
|
||||||
|
delete "$capacitorDir/android/libs"
|
||||||
|
copy {
|
||||||
|
// Maven repo format.
|
||||||
|
from("$buildDir/repo-local")
|
||||||
|
into("$capacitorDir/android/libs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
task nativeScriptRelease(type: Copy) {
|
task nativeScriptRelease(type: Copy) {
|
||||||
from('./build/outputs/aar/tsbackgroundfetch-release.aar')
|
from('./build/outputs/aar/tsbackgroundfetch-release.aar')
|
||||||
into("$WORKSPACE_PATH/NativeScript/background-geolocation/nativescript-background-fetch/src/platforms/android/libs")
|
into("$WORKSPACE_PATH/NativeScript/background-geolocation/nativescript-background-fetch/src/platforms/android/libs")
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.GET_TASKS" />
|
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||||
|
|
||||||
<application>
|
<application>
|
||||||
<receiver android:name="com.transistorsoft.tsbackgroundfetch.FetchAlarmReceiver" />
|
<receiver android:name="com.transistorsoft.tsbackgroundfetch.FetchAlarmReceiver" />
|
||||||
<service android:name="com.transistorsoft.tsbackgroundfetch.FetchJobService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" />
|
<service android:name="com.transistorsoft.tsbackgroundfetch.FetchJobService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" />
|
||||||
<receiver android:name="com.transistorsoft.tsbackgroundfetch.BootReceiver">
|
<receiver android:name="com.transistorsoft.tsbackgroundfetch.BootReceiver" android:exported="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
|
|||||||
@@ -110,6 +110,16 @@ public class BGTask {
|
|||||||
removeTask(mTaskId);
|
removeTask(mTaskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void reschedule(Context context, BackgroundFetchConfig existing, BackgroundFetchConfig config) {
|
||||||
|
BGTask existingTask = BGTask.getTask(existing.getTaskId());
|
||||||
|
if (existingTask != null) {
|
||||||
|
existingTask.finish();
|
||||||
|
}
|
||||||
|
cancel(context, existing.getTaskId(), existing.getJobId());
|
||||||
|
|
||||||
|
schedule(context, config);
|
||||||
|
}
|
||||||
|
|
||||||
static void schedule(Context context, BackgroundFetchConfig config) {
|
static void schedule(Context context, BackgroundFetchConfig config) {
|
||||||
Log.d(BackgroundFetch.TAG, config.toString());
|
Log.d(BackgroundFetch.TAG, config.toString());
|
||||||
|
|
||||||
@@ -136,6 +146,8 @@ public class BGTask {
|
|||||||
}
|
}
|
||||||
PersistableBundle extras = new PersistableBundle();
|
PersistableBundle extras = new PersistableBundle();
|
||||||
extras.putString(BackgroundFetchConfig.FIELD_TASK_ID, config.getTaskId());
|
extras.putString(BackgroundFetchConfig.FIELD_TASK_ID, config.getTaskId());
|
||||||
|
extras.putLong("scheduled_at", System.currentTimeMillis());
|
||||||
|
|
||||||
builder.setExtras(extras);
|
builder.setExtras(extras);
|
||||||
|
|
||||||
if (android.os.Build.VERSION.SDK_INT >= 26) {
|
if (android.os.Build.VERSION.SDK_INT >= 26) {
|
||||||
@@ -172,7 +184,7 @@ public class BGTask {
|
|||||||
|
|
||||||
BackgroundFetch adapter = BackgroundFetch.getInstance(context);
|
BackgroundFetch adapter = BackgroundFetch.getInstance(context);
|
||||||
|
|
||||||
if (adapter.isMainActivityActive()) {
|
if (!LifecycleManager.getInstance().isHeadless()) {
|
||||||
BackgroundFetch.Callback callback = adapter.getFetchCallback();
|
BackgroundFetch.Callback callback = adapter.getFetchCallback();
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.onTimeout(mTaskId);
|
callback.onTimeout(mTaskId);
|
||||||
@@ -246,7 +258,7 @@ public class BGTask {
|
|||||||
static PendingIntent getAlarmPI(Context context, String taskId) {
|
static PendingIntent getAlarmPI(Context context, String taskId) {
|
||||||
Intent intent = new Intent(context, FetchAlarmReceiver.class);
|
Intent intent = new Intent(context, FetchAlarmReceiver.class);
|
||||||
intent.setAction(taskId);
|
intent.setAction(taskId);
|
||||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_IMMUTABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import android.annotation.TargetApi;
|
|||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@@ -76,6 +78,8 @@ public class BackgroundFetch {
|
|||||||
|
|
||||||
private BackgroundFetch(Context context) {
|
private BackgroundFetch(Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
// Start Lifecycle Observer to be notified when app enters background.
|
||||||
|
getUiHandler().post(LifecycleManager.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unused"})
|
@SuppressWarnings({"unused"})
|
||||||
@@ -84,7 +88,16 @@ public class BackgroundFetch {
|
|||||||
mFetchCallback = callback;
|
mFetchCallback = callback;
|
||||||
|
|
||||||
synchronized (mConfig) {
|
synchronized (mConfig) {
|
||||||
mConfig.put(config.getTaskId(), config);
|
if (mConfig.containsKey(config.getTaskId())) {
|
||||||
|
// Developer called `.configure` again. Re-configure the plugin by re-scheduling the fetch task.
|
||||||
|
BackgroundFetchConfig existing = mConfig.get(config.getTaskId());
|
||||||
|
Log.d(TAG, "Re-configured existing task");
|
||||||
|
BGTask.reschedule(mContext, existing, config);
|
||||||
|
mConfig.put(config.getTaskId(), config);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
mConfig.put(config.getTaskId(), config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
start(config.getTaskId());
|
start(config.getTaskId());
|
||||||
}
|
}
|
||||||
@@ -224,8 +237,6 @@ public class BackgroundFetch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void registerTask(String taskId) {
|
private void registerTask(String taskId) {
|
||||||
Log.d(TAG, "- registerTask: " + taskId);
|
|
||||||
|
|
||||||
BackgroundFetchConfig config = getConfig(taskId);
|
BackgroundFetchConfig config = getConfig(taskId);
|
||||||
|
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
@@ -234,6 +245,12 @@ public class BackgroundFetch {
|
|||||||
}
|
}
|
||||||
config.save(mContext);
|
config.save(mContext);
|
||||||
|
|
||||||
|
String msg = "- registerTask: " + taskId;
|
||||||
|
if (!config.getForceAlarmManager()) {
|
||||||
|
msg += " (jobId: " + config.getJobId() + ")";
|
||||||
|
}
|
||||||
|
Log.d(TAG, msg);
|
||||||
|
|
||||||
BGTask.schedule(mContext, config);
|
BGTask.schedule(mContext, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +262,7 @@ public class BackgroundFetch {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMainActivityActive()) {
|
if (!LifecycleManager.getInstance().isHeadless()) {
|
||||||
if (mFetchCallback != null) {
|
if (mFetchCallback != null) {
|
||||||
mFetchCallback.onFetch(task.getTaskId());
|
mFetchCallback.onFetch(task.getTaskId());
|
||||||
}
|
}
|
||||||
@@ -267,29 +284,6 @@ public class BackgroundFetch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"WeakerAccess", "deprecation"})
|
|
||||||
public Boolean isMainActivityActive() {
|
|
||||||
Boolean isActive = false;
|
|
||||||
|
|
||||||
if (mContext == null || mFetchCallback == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
|
||||||
try {
|
|
||||||
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
|
|
||||||
for (ActivityManager.RunningTaskInfo task : tasks) {
|
|
||||||
if (mContext.getPackageName().equalsIgnoreCase(task.baseActivity.getPackageName())) {
|
|
||||||
isActive = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (java.lang.SecurityException e) {
|
|
||||||
Log.w(TAG, "TSBackgroundFetch attempted to determine if MainActivity is active but was stopped due to a missing permission. Please add the permission 'android.permission.GET_TASKS' to your AndroidManifest. See Installation steps for more information");
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
return isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
BackgroundFetchConfig getConfig(String taskId) {
|
BackgroundFetchConfig getConfig(String taskId) {
|
||||||
synchronized (mConfig) {
|
synchronized (mConfig) {
|
||||||
return (mConfig.containsKey(taskId)) ? mConfig.get(taskId) : null;
|
return (mConfig.containsKey(taskId)) ? mConfig.get(taskId) : null;
|
||||||
|
|||||||
@@ -14,6 +14,15 @@ public class FetchJobService extends JobService {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onStartJob(final JobParameters params) {
|
public boolean onStartJob(final JobParameters params) {
|
||||||
PersistableBundle extras = params.getExtras();
|
PersistableBundle extras = params.getExtras();
|
||||||
|
long scheduleAt = extras.getLong("scheduled_at");
|
||||||
|
long dt = System.currentTimeMillis() - scheduleAt;
|
||||||
|
// Scheduled < 1s ago? Ignore.
|
||||||
|
if (dt < 1000) {
|
||||||
|
// JobScheduler always immediately fires an initial event on Periodic jobs -- We IGNORE these.
|
||||||
|
jobFinished(params, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
final String taskId = extras.getString(BackgroundFetchConfig.FIELD_TASK_ID);
|
final String taskId = extras.getString(BackgroundFetchConfig.FIELD_TASK_ID);
|
||||||
|
|
||||||
CompletionHandler completionHandler = new CompletionHandler() {
|
CompletionHandler completionHandler = new CompletionHandler() {
|
||||||
|
|||||||
@@ -0,0 +1,225 @@
|
|||||||
|
package com.transistorsoft.tsbackgroundfetch;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
import androidx.lifecycle.ProcessLifecycleOwner;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component for managing app life-cycle changes, including headless-mode.
|
||||||
|
*/
|
||||||
|
public class LifecycleManager implements DefaultLifecycleObserver, Runnable {
|
||||||
|
private static LifecycleManager sInstance;
|
||||||
|
|
||||||
|
public static LifecycleManager getInstance() {
|
||||||
|
if (sInstance == null) {
|
||||||
|
sInstance = getInstanceSynchronized();
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static synchronized LifecycleManager getInstanceSynchronized() {
|
||||||
|
if (sInstance == null) sInstance = new LifecycleManager();
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<OnHeadlessChangeCallback> mHeadlessChangeCallbacks = new ArrayList<>();
|
||||||
|
private final List<OnStateChangeCallback> mStateChangeCallbacks = new ArrayList<>();
|
||||||
|
private final Handler mHandler;
|
||||||
|
private Runnable mHeadlessChangeEvent;
|
||||||
|
|
||||||
|
private final AtomicBoolean mIsBackground = new AtomicBoolean(true);
|
||||||
|
private final AtomicBoolean mIsHeadless = new AtomicBoolean(true);
|
||||||
|
private final AtomicBoolean mStarted = new AtomicBoolean(false);
|
||||||
|
private final AtomicBoolean mPaused = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
private LifecycleManager() {
|
||||||
|
mHandler = new Handler(Looper.getMainLooper());
|
||||||
|
onHeadlessChange(isHeadless -> {
|
||||||
|
if (isHeadless) {
|
||||||
|
Log.d(BackgroundFetch.TAG, "☯️ HeadlessMode? " + isHeadless);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporarily disable responding to pause/resume events. This was placed here for handling TSLocationManagerActivity events
|
||||||
|
* whose presentation causes onPause / onResume events that we don't want to react to.
|
||||||
|
*/
|
||||||
|
public void pause() {
|
||||||
|
mPaused.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-engage responding to pause/resume events.
|
||||||
|
*/
|
||||||
|
public void resume() {
|
||||||
|
mPaused.set(false);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Are we in the background?
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean isBackground() {
|
||||||
|
return mIsBackground.get();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Are we headless
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean isHeadless() {
|
||||||
|
return mIsHeadless.get();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Explicitly state that we are headless. Probably called when MainActivity is known to have been destroyed.
|
||||||
|
* @param value boolean
|
||||||
|
*/
|
||||||
|
public void setHeadless(boolean value) {
|
||||||
|
mIsHeadless.set(value);
|
||||||
|
if (mIsHeadless.get()) {
|
||||||
|
Log.d(BackgroundFetch.TAG,"☯️ HeadlessMode? " + mIsHeadless);
|
||||||
|
}
|
||||||
|
if (mHeadlessChangeEvent != null) {
|
||||||
|
mHandler.removeCallbacks(mHeadlessChangeEvent);
|
||||||
|
mStarted.set(true);
|
||||||
|
fireHeadlessChangeListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Register Headless-mode change listener.
|
||||||
|
*/
|
||||||
|
public void onHeadlessChange(OnHeadlessChangeCallback callback) {
|
||||||
|
if (mStarted.get()) {
|
||||||
|
callback.onChange(mIsHeadless.get());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
synchronized (mHeadlessChangeCallbacks) {
|
||||||
|
mHeadlessChangeCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Register pause/resume listener.
|
||||||
|
*/
|
||||||
|
public void onStateChange(OnStateChangeCallback callback) {
|
||||||
|
synchronized (mStateChangeCallbacks) {
|
||||||
|
mStateChangeCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regiser the LifecycleObserver
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@NonNull LifecycleOwner owner) {
|
||||||
|
Log.d(BackgroundFetch.TAG,"☯️ onCreate");
|
||||||
|
// If this 50ms Timer fires before onStart, we are headless
|
||||||
|
mHeadlessChangeEvent = new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
mStarted.set(true);
|
||||||
|
fireHeadlessChangeListeners();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mHandler.postDelayed(mHeadlessChangeEvent, 50);
|
||||||
|
mIsHeadless.set(true);
|
||||||
|
mIsBackground.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart(@NonNull LifecycleOwner owner) {
|
||||||
|
Log.d(BackgroundFetch.TAG, "☯️ onStart");
|
||||||
|
// Cancel StateChange Timer.
|
||||||
|
if (mPaused.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mHeadlessChangeEvent != null) {
|
||||||
|
mHandler.removeCallbacks(mHeadlessChangeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
mStarted.set(true);
|
||||||
|
mIsHeadless.set(false);
|
||||||
|
mIsBackground.set(false);
|
||||||
|
|
||||||
|
// Fire listeners.
|
||||||
|
fireHeadlessChangeListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy(@NonNull LifecycleOwner owner) {
|
||||||
|
Log.d(BackgroundFetch.TAG, "☯️ onDestroy");
|
||||||
|
mIsBackground.set(true);
|
||||||
|
mIsHeadless.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop(@NonNull LifecycleOwner owner) {
|
||||||
|
Log.d(BackgroundFetch.TAG, "☯️ onStop");
|
||||||
|
if (mPaused.compareAndSet(true, false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIsBackground.set(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause(@NonNull LifecycleOwner owner) {
|
||||||
|
Log.d(BackgroundFetch.TAG, "☯️ onPause");
|
||||||
|
mIsBackground.set(true);
|
||||||
|
fireStateChangeListeners(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume(@NonNull LifecycleOwner owner) {
|
||||||
|
Log.d(BackgroundFetch.TAG, "☯️ onResume");
|
||||||
|
if (mPaused.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIsBackground.set(false);
|
||||||
|
mIsHeadless.set(false);
|
||||||
|
fireStateChangeListeners(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fire pause/resume change listeners
|
||||||
|
private void fireStateChangeListeners(boolean isForeground) {
|
||||||
|
synchronized (mStateChangeCallbacks) {
|
||||||
|
for (OnStateChangeCallback callback : mStateChangeCallbacks) {
|
||||||
|
callback.onChange(isForeground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fire headless mode change listeners.
|
||||||
|
private void fireHeadlessChangeListeners() {
|
||||||
|
if (mHeadlessChangeEvent != null) {
|
||||||
|
mHandler.removeCallbacks(mHeadlessChangeEvent);
|
||||||
|
mHeadlessChangeEvent = null;
|
||||||
|
}
|
||||||
|
synchronized (mHeadlessChangeCallbacks) {
|
||||||
|
for (OnHeadlessChangeCallback callback : mHeadlessChangeCallbacks) {
|
||||||
|
callback.onChange(mIsHeadless.get());
|
||||||
|
}
|
||||||
|
mHeadlessChangeCallbacks.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnHeadlessChangeCallback {
|
||||||
|
void onChange(boolean isHeadless);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnStateChangeCallback {
|
||||||
|
void onChange(boolean isForeground);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user