Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
6743105
Initial attempt at Espresso tests for package:android_alarm_manager
bkonyi Jan 22, 2020
969b471
Added test for android_alarm_manager background execution
bkonyi Jan 23, 2020
2309b31
Formatting and analysis fixes
bkonyi Jan 23, 2020
20edffa
Fixed typo
bkonyi Jan 23, 2020
f56ba76
Fix AndroidManifest.xml
collinjackson Mar 2, 2020
f8e3e96
Implement code review feedback suggestions
collinjackson Mar 2, 2020
1cd80ed
Fix test to be able to run more than once
collinjackson Mar 2, 2020
3b80084
remove prints
collinjackson Mar 2, 2020
a8bb31e
Split espresso and e2e example apps
collinjackson Mar 2, 2020
1c152a0
add shared_preferences:
collinjackson Mar 2, 2020
bd0c407
fix deprecation warning
collinjackson Mar 2, 2020
fc37fa2
Revert "fix deprecation warning"
collinjackson Mar 2, 2020
b4747bf
different fix for deprecation
collinjackson Mar 2, 2020
9fe8165
Revert back to earlier version with combined example app
collinjackson Mar 2, 2020
496ef94
different fix for deprecation
collinjackson Mar 2, 2020
c29ae2d
remove duplicate test
collinjackson Mar 2, 2020
77da504
remove example/example
collinjackson Mar 2, 2020
b37c9cc
changes per Amir's feedback
collinjackson Mar 2, 2020
650bad7
Move espresso test instructions
collinjackson Mar 2, 2020
8d57d9a
Change Espresso to fix iOS build errors
collinjackson Mar 2, 2020
68e10fe
Use development version of Espresso
collinjackson Mar 2, 2020
458753c
reformat
collinjackson Mar 2, 2020
22e8a5d
Re-enable background execution test on CI
collinjackson Mar 6, 2020
89b5d6d
Fix ref to MainActivity
collinjackson Mar 6, 2020
efad3e6
Merge remote-tracking branch 'origin/master' into alarm_manager_espre…
collinjackson Mar 6, 2020
7c88473
Update README
collinjackson Mar 6, 2020
aa8ee0e
revert EspressoPlugin.m
collinjackson Mar 6, 2020
148ca20
Split out espresso changes
collinjackson Mar 6, 2020
053d3bd
Rename method to appMain
collinjackson Mar 6, 2020
5cd6695
Fix for race condition on test startup
collinjackson Mar 6, 2020
7dff19e
fix formatting
collinjackson Mar 6, 2020
47e1683
Add comments and fix race condition
collinjackson Mar 6, 2020
d44dac8
Update e2e package for release
collinjackson Mar 6, 2020
a95172c
reformat
collinjackson Mar 6, 2020
fc825a1
Tweaks to e2e code
collinjackson Mar 6, 2020
420574a
Better fix for launchActivity issue
collinjackson Mar 6, 2020
9ee1946
Update to point at new e2e release
collinjackson Mar 6, 2020
2626dfe
Fix syntax error
collinjackson Mar 6, 2020
bfa4157
Revert e2e changes
collinjackson Mar 6, 2020
c6463b2
Indicate dependency_overrides shouldn't be landed
collinjackson Mar 6, 2020
5c5fcd3
reformat
collinjackson Mar 6, 2020
0e4fd83
Update runner reference
collinjackson Mar 6, 2020
64b094b
remove dependency overrides
collinjackson Mar 6, 2020
90c08f3
fix import
collinjackson Mar 6, 2020
d9afbdc
bump for release
collinjackson Mar 6, 2020
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
4 changes: 4 additions & 0 deletions packages/android_alarm_manager/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.4.5+5

* Added an Espresso test.

## 0.4.5+4

