[go: nahoru, domu]

Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Commit

Permalink
[android_intent] Make action optional, as Intents can also resolve wi…
Browse files Browse the repository at this point in the history
…th just the component name (#2575)

* An intent takes an action, component or both, but at least one of them.
* Extend the tests and enforce the new assertion on the private constructor as well
* Extends unit test to cover no-action, but component name case.
* Improves unit test even more by writing literal values in the code
  • Loading branch information
ened committed Mar 5, 2020
1 parent c4d53b6 commit 93a1c9b
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 17 deletions.
5 changes: 5 additions & 0 deletions packages/android_intent/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.3.6

* Marks the `action` parameter as optional
* Adds an assertion to ensure the intent receives an action, component or both.

## 0.3.5+1

* Make the pedantic dev_dependency explicit.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public IntentSender(@Nullable Activity activity, @Nullable Context applicationCo
* back to {@code applicationContext} and adds {@link Intent#FLAG_ACTIVITY_NEW_TASK} to the intent
* before launching it.
*
* @param action the Intent action, such as {@code ACTION_VIEW}.
* @param action the Intent action, such as {@code ACTION_VIEW} if non-null.
* @param flags forwarded to {@link Intent#addFlags(int)} if non-null.
* @param category forwarded to {@link Intent#addCategory(String)} if non-null.
* @param data forwarded to {@link Intent#setData(Uri)} if non-null and 'type' parameter is null.
Expand All @@ -57,7 +57,7 @@ public IntentSender(@Nullable Activity activity, @Nullable Context applicationCo
* Intent#setDataAndType(Uri, String)}
*/
void send(
String action,
@Nullable String action,
@Nullable Integer flags,
@Nullable String category,
@Nullable Uri data,
Expand All @@ -70,8 +70,11 @@ void send(
return;
}

Intent intent = new Intent(action);
Intent intent = new Intent();

if (action != null) {
intent.setAction(action);
}
if (flags != null) {
intent.addFlags(flags);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
}

private static String convertAction(String action) {
if (action == null) {
return null;
}

switch (action) {
case "action_view":
return Intent.ACTION_VIEW;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,34 @@ public void onMethodCall_setsComponentName() {
Intent intent = shadowOf((Application) context).getNextStartedActivity();
assertNotNull(intent);
assertNotNull(intent.getComponent());
assertEquals(expectedComponent.getPackageName(), intent.getPackage());
assertEquals(expectedComponent.flattenToString(), intent.getComponent().flattenToString());
assertEquals("foo", intent.getAction());
assertEquals("io.flutter.plugins.androidintent", intent.getPackage());
assertEquals(
"io.flutter.plugins.androidintent/MainActivity", intent.getComponent().flattenToString());
}

@Test
public void onMethodCall_setsOnlyComponentName() {
sender.setApplicationContext(context);
Map<String, Object> args = new HashMap<>();
ComponentName expectedComponent =
new ComponentName("io.flutter.plugins.androidintent", "MainActivity");
args.put("package", expectedComponent.getPackageName());
args.put("componentName", expectedComponent.getClassName());
Result result = mock(Result.class);
ShadowPackageManager shadowPm =
shadowOf(ApplicationProvider.getApplicationContext().getPackageManager());
shadowPm.addActivityIfNotPresent(expectedComponent);

methodCallHandler.onMethodCall(new MethodCall("launch", args), result);

verify(result, times(1)).success(null);
Intent intent = shadowOf((Application) context).getNextStartedActivity();
assertNotNull(intent);
assertNotNull(intent.getComponent());
assertEquals("io.flutter.plugins.androidintent", intent.getPackage());
assertEquals(
"io.flutter.plugins.androidintent/MainActivity", intent.getComponent().flattenToString());
}

@Test
Expand Down
16 changes: 11 additions & 5 deletions packages/android_intent/lib/android_intent.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AndroidIntent {
/// If not null, then [package] but also be provided.
/// [type] refers to the type of the intent, can be null.
const AndroidIntent({
@required this.action,
this.action,
this.flags,
this.category,
this.data,
Expand All @@ -38,25 +38,28 @@ class AndroidIntent {
this.componentName,
Platform platform,
this.type,
}) : assert(action != null),
}) : 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 this.action,
@required Platform platform,
@required MethodChannel channel,
this.action,
this.flags,
this.category,
this.data,
this.arguments,
this.package,
this.componentName,
this.type,
}) : _channel = channel,
}) : 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
Expand Down Expand Up @@ -131,7 +134,10 @@ class AndroidIntent {
if (!_platform.isAndroid) {
return;
}
final Map<String, dynamic> args = <String, dynamic>{'action': action};
final Map<String, dynamic> args = <String, dynamic>{};
if (action != null) {
args['action'] = action;
}
if (flags != null) {
args['flags'] = convertFlags(flags);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/android_intent/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: android_intent
description: Flutter plugin for launching Android Intents. Not supported on iOS.
homepage: https://github.com/flutter/plugins/tree/master/packages/android_intent
version: 0.3.5+1
version: 0.3.6

flutter:
plugin:
Expand Down
40 changes: 34 additions & 6 deletions packages/android_intent/test/android_intent_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ void main() {
setUp(() {
mockChannel = MockMethodChannel();
});

group('AndroidIntent', () {
test('pass right params', () async {
androidIntent = AndroidIntent.private(
Expand All @@ -32,26 +33,53 @@ void main() {
'type': 'video/*',
}));
});
test('pass null value to action param', () async {

test('raises error if neither an action nor a component is provided', () {
try {
androidIntent = AndroidIntent(data: 'https://flutter.io');
fail('should raise an AssertionError');
} on AssertionError catch (e) {
expect(e.message, 'action or component (or both) must be specified');
} catch (e) {
fail('should raise an AssertionError');
}
});
test('can send Intent with an action and no component', () async {
androidIntent = AndroidIntent.private(
action: null,
channel: mockChannel,
platform: FakePlatform(operatingSystem: 'android'));
action: 'action_view',
channel: mockChannel,
platform: FakePlatform(operatingSystem: 'android'),
);
await androidIntent.launch();
verify(mockChannel.invokeMethod<void>('launch', <String, Object>{
'action': null,
'action': 'action_view',
}));
});

test('can send Intent with a component and no action', () async {
androidIntent = AndroidIntent.private(
package: 'packageName',
componentName: 'componentName',
channel: mockChannel,
platform: FakePlatform(operatingSystem: 'android'),
);
await androidIntent.launch();
verify(mockChannel.invokeMethod<void>('launch', <String, Object>{
'package': 'packageName',
'componentName': 'componentName',
}));
});

test('call in ios platform', () async {
androidIntent = AndroidIntent.private(
action: null,
action: 'action_view',
channel: mockChannel,
platform: FakePlatform(operatingSystem: 'ios'));
await androidIntent.launch();
verifyZeroInteractions(mockChannel);
});
});

group('convertFlags ', () {
androidIntent = const AndroidIntent(
action: 'action_view',
Expand Down

0 comments on commit 93a1c9b

Please sign in to comment.