fixed starting new intents when activity already exists

This commit is contained in:
Thibault Deckers 2020-09-23 15:05:54 +09:00
parent f78b466229
commit 0547c3bbf1
8 changed files with 74 additions and 24 deletions

View file

@ -6,6 +6,7 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.core.content.pm.ShortcutInfoCompat; import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat; import androidx.core.content.pm.ShortcutManagerCompat;
@ -25,19 +26,23 @@ import deckers.thibault.aves.channel.calls.MetadataHandler;
import deckers.thibault.aves.channel.calls.StorageHandler; import deckers.thibault.aves.channel.calls.StorageHandler;
import deckers.thibault.aves.channel.streams.ImageByteStreamHandler; import deckers.thibault.aves.channel.streams.ImageByteStreamHandler;
import deckers.thibault.aves.channel.streams.ImageOpStreamHandler; import deckers.thibault.aves.channel.streams.ImageOpStreamHandler;
import deckers.thibault.aves.channel.streams.IntentStreamHandler;
import deckers.thibault.aves.channel.streams.MediaStoreStreamHandler; import deckers.thibault.aves.channel.streams.MediaStoreStreamHandler;
import deckers.thibault.aves.channel.streams.StorageAccessStreamHandler; import deckers.thibault.aves.channel.streams.StorageAccessStreamHandler;
import deckers.thibault.aves.utils.PermissionManager; import deckers.thibault.aves.utils.PermissionManager;
import deckers.thibault.aves.utils.Utils; import deckers.thibault.aves.utils.Utils;
import io.flutter.embedding.android.FlutterActivity; import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel;
public class MainActivity extends FlutterActivity { public class MainActivity extends FlutterActivity {
private static final String LOG_TAG = Utils.createLogTag(MainActivity.class); private static final String LOG_TAG = Utils.createLogTag(MainActivity.class);
public static final String INTENT_CHANNEL = "deckers.thibault/aves/intent";
public static final String VIEWER_CHANNEL = "deckers.thibault/aves/viewer"; public static final String VIEWER_CHANNEL = "deckers.thibault/aves/viewer";
private IntentStreamHandler intentStreamHandler;
private Map<String, Object> intentDataMap; private Map<String, Object> intentDataMap;
@Override @Override
@ -79,6 +84,8 @@ public class MainActivity extends FlutterActivity {
finish(); finish();
} }
}); });
intentStreamHandler = new IntentStreamHandler();
new EventChannel(messenger, INTENT_CHANNEL).setStreamHandler(intentStreamHandler);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
setupShortcuts(); setupShortcuts();
@ -107,6 +114,13 @@ public class MainActivity extends FlutterActivity {
ShortcutManagerCompat.setDynamicShortcuts(this, Arrays.asList(videos, search)); ShortcutManagerCompat.setDynamicShortcuts(this, Arrays.asList(videos, search));
} }
@Override
protected void onNewIntent(@NonNull Intent intent) {
super.onNewIntent(intent);
handleIntent(intent);
intentStreamHandler.notifyNewIntent();
}
private void handleIntent(Intent intent) { private void handleIntent(Intent intent) {
Log.i(LOG_TAG, "handleIntent intent=" + intent); Log.i(LOG_TAG, "handleIntent intent=" + intent);
if (intent == null) return; if (intent == null) return;

View file

@ -44,7 +44,7 @@ public class ImageByteStreamHandler implements EventChannel.StreamHandler {
} }
@Override @Override
public void onListen(Object o, final EventChannel.EventSink eventSink) { public void onListen(Object args, EventChannel.EventSink eventSink) {
this.eventSink = eventSink; this.eventSink = eventSink;
this.handler = new Handler(Looper.getMainLooper()); this.handler = new Handler(Looper.getMainLooper());
new Thread(this::getImage).start(); new Thread(this::getImage).start();

View file

@ -47,7 +47,7 @@ public class ImageOpStreamHandler implements EventChannel.StreamHandler {
} }
@Override @Override
public void onListen(Object o, final EventChannel.EventSink eventSink) { public void onListen(Object args, EventChannel.EventSink eventSink) {
this.eventSink = eventSink; this.eventSink = eventSink;
this.handler = new Handler(Looper.getMainLooper()); this.handler = new Handler(Looper.getMainLooper());
if ("delete".equals(op)) { if ("delete".equals(op)) {

View file

@ -0,0 +1,20 @@
package deckers.thibault.aves.channel.streams;
import io.flutter.plugin.common.EventChannel;
public class IntentStreamHandler implements EventChannel.StreamHandler {
private EventChannel.EventSink eventSink;
@Override
public void onListen(Object args, EventChannel.EventSink eventSink) {
this.eventSink = eventSink;
}
@Override
public void onCancel(Object arguments) {
}
public void notifyNewIntent() {
eventSink.success(true);
}
}

View file

@ -27,7 +27,7 @@ public class MediaStoreStreamHandler implements EventChannel.StreamHandler {
} }
@Override @Override
public void onListen(Object args, final EventChannel.EventSink eventSink) { public void onListen(Object args, EventChannel.EventSink eventSink) {
this.eventSink = eventSink; this.eventSink = eventSink;
this.handler = new Handler(Looper.getMainLooper()); this.handler = new Handler(Looper.getMainLooper());
new Thread(this::fetchAll).start(); new Thread(this::fetchAll).start();

View file

@ -29,7 +29,7 @@ public class StorageAccessStreamHandler implements EventChannel.StreamHandler {
} }
@Override @Override
public void onListen(Object o, final EventChannel.EventSink eventSink) { public void onListen(Object args, EventChannel.EventSink eventSink) {
this.eventSink = eventSink; this.eventSink = eventSink;
this.handler = new Handler(Looper.getMainLooper()); this.handler = new Handler(Looper.getMainLooper());
Runnable onGranted = () -> success(true); // user gave access to a directory, with no guarantee that it matches the specified `path` Runnable onGranted = () -> success(true); // user gave access to a directory, with no guarantee that it matches the specified `path`

View file

@ -5,6 +5,7 @@ import 'package:aves/model/settings/settings.dart';
import 'package:aves/utils/route_tracker.dart'; import 'package:aves/utils/route_tracker.dart';
import 'package:aves/widgets/common/data_providers/settings_provider.dart'; import 'package:aves/widgets/common/data_providers/settings_provider.dart';
import 'package:aves/widgets/common/icons.dart'; import 'package:aves/widgets/common/icons.dart';
import 'package:aves/widgets/common/routes.dart';
import 'package:aves/widgets/home_page.dart'; import 'package:aves/widgets/home_page.dart';
import 'package:aves/widgets/welcome_page.dart'; import 'package:aves/widgets/welcome_page.dart';
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
@ -32,7 +33,7 @@ void main() {
enum AppMode { main, pick, view } enum AppMode { main, pick, view }
class AvesApp extends StatefulWidget { class AvesApp extends StatefulWidget {
static AppMode mode = AppMode.main; static AppMode mode;
@override @override
_AvesAppState createState() => _AvesAppState(); _AvesAppState createState() => _AvesAppState();
@ -41,6 +42,8 @@ class AvesApp extends StatefulWidget {
class _AvesAppState extends State<AvesApp> { class _AvesAppState extends State<AvesApp> {
Future<void> _appSetup; Future<void> _appSetup;
final NavigatorObserver _routeTracker = CrashlyticsRouteTracker(); final NavigatorObserver _routeTracker = CrashlyticsRouteTracker();
final _newIntentChannel = EventChannel('deckers.thibault/aves/intent');
final _navigatorKey = GlobalKey<NavigatorState>();
static const accentColor = Colors.indigoAccent; static const accentColor = Colors.indigoAccent;
@ -64,10 +67,13 @@ class _AvesAppState extends State<AvesApp> {
), ),
); );
Widget get firstPage => settings.hasAcceptedTerms ? HomePage() : WelcomePage();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_appSetup = _setup(); _appSetup = _setup();
_newIntentChannel.receiveBroadcastStream().listen((_) => _onNewIntent());
} }
Future<void> _setup() async { Future<void> _setup() async {
@ -87,6 +93,14 @@ class _AvesAppState extends State<AvesApp> {
await settings.init(); await settings.init();
} }
void _onNewIntent() {
FirebaseCrashlytics.instance.log('New intent');
_navigatorKey.currentState.pushReplacement(DirectMaterialPageRoute(
settings: RouteSettings(name: HomePage.routeName),
builder: (_) => firstPage,
));
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// place the settings provider above `MaterialApp` // place the settings provider above `MaterialApp`
@ -95,23 +109,10 @@ class _AvesAppState extends State<AvesApp> {
future: _appSetup, future: _appSetup,
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasError && snapshot.connectionState == ConnectionState.done) { if (!snapshot.hasError && snapshot.connectionState == ConnectionState.done) {
return settings.hasAcceptedTerms ? HomePage() : WelcomePage(); return firstPage;
} }
return Scaffold( return Scaffold(
body: snapshot.hasError body: snapshot.hasError ? _buildError(snapshot.error) : SizedBox.shrink(),
? Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(AIcons.error),
SizedBox(height: 16),
Text(snapshot.error.toString()),
],
),
)
: SizedBox.shrink(),
); );
}, },
); );
@ -121,6 +122,7 @@ class _AvesAppState extends State<AvesApp> {
future: _appSetup, future: _appSetup,
builder: (context, snapshot) { builder: (context, snapshot) {
return MaterialApp( return MaterialApp(
navigatorKey: _navigatorKey,
home: home, home: home,
navigatorObservers: [ navigatorObservers: [
if (!snapshot.hasError && snapshot.connectionState == ConnectionState.done) _routeTracker, if (!snapshot.hasError && snapshot.connectionState == ConnectionState.done) _routeTracker,
@ -134,4 +136,19 @@ class _AvesAppState extends State<AvesApp> {
), ),
); );
} }
Widget _buildError(Object error) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(AIcons.error),
SizedBox(height: 16),
Text(error.toString()),
],
),
);
}
} }

View file

@ -63,19 +63,18 @@ class _HomePageState extends State<HomePage> {
await androidFileUtils.init(); await androidFileUtils.init();
unawaited(androidFileUtils.initAppNames()); unawaited(androidFileUtils.initAppNames());
AvesApp.mode = AppMode.main;
final intentData = await ViewerService.getIntentData(); final intentData = await ViewerService.getIntentData();
if (intentData != null) { if (intentData != null) {
final action = intentData['action']; final action = intentData['action'];
switch (action) { switch (action) {
case 'view': case 'view':
AvesApp.mode = AppMode.view;
_viewerEntry = await _initViewerEntry( _viewerEntry = await _initViewerEntry(
uri: intentData['uri'], uri: intentData['uri'],
mimeType: intentData['mimeType'], mimeType: intentData['mimeType'],
); );
if (_viewerEntry == null) { if (_viewerEntry != null) {
// fallback to default mode when we fail to retrieve the entry AvesApp.mode = AppMode.view;
AvesApp.mode = AppMode.main;
} }
break; break;
case 'pick': case 'pick':