* Make the pedantic dev_dependency explicit.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ flutter {

dependencies {
testImplementation 'junit:junit:4.12'
testImplementation "com.google.truth:truth:1.0"
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
api 'androidx.test:core:1.2.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2020 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.

package io.flutter.plugins.androidalarmmanagerexample;

import static androidx.test.espresso.Espresso.pressBackUnconditionally;
import static androidx.test.espresso.flutter.EspressoFlutter.onFlutterWidget;
import static androidx.test.espresso.flutter.action.FlutterActions.click;
import static androidx.test.espresso.flutter.matcher.FlutterMatchers.withValueKey;
import static org.junit.Assert.assertEquals;

import android.content.Context;
import android.content.SharedPreferences;
import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.rule.ActivityTestRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class BackgroundExecutionTest {
private SharedPreferences prefs;
static final String COUNT_KEY = "flutter.count";

@Rule
public ActivityTestRule<DriverExtensionActivity> myActivityTestRule =
new ActivityTestRule<>(DriverExtensionActivity.class, true, false);

@Before
public void setUp() throws Exception {
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);
prefs.edit().putLong(COUNT_KEY, 0).apply();

ActivityScenario.launch(DriverExtensionActivity.class);
}

@Test
public void startBackgroundIsolate() throws Exception {

// Register a one shot alarm which will go off in ~5 seconds.
onFlutterWidget(withValueKey("RegisterOneShotAlarm")).perform(click());

// The alarm count should be 0 after installation.
assertEquals(prefs.getLong(COUNT_KEY, -1), 0);

// Close the application to background it.
pressBackUnconditionally();

// The alarm should eventually fire, wake up the application, create a
// background isolate, and then increment the counter in the shared
// preferences. Timeout after 20s, just to be safe.
int tries = 0;
while ((prefs.getLong(COUNT_KEY, -1) == 0) && (tries < 200)) {
Thread.sleep(100);
++tries;
}
assertEquals(prefs.getLong(COUNT_KEY, -1), 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2019 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.

package io.flutter.plugins.androidalarmmanagerexample;

import androidx.annotation.NonNull;

public class DriverExtensionActivity extends MainActivity {
@Override
@NonNull
public String getDartEntrypointFunctionName() {
return "appMain";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
package io.flutter.plugins.androidalarmmanagerexample;

import androidx.test.rule.ActivityTestRule;
import dev.flutter.plugins.e2e.FlutterRunner;
import dev.flutter.plugins.e2e.FlutterTestRunner;
import org.junit.Rule;
import org.junit.runner.RunWith;

@RunWith(FlutterRunner.class)
@RunWith(FlutterTestRunner.class)
public class MainActivityTest {
@Rule public ActivityTestRule<MainActivity> rule = new ActivityTestRule<>(MainActivity.class);
@Rule
public ActivityTestRule<MainActivity> rule =
new ActivityTestRule<>(MainActivity.class, true, false);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.flutter.plugins.androidalarmmanagerexample">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<application android:usesCleartextTraffic="true">
<activity
android:name=".DriverExtensionActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.flutter.embedding.engine.plugins.shim.ShimPluginRegistry;
import io.flutter.plugins.androidalarmmanager.AndroidAlarmManagerPlugin;
import io.flutter.plugins.pathprovider.PathProviderPlugin;
import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin;

public class MainActivity extends FlutterActivity {
// TODO(bkonyi): Remove this once v2 of GeneratedPluginRegistrant rolls to stable. https://github.com/flutter/flutter/issues/42694
Expand All @@ -18,6 +19,7 @@ public void configureFlutterEngine(FlutterEngine flutterEngine) {
ShimPluginRegistry shimPluginRegistry = new ShimPluginRegistry(flutterEngine);
flutterEngine.getPlugins().add(new AndroidAlarmManagerPlugin());
flutterEngine.getPlugins().add(new E2EPlugin());
flutterEngine.getPlugins().add(new SharedPreferencesPlugin());
PathProviderPlugin.registerWith(
shimPluginRegistry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin"));
}
Expand Down
164 changes: 144 additions & 20 deletions packages/android_alarm_manager/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,156 @@

// ignore_for_file: public_member_api_docs

import 'dart:async';
import 'dart:isolate';
import 'dart:math';
import 'dart:ui';

import 'package:android_alarm_manager/android_alarm_manager.dart';
import 'package:flutter/widgets.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/material.dart';

void printMessage(String msg) => print('[${DateTime.now()}] $msg');
/// The [SharedPreferences] key to access the alarm fire count.
const String countKey = 'count';

void printPeriodic() => printMessage("Periodic!");
void printOneShot() => printMessage("One shot!");
/// The name associated with the UI isolate's [SendPort].
const String isolateName = 'isolate';

Future<void> main() async {
final int periodicID = 0;
final int oneShotID = 1;
/// A port used to communicate from a background isolate to the UI isolate.
final ReceivePort port = ReceivePort();

/// Global [SharedPreferences] object.
SharedPreferences prefs;

Future<void> main() async {
// TODO(bkonyi): uncomment
WidgetsFlutterBinding.ensureInitialized();

// Start the AlarmManager service.
await AndroidAlarmManager.initialize();

printMessage("main run");
runApp(const Center(
child:
Text('See device log for output', textDirection: TextDirection.ltr)));
await AndroidAlarmManager.periodic(
const Duration(seconds: 5), periodicID, printPeriodic,
wakeup: true, exact: true);
await AndroidAlarmManager.oneShot(
const Duration(seconds: 5), oneShotID, printOneShot);
// Register the UI isolate's SendPort to allow for communication from the
// background isolate.
IsolateNameServer.registerPortWithName(
port.sendPort,
isolateName,
);
prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey(countKey)) {
await prefs.setInt(countKey, 0);
}
runApp(AlarmManagerExampleApp());
}

/// Example app for Espresso plugin.
class AlarmManagerExampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: _AlarmHomePage(title: 'Flutter Demo Home Page'),
);
}
}

class _AlarmHomePage extends StatefulWidget {
_AlarmHomePage({Key key, this.title}) : super(key: key);
final String title;

@override
_AlarmHomePageState createState() => _AlarmHomePageState();
}

class _AlarmHomePageState extends State<_AlarmHomePage> {
int _counter = 0;

@override
void initState() {
super.initState();
AndroidAlarmManager.initialize();

// Register for events from the background isolate. These messages will
// always coincide with an alarm firing.
port.listen((_) async => await _incrementCounter());
}

Future<void> _incrementCounter() async {
print('Increment counter!');

// Ensure we've loaded the updated count from the background isolate.
await prefs.reload();

setState(() {
_counter++;
});
}

// The background
static SendPort uiSendPort;

// The callback for our alarm
static Future<void> callback() async {
print('Alarm fired!');

// Get the previous cached count and increment it.
final prefs = await SharedPreferences.getInstance();
int currentCount = prefs.getInt(countKey);
await prefs.setInt(countKey, currentCount + 1);

// This will be null if we're running in the background.
uiSendPort ??= IsolateNameServer.lookupPortByName(isolateName);
uiSendPort?.send(null);
}

@override
Widget build(BuildContext context) {
// TODO(jackson): This has been deprecated and should be replaced
// with `headline4` when it's available on all the versions of
// Flutter that we test.
// ignore: deprecated_member_use
final textStyle = Theme.of(context).textTheme.display1;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Alarm fired $_counter times',
style: textStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Total alarms fired: ',
style: textStyle,
),
Text(
prefs.getInt(countKey).toString(),
key: ValueKey('BackgroundCountText'),
style: textStyle,
),
],
),
RaisedButton(
child: Text(
'Schedule OneShot Alarm',
),
key: ValueKey('RegisterOneShotAlarm'),
onPressed: () async {
await AndroidAlarmManager.oneShot(
const Duration(seconds: 5),
// Ensure we have a unique alarm ID.
Random().nextInt(pow(2, 31)),
callback,
exact: true,
wakeup: true,
);
},
),
],
),
),
);
}
}
5 changes: 3 additions & 2 deletions packages/android_alarm_manager/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ dependencies:
sdk: flutter
android_alarm_manager:
path: ../
e2e: ^0.2.1
shared_preferences: ^0.5.6
e2e: 0.3.0
path_provider: ^1.3.1


