forked from flutter/flutter
/
android_intent.dart
171 lines (151 loc) · 5.84 KB
/
android_intent.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'package:platform/platform.dart';
const String _kChannelName = 'plugins.flutter.io/android_intent';
/// Flutter plugin for launching arbitrary Android Intents.
///
/// See [the official Android
/// documentation](https://developer.android.com/reference/android/content/Intent.html)
/// for more information on how to use Intents.
class AndroidIntent {
/// Builds an Android intent with the following parameters
/// [action] refers to the action parameter of the intent.
/// [flags] is the list of int that will be converted to native flags.
/// [category] refers to the category of the intent, can be null.
/// [data] refers to the string format of the URI that will be passed to
/// intent.
/// [arguments] is the map that will be converted into an extras bundle and
/// passed to the intent.
/// [package] refers to the package parameter of the intent, can be null.
/// [componentName] refers to the component name of the intent, can be null.
/// If not null, then [package] but also be provided.
/// [type] refers to the type of the intent, can be null.
const AndroidIntent({
this.action,
this.flags,
this.category,
this.data,
this.arguments,
this.package,
this.componentName,
Platform? platform,
this.type,
}) : assert(action != null || componentName != null,
'action or component (or both) must be specified'),
_channel = const MethodChannel(_kChannelName),
_platform = platform ?? const LocalPlatform();
/// This constructor is only exposed for unit testing. Do not rely on this in
/// app code, it may break without warning.
@visibleForTesting
AndroidIntent.private({
required Platform platform,
required MethodChannel channel,
this.action,
this.flags,
this.category,
this.data,
this.arguments,
this.package,
this.componentName,
this.type,
}) : assert(action != null || componentName != null,
'action or component (or both) must be specified'),
_channel = channel,
_platform = platform;
/// This is the general verb that the intent should attempt to do. This
/// includes constants like `ACTION_VIEW`.
///
/// See https://developer.android.com/reference/android/content/Intent.html#intent-structure.
final String? action;
/// Constants that can be set on an intent to tweak how it is finally handled.
/// Some of the constants are mirrored to Dart via [Flag].
///
/// See https://developer.android.com/reference/android/content/Intent.html#setFlags(int).
final List<int>? flags;
/// An optional additional constant qualifying the given [action].
///
/// See https://developer.android.com/reference/android/content/Intent.html#intent-structure.
final String? category;
/// The Uri that the [action] is pointed towards.
///
/// See https://developer.android.com/reference/android/content/Intent.html#intent-structure.
final String? data;
/// The equivalent of `extras`, a generic `Bundle` of data that the Intent can
/// carry. This is a slot for extraneous data that the listener may use.
///
/// See https://developer.android.com/reference/android/content/Intent.html#intent-structure.
final Map<String, dynamic>? arguments;
/// Sets the [data] to only resolve within this given package.
///
/// See https://developer.android.com/reference/android/content/Intent.html#setPackage(java.lang.String).
final String? package;
/// Set the exact `ComponentName` that should handle the intent. If this is
/// set [package] should also be non-null.
///
/// See https://developer.android.com/reference/android/content/Intent.html#setComponent(android.content.ComponentName).
final String? componentName;
final MethodChannel _channel;
final Platform _platform;
/// Set an explicit MIME data type.
///
/// See https://developer.android.com/reference/android/content/Intent.html#intent-structure.
final String? type;
bool _isPowerOfTwo(int x) {
/* First x in the below expression is for the case when x is 0 */
return x != 0 && ((x & (x - 1)) == 0);
}
/// This method is just visible for unit testing and should not be relied on.
/// Its method signature may change at any time.
@visibleForTesting
int convertFlags(List<int> flags) {
int finalValue = 0;
for (int i = 0; i < flags.length; i++) {
if (!_isPowerOfTwo(flags[i])) {
throw ArgumentError.value(flags[i], 'flag\'s value must be power of 2');
}
finalValue |= flags[i];
}
return finalValue;
}
/// Launch the intent.
///
/// This works only on Android platforms.
Future<void> launch() async {
if (!_platform.isAndroid) {
return;
}
await _channel.invokeMethod<void>('launch', _buildArguments());
}
/// Check whether the intent can be resolved to an activity.
///
/// This works only on Android platforms.
Future<bool> canResolveActivity() async {
if (!_platform.isAndroid) {
return false;
}
final result = await _channel.invokeMethod<bool>(
'canResolveActivity',
_buildArguments(),
);
return result!;
}
/// Constructs the map of arguments which is passed to the plugin.
Map<String, dynamic> _buildArguments() {
return {
if (action != null) 'action': action,
if (flags != null) 'flags': convertFlags(flags!),
if (category != null) 'category': category,
if (data != null) 'data': data,
if (arguments != null) 'arguments': arguments,
if (package != null) ...{
'package': package,
if (componentName != null) 'componentName': componentName,
},
if (type != null) 'type': type,
};
}
}