Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open location from Android intent with geo: url #770

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="geo" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="com.linusu.flutter_web_auth_2.CallbackActivity" android:exported="true">
<intent-filter android:label="flutter_web_auth_2">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
package info.zverev.ilya.every_door

import androidx.annotation.NonNull
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity: FlutterActivity() {
private var lastIntentUrlPassed = ""
private val CHANNEL = "info.zverev.ilya.every_door/location"

override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "getLocationFromIntent") {
val intentLocationUrl = intent.data?.toString() ?: ""
if (intentLocationUrl.startsWith("geo:") && intentLocationUrl != lastIntentUrlPassed) {
result.success(intentLocationUrl)
lastIntentUrlPassed = intentLocationUrl
} else {
result.error("UNAVAILABLE", "Location url from Intent not available", null)
}
} else {
result.notImplemented()
}
}
}
}
67 changes: 58 additions & 9 deletions lib/screens/loading.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';

import 'package:every_door/providers/changes.dart';
import 'package:every_door/providers/changeset_tags.dart';
Expand All @@ -12,12 +13,14 @@ import 'package:every_door/screens/browser.dart';
import 'package:flutter/foundation.dart' show compute;
import 'package:flutter/material.dart';
import 'package:every_door/constants.dart';
import 'package:flutter/services.dart';
import 'package:flutter_dropdown_alert/alert_controller.dart';
import 'package:flutter_dropdown_alert/model/data_alert.dart';
import 'package:latlong2/latlong.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:country_coder/country_coder.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:logging/logging.dart';
import 'package:shared_preferences/shared_preferences.dart';

class LoadingPage extends ConsumerStatefulWidget {
Expand All @@ -26,9 +29,57 @@ class LoadingPage extends ConsumerStatefulWidget {
}

class _LoadingPageState extends ConsumerState<LoadingPage> {
static final _logger = Logger('LoadingPageState');
String? message;
static const kPrefLastSizeWarning = 'last_size_warning';

// https://en.wikipedia.org/wiki/Geo_URI_scheme
parseGeoLocation(String geo) {
if (!geo.startsWith("geo:")) return null;
final geoSplit = geo.split("geo:");
if (geoSplit.length != 2) return null;
final semicolonSplit = geoSplit[1].split(";");
final questionMarkSplit = semicolonSplit[0].split("?");
final latLonSplit = questionMarkSplit[0].split(",");
try {
final lat = double.parse(latLonSplit[0]);
final lon = double.parse(latLonSplit[1]);
return LatLng(lat, lon);
} catch (e) {
_logger.severe("Couldn't parseGeoLocation: " + questionMarkSplit[0] + "\n" + e.toString());
return null;
}
}

Future setLocationFromAndroidIntent() async {
const intentLocationChannel = MethodChannel('info.zverev.ilya.every_door/location');
try {
final result = await intentLocationChannel.invokeMethod<String>('getLocationFromIntent');
if (result != null) {
final parsedLocation = parseGeoLocation(result);
if (parsedLocation != null) {
ref.read(effectiveLocationProvider.notifier).set(parsedLocation);
return true;
}
}
} on PlatformException catch (e) {
_logger.severe("Failed calling getLocationFromIntent: " + e.toString());
}
return false;
}

Future acquireUserLocation(AppLocalizations loc) async {
setState(() {
message = loc.loadingLocation;
});
if (!mounted) return;
await ref.read(geolocationProvider.notifier).enableTracking(context);
LatLng? location = ref.read(geolocationProvider);
if (location != null) {
ref.read(effectiveLocationProvider.notifier).set(location);
}
}

Future doInit() async {
final loc = AppLocalizations.of(context)!;

Expand Down Expand Up @@ -69,15 +120,13 @@ class _LoadingPageState extends ConsumerState<LoadingPage> {
// Update floors in the background.
ref.read(osmDataProvider).updateAddressesWithFloors();

// Acquire user location.
setState(() {
message = loc.loadingLocation;
});
if (!mounted) return;
await ref.read(geolocationProvider.notifier).enableTracking(context);
LatLng? location = ref.read(geolocationProvider);
if (location != null) {
ref.read(effectiveLocationProvider.notifier).set(location);
if (Platform.isAndroid) {
final success = await setLocationFromAndroidIntent();
if (!success) {
await acquireUserLocation(loc);
}
} else {
await acquireUserLocation(loc);
}

// Alert if there are too many changes loaded.
Expand Down