dev_dependencies:
espresso: ^0.0.1+3
flutter_driver:
sdk: flutter
flutter_test:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

import 'dart:async';
import 'dart:io';
import 'package:android_alarm_manager_example/main.dart' as app;
import 'package:android_alarm_manager/android_alarm_manager.dart';
import 'package:e2e/e2e.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'package:path_provider/path_provider.dart';

// From https://flutter.dev/docs/cookbook/persistence/reading-writing-files
Expand Down Expand Up @@ -44,14 +46,17 @@ Future<int> readCounter() async {

Future<void> incrementCounter() async {
final int value = await readCounter();
print('incrementCounter to: ${value + 1}');
await writeCounter(value + 1);
}

void appMain() {
enableFlutterDriverExtension();
app.main();
}

void main() {
E2EWidgetsFlutterBinding.ensureInitialized();

print('main');
setUp(() async {
await AndroidAlarmManager.initialize();
});
Expand Down
2 changes: 1 addition & 1 deletion packages/android_alarm_manager/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: android_alarm_manager
description: Flutter plugin for accessing the Android AlarmManager service, and
running Dart code in the background when alarms fire.
version: 0.4.5+4
version: 0.4.5+5
homepage: https://github.com/flutter/plugins/tree/master/packages/android_alarm_manager

dependencies:
Expand Down