[battery_platform_interface] Introduce package. (#2975)
diff --git a/packages/battery/battery_platform_interface/CHANGELOG.md b/packages/battery/battery_platform_interface/CHANGELOG.md
new file mode 100644
index 0000000..6fadda9
--- /dev/null
+++ b/packages/battery/battery_platform_interface/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 1.0.0
+
+- Initial open-source release.
diff --git a/packages/battery/battery_platform_interface/LICENSE b/packages/battery/battery_platform_interface/LICENSE
new file mode 100644
index 0000000..c892933
--- /dev/null
+++ b/packages/battery/battery_platform_interface/LICENSE
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/battery/battery_platform_interface/README.md b/packages/battery/battery_platform_interface/README.md
new file mode 100644
index 0000000..e1a4257
--- /dev/null
+++ b/packages/battery/battery_platform_interface/README.md
@@ -0,0 +1,26 @@
+# battery_platform_interface
+
+A common platform interface for the [`battery`][1] plugin.
+
+This interface allows platform-specific implementations of the `battery`
+plugin, as well as the plugin itself, to ensure they are supporting the
+same interface.
+
+# Usage
+
+To implement a new platform-specific implementation of `battery`, extend
+[`BatteryPlatform`][2] with an implementation that performs the
+platform-specific behavior, and when you register your plugin, set the default
+`BatteryPlatform` by calling
+`BatteryPlatform.instance = MyPlatformBattery()`.
+
+# Note on breaking changes
+
+Strongly prefer non-breaking changes (such as adding a method to the interface)
+over breaking changes for this package.
+
+See https://flutter.dev/go/platform-interface-breaking-changes for a discussion
+on why a less-clean interface is preferable to a breaking change.
+
+[1]: ../battery
+[2]: lib/battery_platform_interface.dart
diff --git a/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart b/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart
new file mode 100644
index 0000000..f803c7a
--- /dev/null
+++ b/packages/battery/battery_platform_interface/lib/battery_platform_interface.dart
@@ -0,0 +1,51 @@
+// 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:plugin_platform_interface/plugin_platform_interface.dart';
+
+import 'method_channel/method_channel_battery.dart';
+import 'enums/battery_state.dart';
+
+export 'enums/battery_state.dart';
+
+/// The interface that implementations of battery must implement.
+///
+/// Platform implementations should extend this class rather than implement it as `battery`
+/// does not consider newly added methods to be breaking changes. Extending this class
+/// (using `extends`) ensures that the subclass will get the default implementation, while
+/// platform implementations that `implements` this interface will be broken by newly added
+/// [BatteryPlatform] methods.
+abstract class BatteryPlatform extends PlatformInterface {
+ /// Constructs a BatteryPlatform.
+ BatteryPlatform() : super(token: _token);
+
+ static final Object _token = Object();
+
+ static BatteryPlatform _instance = MethodChannelBattery();
+
+ /// The default instance of [BatteryPlatform] to use.
+ ///
+ /// Defaults to [MethodChannelBattery].
+ static BatteryPlatform get instance => _instance;
+
+ /// Platform-specific plugins should set this with their own platform-specific
+ /// class that extends [BatteryPlatform] when they register themselves.
+ static set instance(BatteryPlatform instance) {
+ PlatformInterface.verifyToken(instance, _token);
+ _instance = instance;
+ }
+
+ /// Gets the battery level from device.
+ Future<int> batteryLevel() {
+ throw UnimplementedError('batteryLevel() has not been implemented.');
+ }
+
+ /// gets battery state from device.
+ Stream<BatteryState> onBatteryStateChanged() {
+ throw UnimplementedError(
+ 'onBatteryStateChanged() has not been implemented.');
+ }
+}
diff --git a/packages/battery/battery_platform_interface/lib/enums/battery_state.dart b/packages/battery/battery_platform_interface/lib/enums/battery_state.dart
new file mode 100644
index 0000000..7dd5e40
--- /dev/null
+++ b/packages/battery/battery_platform_interface/lib/enums/battery_state.dart
@@ -0,0 +1,11 @@
+/// Indicates the current battery state.
+enum BatteryState {
+ /// The battery is completely full of energy.
+ full,
+
+ /// The battery is currently storing energy.
+ charging,
+
+ /// The battery is currently losing energy.
+ discharging
+}
diff --git a/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart b/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart
new file mode 100644
index 0000000..4a3365c
--- /dev/null
+++ b/packages/battery/battery_platform_interface/lib/method_channel/method_channel_battery.dart
@@ -0,0 +1,51 @@
+import 'dart:async';
+
+import 'package:flutter/services.dart';
+import 'package:meta/meta.dart';
+
+import 'package:battery_platform_interface/battery_platform_interface.dart';
+
+import '../battery_platform_interface.dart';
+
+/// An implementation of [BatteryPlatform] that uses method channels.
+class MethodChannelBattery extends BatteryPlatform {
+ /// The method channel used to interact with the native platform.
+ @visibleForTesting
+ MethodChannel channel = MethodChannel('plugins.flutter.io/battery');
+
+ /// The event channel used to interact with the native platform.
+ @visibleForTesting
+ EventChannel eventChannel = EventChannel('plugins.flutter.io/charging');
+
+ /// Method channel for getting battery level.
+ Future<int> batteryLevel() async {
+ return (await channel.invokeMethod('getBatteryLevel')).toInt();
+ }
+
+ /// Stream variable for storing battery state.
+ Stream<BatteryState> _onBatteryStateChanged;
+
+ /// Event channel for getting battery change state.
+ Stream<BatteryState> onBatteryStateChanged() {
+ if (_onBatteryStateChanged == null) {
+ _onBatteryStateChanged = eventChannel
+ .receiveBroadcastStream()
+ .map((dynamic event) => _parseBatteryState(event));
+ }
+ return _onBatteryStateChanged;
+ }
+}
+
+/// Method for parsing battery state.
+BatteryState _parseBatteryState(String state) {
+ switch (state) {
+ case 'full':
+ return BatteryState.full;
+ case 'charging':
+ return BatteryState.charging;
+ case 'discharging':
+ return BatteryState.discharging;
+ default:
+ throw ArgumentError('$state is not a valid BatteryState.');
+ }
+}
diff --git a/packages/battery/battery_platform_interface/pubspec.yaml b/packages/battery/battery_platform_interface/pubspec.yaml
new file mode 100644
index 0000000..6c571de
--- /dev/null
+++ b/packages/battery/battery_platform_interface/pubspec.yaml
@@ -0,0 +1,22 @@
+name: battery_platform_interface
+description: A common platform interface for the battery plugin.
+homepage: https://github.com/flutter/plugins/tree/master/packages/battery
+# NOTE: We strongly prefer non-breaking changes, even at the expense of a
+# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
+version: 1.0.0
+
+dependencies:
+ flutter:
+ sdk: flutter
+ meta: ^1.1.8
+ plugin_platform_interface: ^1.0.2
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+ mockito: ^4.1.1
+ pedantic: ^1.8.0
+
+environment:
+ sdk: ">=2.7.0 <3.0.0"
+ flutter: ">=1.9.1+hotfix.4 <2.0.0"
diff --git a/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart b/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart
new file mode 100644
index 0000000..65323e4
--- /dev/null
+++ b/packages/battery/battery_platform_interface/test/method_channel_battery_test.dart
@@ -0,0 +1,63 @@
+// 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 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'package:battery_platform_interface/battery_platform_interface.dart';
+
+import 'package:battery_platform_interface/method_channel/method_channel_battery.dart';
+
+void main() {
+ TestWidgetsFlutterBinding.ensureInitialized();
+
+ group("$MethodChannelBattery", () {
+ MethodChannelBattery methodChannelBattery;
+
+ setUp(() async {
+ methodChannelBattery = MethodChannelBattery();
+
+ methodChannelBattery.channel
+ .setMockMethodCallHandler((MethodCall methodCall) async {
+ switch (methodCall.method) {
+ case 'getBatteryLevel':
+ return 90;
+ default:
+ return null;
+ }
+ });
+
+ MethodChannel(methodChannelBattery.eventChannel.name)
+ .setMockMethodCallHandler((MethodCall methodCall) async {
+ switch (methodCall.method) {
+ case 'listen':
+ await ServicesBinding.instance.defaultBinaryMessenger
+ .handlePlatformMessage(
+ methodChannelBattery.eventChannel.name,
+ methodChannelBattery.eventChannel.codec
+ .encodeSuccessEnvelope('full'),
+ (_) {},
+ );
+ break;
+ case 'cancel':
+ default:
+ return null;
+ }
+ });
+ });
+
+ /// Test for batetry level call.
+ test("getBatteryLevel", () async {
+ final int result = await methodChannelBattery.batteryLevel();
+ expect(result, 90);
+ });
+
+ /// Test for battery changed state call.
+ test("onBatteryChanged", () async {
+ final BatteryState result =
+ await methodChannelBattery.onBatteryStateChanged().first;
+ expect(result, BatteryState.full);
+ });
+ });
+}