diff --git a/packages/battery_plus/battery_plus/CHANGELOG.md b/packages/battery_plus/battery_plus/CHANGELOG.md index fab821480f..0fb29448b5 100644 --- a/packages/battery_plus/battery_plus/CHANGELOG.md +++ b/packages/battery_plus/battery_plus/CHANGELOG.md @@ -1,3 +1,10 @@ +## 2.2.0 + +- Android: Migrate to Kotlin +- Android: Bump targetSDK to 33 (Android 13) +- Android: Update dependencies, build config updates +- Update Flutter dependencies + ## 2.1.4+1 - Add issue_tracker link. diff --git a/packages/battery_plus/battery_plus/README.md b/packages/battery_plus/battery_plus/README.md index 3b48396eff..e4280ecd1f 100644 --- a/packages/battery_plus/battery_plus/README.md +++ b/packages/battery_plus/battery_plus/README.md @@ -38,5 +38,3 @@ battery.onBatteryStateChanged.listen((BatteryState state) { // Do something with new state }); ``` - -**Important:** As of January 2021, the Flutter team is no longer accepting non-critical PRs for the original set of plugins in `flutter/plugins`, and instead they should be submitted in this project. [You can read more about this announcement here.](https://github.com/flutter/plugins/blob/master/CONTRIBUTING.md#important-note) as well as [in the Flutter 2 announcement blog post.](https://medium.com/flutter/whats-new-in-flutter-2-0-fe8e95ecc65) diff --git a/packages/battery_plus/battery_plus/android/build.gradle b/packages/battery_plus/battery_plus/android/build.gradle index 23e1849d6d..f27a076f17 100644 --- a/packages/battery_plus/battery_plus/android/build.gradle +++ b/packages/battery_plus/battery_plus/android/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.0.2' + classpath 'com.android.tools.build:gradle:7.3.0' } } @@ -20,9 +20,10 @@ rootProject.allprojects { } apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' android { - compileSdkVersion 31 + compileSdkVersion 33 defaultConfig { minSdkVersion 16 @@ -31,5 +32,8 @@ android { lintOptions { disable 'InvalidPackage' } +} +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" } diff --git a/packages/battery_plus/battery_plus/android/src/main/java/dev/fluttercommunity/plus/battery/BatteryPlusPlugin.java b/packages/battery_plus/battery_plus/android/src/main/java/dev/fluttercommunity/plus/battery/BatteryPlusPlugin.java deleted file mode 100644 index ccaba7fba7..0000000000 --- a/packages/battery_plus/battery_plus/android/src/main/java/dev/fluttercommunity/plus/battery/BatteryPlusPlugin.java +++ /dev/null @@ -1,234 +0,0 @@ -// 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. - -package dev.fluttercommunity.plus.battery; - -import android.annotation.TargetApi; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.ContextWrapper; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.BatteryManager; -import android.os.Build; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; -import android.os.PowerManager; -import android.provider.Settings; -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; -import io.flutter.embedding.engine.plugins.FlutterPlugin; -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.EventChannel; -import io.flutter.plugin.common.EventChannel.EventSink; -import io.flutter.plugin.common.EventChannel.StreamHandler; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.MethodCallHandler; -import io.flutter.plugin.common.MethodChannel.Result; -import java.util.Locale; - -/** BatteryPlusPlugin */ -public class BatteryPlusPlugin implements MethodCallHandler, StreamHandler, FlutterPlugin { - - private Context applicationContext; - private BroadcastReceiver chargingStateChangeReceiver; - private MethodChannel methodChannel; - private EventChannel eventChannel; - - public static final String POWER_SAVE_MODE_SAMSUNG = "1"; - private static final int POWER_SAVE_MODE_XIAOMI = 1; - private static final int POWER_SAVE_MODE_HUAWEI = 4; - - @Override - public void onAttachedToEngine(FlutterPluginBinding binding) { - onAttachedToEngine(binding.getApplicationContext(), binding.getBinaryMessenger()); - } - - private void onAttachedToEngine(Context applicationContext, BinaryMessenger messenger) { - this.applicationContext = applicationContext; - methodChannel = new MethodChannel(messenger, "dev.fluttercommunity.plus/battery"); - eventChannel = new EventChannel(messenger, "dev.fluttercommunity.plus/charging"); - eventChannel.setStreamHandler(this); - methodChannel.setMethodCallHandler(this); - } - - @Override - public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { - applicationContext = null; - methodChannel.setMethodCallHandler(null); - methodChannel = null; - eventChannel.setStreamHandler(null); - eventChannel = null; - } - - @Override - public void onMethodCall(MethodCall call, @NonNull Result result) { - if (call.method.equals("getBatteryLevel")) { - int batteryLevel = getBatteryLevel(); - - if (batteryLevel != -1) { - result.success(batteryLevel); - } else { - result.error("UNAVAILABLE", "Battery level not available.", null); - } - } else if (call.method.equals("getBatteryState")) { - String batteryStatus = getBatteryStatus(); - - if (batteryStatus != null) { - result.success(batteryStatus); - } else { - result.error("UNAVAILABLE", "Charging status not available.", null); - } - } else if (call.method.equals("isInBatterySaveMode")) { - Boolean isInPowerSaveMode = this.isInPowerSaveMode(); - - if (isInPowerSaveMode != null) { - result.success(isInPowerSaveMode); - } else { - result.error("UNAVAILABLE", "Battery save mode not available.", null); - } - } else { - result.notImplemented(); - } - } - - @TargetApi(VERSION_CODES.O) - @Override - public void onListen(Object arguments, EventSink events) { - chargingStateChangeReceiver = createChargingStateChangeReceiver(events); - applicationContext.registerReceiver( - chargingStateChangeReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - - String status = getBatteryStatus(); - publishBatteryStatus(events, status); - } - - private String getBatteryStatus() { - int status; - if (android.os.Build.VERSION.SDK_INT >= VERSION_CODES.O) { - status = getBatteryProperty(BatteryManager.BATTERY_PROPERTY_STATUS); - } else { - status = BatteryManager.BATTERY_STATUS_UNKNOWN; - } - return convertBatteryStatus(status); - } - - @Override - public void onCancel(Object arguments) { - applicationContext.unregisterReceiver(chargingStateChangeReceiver); - chargingStateChangeReceiver = null; - } - - private int getBatteryLevel() { - int batteryLevel; - if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - batteryLevel = getBatteryProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); - } else { - Intent intent = - new ContextWrapper(applicationContext) - .registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - batteryLevel = - (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) - / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); - } - - return batteryLevel; - } - - private Boolean isInPowerSaveMode() { - String manufacturer = Build.MANUFACTURER.toLowerCase(Locale.getDefault()); - if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - switch (manufacturer) { - case "xiaomi": - { - return getPowerSaveModeForXiaomi(); - } - case "huawei": - { - return getPowerSaveModeHuawei(); - } - case "samsung": - { - return getPowerSaveModeSamsung(); - } - default: - PowerManager powerManager = - (PowerManager) applicationContext.getSystemService(Context.POWER_SERVICE); - return powerManager.isPowerSaveMode(); - } - } - return null; - } - - private Boolean getPowerSaveModeSamsung() { - String mode = Settings.System.getString(applicationContext.getContentResolver(), "psm_switch"); - if (mode == null && (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP)) { - PowerManager powerManager = - (PowerManager) applicationContext.getSystemService(Context.POWER_SERVICE); - return powerManager.isPowerSaveMode(); - } else { - return (POWER_SAVE_MODE_SAMSUNG.equals(mode)); - } - } - - private Boolean getPowerSaveModeHuawei() { - int mode = - Settings.System.getInt(applicationContext.getContentResolver(), "SmartModeStatus", -1); - if (mode != -1) { - return (mode == POWER_SAVE_MODE_HUAWEI); - } - return null; - } - - private Boolean getPowerSaveModeForXiaomi() { - int mode = - Settings.System.getInt(applicationContext.getContentResolver(), "POWER_SAVE_MODE_OPEN", -1); - if (mode != -1) { - return (mode == POWER_SAVE_MODE_XIAOMI); - } - return null; - } - - @RequiresApi(api = VERSION_CODES.LOLLIPOP) - private int getBatteryProperty(int property) { - BatteryManager batteryManager = - (BatteryManager) applicationContext.getSystemService(Context.BATTERY_SERVICE); - return batteryManager.getIntProperty(property); - } - - private static String convertBatteryStatus(int status) { - switch (status) { - case BatteryManager.BATTERY_STATUS_CHARGING: - return "charging"; - case BatteryManager.BATTERY_STATUS_FULL: - return "full"; - case BatteryManager.BATTERY_STATUS_DISCHARGING: - case BatteryManager.BATTERY_STATUS_NOT_CHARGING: - return "discharging"; - case BatteryManager.BATTERY_STATUS_UNKNOWN: - return "unknown"; - default: - return null; - } - } - - private static void publishBatteryStatus(final EventSink events, String status) { - if (status != null) { - events.success(status); - } else { - events.error("UNAVAILABLE", "Charging status unavailable", null); - } - } - - 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); - publishBatteryStatus(events, convertBatteryStatus(status)); - } - }; - } -} diff --git a/packages/battery_plus/battery_plus/android/src/main/kotlin/dev/fluttercommunity/plus/battery/BatteryPlusPlugin.kt b/packages/battery_plus/battery_plus/android/src/main/kotlin/dev/fluttercommunity/plus/battery/BatteryPlusPlugin.kt new file mode 100644 index 0000000000..31d2079bf1 --- /dev/null +++ b/packages/battery_plus/battery_plus/android/src/main/kotlin/dev/fluttercommunity/plus/battery/BatteryPlusPlugin.kt @@ -0,0 +1,195 @@ +package dev.fluttercommunity.plus.battery + +import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import io.flutter.plugin.common.EventChannel +import io.flutter.embedding.engine.plugins.FlutterPlugin +import android.content.Context +import android.content.BroadcastReceiver +import io.flutter.plugin.common.MethodChannel +import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding +import io.flutter.plugin.common.MethodCall +import android.annotation.TargetApi +import android.os.Build.VERSION_CODES +import io.flutter.plugin.common.EventChannel.EventSink +import android.content.IntentFilter +import android.content.Intent +import android.os.BatteryManager +import android.os.Build.VERSION +import android.content.ContextWrapper +import android.os.Build +import java.util.Locale +import android.os.PowerManager +import android.provider.Settings +import androidx.annotation.RequiresApi + +/** BatteryPlusPlugin */ +class BatteryPlusPlugin : MethodCallHandler, EventChannel.StreamHandler, FlutterPlugin { + private var applicationContext: Context? = null + private var chargingStateChangeReceiver: BroadcastReceiver? = null + private var methodChannel: MethodChannel? = null + private var eventChannel: EventChannel? = null + + override fun onAttachedToEngine(binding: FlutterPluginBinding) { + this.applicationContext = binding.applicationContext + methodChannel = MethodChannel(binding.binaryMessenger, "dev.fluttercommunity.plus/battery") + eventChannel = EventChannel(binding.binaryMessenger, "dev.fluttercommunity.plus/charging") + eventChannel!!.setStreamHandler(this) + methodChannel!!.setMethodCallHandler(this) + } + + override fun onDetachedFromEngine(binding: FlutterPluginBinding) { + applicationContext = null + methodChannel!!.setMethodCallHandler(null) + methodChannel = null + eventChannel!!.setStreamHandler(null) + eventChannel = null + } + + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + when (call.method) { + "getBatteryLevel" -> { + val currentBatteryLevel = getBatteryLevel() + if (currentBatteryLevel != -1) { + result.success(currentBatteryLevel) + } else { + result.error("UNAVAILABLE", "Battery level not available.", null) + } + } + "getBatteryState" -> { + val currentBatteryStatus = getBatteryStatus() + if (currentBatteryStatus != null) { + result.success(currentBatteryStatus) + } else { + result.error("UNAVAILABLE", "Charging status not available.", null) + } + } + "isInBatterySaveMode" -> { + val isInPowerSaveMode = isInPowerSaveMode() + if (isInPowerSaveMode != null) { + result.success(isInPowerSaveMode) + } else { + result.error("UNAVAILABLE", "Battery save mode not available.", null) + } + } + else -> result.notImplemented() + } + } + + @TargetApi(VERSION_CODES.O) + override fun onListen(arguments: Any, events: EventSink) { + chargingStateChangeReceiver = createChargingStateChangeReceiver(events) + applicationContext!!.registerReceiver(chargingStateChangeReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) + val status = getBatteryStatus() + publishBatteryStatus(events, status) + } + + override fun onCancel(arguments: Any) { + applicationContext!!.unregisterReceiver(chargingStateChangeReceiver) + chargingStateChangeReceiver = null + } + + private fun getBatteryStatus(): String? { + val status: Int = if (VERSION.SDK_INT >= VERSION_CODES.O) { + getBatteryProperty(BatteryManager.BATTERY_PROPERTY_STATUS) + } else { + BatteryManager.BATTERY_STATUS_UNKNOWN + } + return convertBatteryStatus(status) + } + + private fun getBatteryLevel(): Int { + return if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { + getBatteryProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) + } else { + val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) + val level = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) + val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1) + (level * 100 / scale) + } + } + + private fun isInPowerSaveMode(): Boolean? { + val deviceManufacturer = Build.MANUFACTURER.lowercase(Locale.getDefault()) + + return if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { + when (deviceManufacturer) { + "xiaomi" -> isXiaomiPowerSaveModeActive() + "huawei" -> isHuaweiPowerSaveModeActive() + "samsung" -> isSamsungPowerSaveModeActive() + else -> { + val powerManager = applicationContext!!.getSystemService(Context.POWER_SERVICE) as PowerManager + powerManager.isPowerSaveMode + } + } + } else { + null + } + } + + private fun isSamsungPowerSaveModeActive(): Boolean { + val mode = Settings.System.getString(applicationContext!!.contentResolver, "psm_switch") + return if (mode == null && VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { + val powerManager = applicationContext!!.getSystemService(Context.POWER_SERVICE) as PowerManager + powerManager.isPowerSaveMode + } else { + POWER_SAVE_MODE_SAMSUNG == mode + } + } + + private fun isHuaweiPowerSaveModeActive(): Boolean? { + val mode = Settings.System.getInt(applicationContext!!.contentResolver, "SmartModeStatus", -1) + return if (mode != -1) { + mode == POWER_SAVE_MODE_HUAWEI + } else { + null + } + } + + private fun isXiaomiPowerSaveModeActive(): Boolean? { + val mode = Settings.System.getInt(applicationContext!!.contentResolver, "POWER_SAVE_MODE_OPEN", -1) + return if (mode != -1) { + mode == POWER_SAVE_MODE_XIAOMI + } else { + null + } + } + + @RequiresApi(api = VERSION_CODES.LOLLIPOP) + private fun getBatteryProperty(property: Int): Int { + val batteryManager = applicationContext!!.getSystemService(Context.BATTERY_SERVICE) as BatteryManager + return batteryManager.getIntProperty(property) + } + + private fun createChargingStateChangeReceiver(events: EventSink): BroadcastReceiver { + return object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1) + publishBatteryStatus(events, convertBatteryStatus(status)) + } + } + } + + private fun convertBatteryStatus(status: Int): String? { + return when (status) { + BatteryManager.BATTERY_STATUS_CHARGING -> "charging" + BatteryManager.BATTERY_STATUS_FULL -> "full" + BatteryManager.BATTERY_STATUS_DISCHARGING, BatteryManager.BATTERY_STATUS_NOT_CHARGING -> "discharging" + BatteryManager.BATTERY_STATUS_UNKNOWN -> "unknown" + else -> null + } + } + + private fun publishBatteryStatus(events: EventSink, status: String?) { + if (status != null) { + events.success(status) + } else { + events.error("UNAVAILABLE", "Charging status unavailable", null) + } + } + + companion object { + private const val POWER_SAVE_MODE_SAMSUNG = "1" + private const val POWER_SAVE_MODE_XIAOMI = 1 + private const val POWER_SAVE_MODE_HUAWEI = 4 + } +} diff --git a/packages/battery_plus/battery_plus/example/android/app/build.gradle b/packages/battery_plus/battery_plus/example/android/app/build.gradle index b9587ca56a..52414d03c0 100644 --- a/packages/battery_plus/battery_plus/example/android/app/build.gradle +++ b/packages/battery_plus/battery_plus/example/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 31 + compileSdkVersion 33 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -40,7 +40,7 @@ android { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "io.flutter.plugins.batteryexample.example" minSdkVersion 16 - targetSdkVersion 31 + targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } @@ -59,5 +59,5 @@ flutter { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" } diff --git a/packages/battery_plus/battery_plus/example/android/build.gradle b/packages/battery_plus/battery_plus/example/android/build.gradle index cba6c84b63..e50c3a02b0 100644 --- a/packages/battery_plus/battery_plus/example/android/build.gradle +++ b/packages/battery_plus/battery_plus/example/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.1.1' + classpath 'com.android.tools.build:gradle:7.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/packages/battery_plus/battery_plus/example/android/gradle.properties b/packages/battery_plus/battery_plus/example/android/gradle.properties index 94adc3a3f9..d9cf55df7c 100644 --- a/packages/battery_plus/battery_plus/example/android/gradle.properties +++ b/packages/battery_plus/battery_plus/example/android/gradle.properties @@ -1,3 +1,2 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true -android.enableJetifier=true diff --git a/packages/battery_plus/battery_plus/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/battery_plus/battery_plus/example/android/gradle/wrapper/gradle-wrapper.properties index 48be6dfa99..aa6c47903b 100644 --- a/packages/battery_plus/battery_plus/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/battery_plus/battery_plus/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Oct 05 14:03:03 CEST 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/packages/battery_plus/battery_plus/pubspec.yaml b/packages/battery_plus/battery_plus/pubspec.yaml index efad4c0b9a..a3a050e277 100644 --- a/packages/battery_plus/battery_plus/pubspec.yaml +++ b/packages/battery_plus/battery_plus/pubspec.yaml @@ -1,6 +1,6 @@ name: battery_plus description: Flutter plugin for accessing information about the battery state(full, charging, discharging). -version: 2.1.4+1 +version: 2.2.0 homepage: https://plus.fluttercommunity.dev/ repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/ issue_tracker: https://github.com/fluttercommunity/plus_plugins/labels/battery_plus @@ -25,20 +25,19 @@ flutter: dependencies: flutter: sdk: flutter - meta: ^1.7.0 + meta: ^1.8.0 + battery_plus_platform_interface: ^1.2.1 - battery_plus_linux: ^1.1.1 - battery_plus_macos: ^1.1.0 + battery_plus_linux: ^1.2.0 + battery_plus_macos: ^1.1.1 battery_plus_web: ^1.1.0 battery_plus_windows: ^1.1.3 dev_dependencies: flutter_test: sdk: flutter - - async: ^2.8.2 - plugin_platform_interface: ^2.1.2 - test: ^1.16.4 + async: ^2.9.0 + plugin_platform_interface: ^2.1.3 flutter_lints: ^2.0.1 environment: diff --git a/packages/battery_plus/battery_plus/test/battery_test.dart b/packages/battery_plus/battery_plus/test/battery_test.dart index 53b444e95e..f98c80932d 100644 --- a/packages/battery_plus/battery_plus/test/battery_test.dart +++ b/packages/battery_plus/battery_plus/test/battery_test.dart @@ -7,8 +7,8 @@ import 'dart:async'; import 'package:async/async.dart'; import 'package:battery_plus/battery_plus.dart'; import 'package:battery_plus_platform_interface/battery_plus_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'package:test/test.dart'; late StreamController controller;