Add battery charging status to Platform Channel example (#9147)
diff --git a/examples/platform_channel/android/app/src/main/java/com/example/platformchannel/MainActivity.java b/examples/platform_channel/android/app/src/main/java/com/example/platformchannel/MainActivity.java index af0825c..6f10be3 100644 --- a/examples/platform_channel/android/app/src/main/java/com/example/platformchannel/MainActivity.java +++ b/examples/platform_channel/android/app/src/main/java/com/example/platformchannel/MainActivity.java
@@ -4,6 +4,8 @@ package com.example.platformchannel; +import android.content.BroadcastReceiver; +import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; @@ -13,19 +15,41 @@ import android.os.Bundle; import io.flutter.app.FlutterActivity; +import io.flutter.plugin.common.FlutterEventChannel; +import io.flutter.plugin.common.FlutterEventChannel.EventSink; +import io.flutter.plugin.common.FlutterEventChannel.StreamHandler; import io.flutter.plugin.common.FlutterMethodChannel; import io.flutter.plugin.common.FlutterMethodChannel.MethodCallHandler; import io.flutter.plugin.common.FlutterMethodChannel.Response; import io.flutter.plugin.common.MethodCall; public class MainActivity extends FlutterActivity { - private static final String CHANNEL = "samples.flutter.io/battery"; + private static final String BATTERY_CHANNEL = "samples.flutter.io/battery"; + private static final String CHARGING_CHANNEL = "samples.flutter.io/charging"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - new FlutterMethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( + new FlutterEventChannel(getFlutterView(), CHARGING_CHANNEL).setStreamHandler( + new StreamHandler() { + private BroadcastReceiver chargingStateChangeReceiver; + @Override + public void onListen(Object arguments, EventSink events) { + chargingStateChangeReceiver = createChargingStateChangeReceiver(events); + registerReceiver( + chargingStateChangeReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + } + + @Override + public void onCancel(Object arguments) { + unregisterReceiver(chargingStateChangeReceiver); + chargingStateChangeReceiver = null; + } + } + ); + + new FlutterMethodChannel(getFlutterView(), BATTERY_CHANNEL).setMethodCallHandler( new MethodCallHandler() { @Override public void onMethodCall(MethodCall call, Response response) { @@ -45,6 +69,23 @@ ); } + private BroadcastReceiver createChargingStateChangeReceiver(final EventSink events) { + return new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + + if (status == BatteryManager.BATTERY_STATUS_UNKNOWN) { + events.error("UNAVAILABLE", "Charging status unavailable", null); + } else { + boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + events.success(isCharging ? "charging" : "discharging"); + } + } + }; + } + private int getBatteryLevel() { int batteryLevel = -1; if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
diff --git a/examples/platform_channel/ios/Runner/AppDelegate.h b/examples/platform_channel/ios/Runner/AppDelegate.h index d81813b..c3197e9 100644 --- a/examples/platform_channel/ios/Runner/AppDelegate.h +++ b/examples/platform_channel/ios/Runner/AppDelegate.h
@@ -5,6 +5,6 @@ #import <Flutter/Flutter.h> #import <UIKit/UIKit.h> -@interface AppDelegate : FlutterAppDelegate +@interface AppDelegate : FlutterAppDelegate<FlutterStreamHandler> @end
diff --git a/examples/platform_channel/ios/Runner/AppDelegate.m b/examples/platform_channel/ios/Runner/AppDelegate.m index c74eb73..75f1172 100644 --- a/examples/platform_channel/ios/Runner/AppDelegate.m +++ b/examples/platform_channel/ios/Runner/AppDelegate.m
@@ -5,11 +5,16 @@ #import "AppDelegate.h" #import <Flutter/Flutter.h> -@implementation AppDelegate + +@implementation AppDelegate { + FlutterEventReceiver _eventReceiver; +} + - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController; + FlutterMethodChannel* batteryChannel = [FlutterMethodChannel methodChannelWithName:@"samples.flutter.io/battery" binaryMessenger:controller]; @@ -28,6 +33,11 @@ result(FlutterMethodNotImplemented); } }]; + + FlutterEventChannel* chargingChannel = [FlutterEventChannel + eventChannelWithName:@"samples.flutter.io/charging" + binaryMessenger:controller]; + [chargingChannel setStreamHandler:self]; return YES; } @@ -41,4 +51,41 @@ } } +- (FlutterError*)onListenWithArguments:(id)arguments + eventReceiver:(FlutterEventReceiver)eventReceiver { + _eventReceiver = eventReceiver; + [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onBatteryStateDidChange:) + name:UIDeviceBatteryStateDidChangeNotification + object:nil]; + return nil; +} + +- (void)onBatteryStateDidChange:(NSNotification*)notification { + if (!_eventReceiver) return; + UIDeviceBatteryState state = [[UIDevice currentDevice] batteryState]; + switch (state) { + case UIDeviceBatteryStateFull: + case UIDeviceBatteryStateCharging: + _eventReceiver(@"charging"); + break; + case UIDeviceBatteryStateUnplugged: + _eventReceiver(@"discharging"); + break; + default: + _eventReceiver([FlutterError errorWithCode:@"UNAVAILABLE" + message:@"Charging status unavailable" + details:nil]); + break; + } +} + +- (FlutterError*)onCancelWithArguments:(id)arguments { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + _eventReceiver = nil; + return nil; +} + @end
diff --git a/examples/platform_channel/lib/main.dart b/examples/platform_channel/lib/main.dart index 6c8c161..19f6738 100644 --- a/examples/platform_channel/lib/main.dart +++ b/examples/platform_channel/lib/main.dart
@@ -1,4 +1,4 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. +// 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. @@ -13,16 +13,21 @@ } class _PlatformChannelState extends State<PlatformChannel> { - static const PlatformMethodChannel platform = const PlatformMethodChannel('samples.flutter.io/battery'); - String _batteryLevel = ''; + static const PlatformMethodChannel methodChannel = + const PlatformMethodChannel('samples.flutter.io/battery'); + static const PlatformEventChannel eventChannel = + const PlatformEventChannel('samples.flutter.io/charging'); + + String _batteryLevel = 'Battery level: unknown.'; + String _chargingStatus = 'Battery status: unknown.'; Future<Null> _getBatteryLevel() async { String batteryLevel; try { - final int result = await platform.invokeMethod('getBatteryLevel'); - batteryLevel = 'Battery level at $result % .'; - } on PlatformException catch (e) { - batteryLevel = "Failed to get battery level: '${e.message}'."; + final int result = await methodChannel.invokeMethod('getBatteryLevel'); + batteryLevel = 'Battery level: $result%.'; + } on PlatformException { + batteryLevel = "Failed to get battery level."; } setState(() { _batteryLevel = batteryLevel; @@ -30,19 +35,45 @@ } @override + void initState() { + super.initState(); + eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError); + } + + void _onEvent(String event) { + setState(() { + _chargingStatus = + "Battery status: ${event == 'charging' ? '' : 'dis'}charging."; + }); + } + + void _onError(PlatformException error) { + setState(() { + _chargingStatus = "Battery status: unknown."; + }); + } + + @override Widget build(BuildContext context) { return new Material( - child: new Center( - child: new Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: <Widget>[ - new RaisedButton( - child: new Text('Get Battery Level'), - onPressed: _getBatteryLevel, - ), - new Text(_batteryLevel, key: new Key('Battery level label')), - ], - ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: <Widget>[ + new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: <Widget>[ + new Text(_batteryLevel, key: new Key('Battery level label')), + new Padding( + padding: new EdgeInsets.all(16.0), + child: new RaisedButton( + child: new Text('Refresh'), + onPressed: _getBatteryLevel, + ), + ), + ], + ), + new Text(_chargingStatus), + ], ), ); }
diff --git a/examples/platform_channel/test_driver/button_tap_test.dart b/examples/platform_channel/test_driver/button_tap_test.dart index cf6601e..67ea6b8 100644 --- a/examples/platform_channel/test_driver/button_tap_test.dart +++ b/examples/platform_channel/test_driver/button_tap_test.dart
@@ -14,23 +14,24 @@ }); tearDownAll(() async { - if (driver != null) - driver.close(); + if (driver != null) driver.close(); }); test('tap on the button, verify result', () async { - final SerializableFinder batteryLevelLabel = find.byValueKey('Battery level label'); - expect(batteryLevelLabel, isNotNull); + final SerializableFinder batteryLevelLabel = + find.byValueKey('Battery level label'); + expect(batteryLevelLabel, isNotNull); - final SerializableFinder button = find.text('Get Battery Level'); - await driver.waitFor(button); - await driver.tap(button); + final SerializableFinder button = find.text('Refresh'); + await driver.waitFor(button); + await driver.tap(button); - String batteryLevel; - while(batteryLevel == null || batteryLevel.isEmpty) { - batteryLevel = await driver.getText(batteryLevelLabel); - } - expect(batteryLevel, isNotEmpty); + String batteryLevel; + while (batteryLevel == null || batteryLevel.contains('unknown')) { + batteryLevel = await driver.getText(batteryLevelLabel); + } + + expect(batteryLevel.contains('%'), isTrue); }); }); -} \ No newline at end of file +}