Skip to content

Commit f8de6b8

Browse files
author
alexandre_poichet
committed
add android connetivity feature
1 parent 5d5c7cc commit f8de6b8

27 files changed

+1368
-331
lines changed

.fvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"flutter": "3.19.3",
2+
"flutter": "3.19.6",
33
"flavors": {}
44
}

.github/workflows/test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
working-directory: lib
4040

4141
- name: Run tests
42-
run: flutter test --coverage --update-goldens
42+
run: flutter test --coverage && lcov --remove coverage/lcov.info 'lib/flutter_eco_mode_platform_interface.dart' 'lib/messages.g.dart' 'lib/streams/*' -o coverage/lcov.info
4343

4444
- name: Upload coverage reports to Codecov
4545
uses: codecov/[email protected]

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,6 @@ migrate_working_dir/
2727
**/doc/api/
2828
.dart_tool/
2929
build/
30-
.fvm
30+
31+
# FVM Version Cache
32+
.fvm/

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ also to offer a less energy-consuming app.
3939
| Battery Level | Yes | Yes | X | X |
4040
| Battery In Low Power Mode | Yes | Yes | X | X |
4141
| <span style="color: #3CB371">**Battery Eco Mode**</span> | <span style="color: #3CB371">Yes</span> | <span style="color: #3CB371">Yes</span> | <span style="color: #3CB371">X</span> | <span style="color: #3CB371">X</span> |
42+
| <span style="color: #007FFF">**Connectivity**</span> | <span style="color: #007FFF">Yes</span> | <span style="color: #007FFF">No</span> | <span style="color: #007FFF">X</span> | <span style="color: #007FFF">X</span> |
4243

4344
## Eco Mode
4445

@@ -82,6 +83,44 @@ It will return a boolean.
8283
]).map((event) => event.every((element) => element)).asBroadcastStream();
8384
```
8485

86+
## Connectivity
87+
88+
### /!\ Only available for Android at the moment
89+
90+
This feature can help you to observe the network, know if the device is connected to the internet,
91+
or just want to adapt your app to the network state.
92+
93+
We have created a class **_Connectivity_** which contains basic information about the network.
94+
95+
And you can use directly the methode **_hasEnoughNetwork_** which follows these rules in the code
96+
97+
```
98+
extension on Connectivity {
99+
bool? get isEnough => type == ConnectivityType.unknown
100+
? null
101+
: (_isMobileEnoughNetwork || _isWifiEnoughNetwork || type == ConnectivityType.ethernet);
102+
103+
bool get _isMobileEnoughNetwork =>
104+
[ConnectivityType.mobile5g, ConnectivityType.mobile4g, ConnectivityType.mobile3g].contains(type);
105+
106+
bool get _isWifiEnoughNetwork =>
107+
ConnectivityType.wifi == type && wifiSignalStrength != null ? wifiSignalStrength! >= minWifiSignalStrength : false;
108+
}
109+
```
110+
111+
### How does it work ?
112+
113+
* First, we retrieve the type of network via native access.
114+
* Then, if we have Wifi identified we catch the signal strength.
115+
* And finally, we build and return the object Connectivity.
116+
117+
At this moment, you can ask your self. Is it really reliable ? Is there a better way ?
118+
119+
Probably the better thing to do is to make your own speed test in your app.
120+
You're right, it's more precise, and you can directly define what is a good network fo your purposes.
121+
But you need to ping a server, and it's not really eco-friendly.
122+
Here we just use the native access, trust directly your device and OS.
123+
85124
## Example
86125

87126
See the `example` directory for a complete sample app using flutter_eco_mode.

android/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ version '1.0-SNAPSHOT'
33

44
buildscript {
55
ext.kotlin_version = '1.7.10'
6+
67
repositories {
78
google()
89
mavenCentral()
@@ -12,9 +13,11 @@ buildscript {
1213
classpath 'com.android.tools.build:gradle:8.3.2'
1314
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1415
}
16+
1517
}
1618

1719
allprojects {
20+
1821
repositories {
1922
google()
2023
mavenCentral()
@@ -25,6 +28,7 @@ apply plugin: 'com.android.library'
2528
apply plugin: 'kotlin-android'
2629

2730
android {
31+
2832
if (project.android.hasProperty("namespace")) {
2933
namespace 'sncf.connect.tech.flutter_eco_mode'
3034
}
@@ -56,6 +60,7 @@ android {
5660
testImplementation 'org.powermock:powermock-module-junit4-rule-agent:1.6.2'
5761
testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.2'
5862
testImplementation 'org.powermock:powermock-module-junit4:1.6.2'
63+
implementation('com.google.code.gson:gson:2.10.1')
5964
}
6065

6166
tasks.withType(Test).configureEach {
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
22
package="sncf.connect.tech.flutter_eco_mode">
3+
4+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
5+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
6+
<uses-permission android:name="android.permission.READ_BASIC_PHONE_STATE" />
37
</manifest>
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package listener
2+
3+
import android.content.BroadcastReceiver
4+
import android.content.Context
5+
import android.content.Intent
6+
import android.content.Intent.ACTION_BATTERY_CHANGED
7+
import android.content.IntentFilter
8+
import android.os.BatteryManager
9+
import android.os.BatteryManager.BATTERY_STATUS_CHARGING
10+
import android.os.BatteryManager.BATTERY_STATUS_DISCHARGING
11+
import android.os.BatteryManager.BATTERY_STATUS_FULL
12+
import android.os.BatteryManager.BATTERY_STATUS_NOT_CHARGING
13+
import android.os.Build
14+
import android.os.PowerManager
15+
import androidx.annotation.RequiresApi
16+
import io.flutter.plugin.common.EventChannel
17+
import sncf.connect.tech.flutter_eco_mode.BatteryState.CHARGING
18+
import sncf.connect.tech.flutter_eco_mode.BatteryState.DISCHARGING
19+
import sncf.connect.tech.flutter_eco_mode.BatteryState.FULL
20+
import sncf.connect.tech.flutter_eco_mode.BatteryState.UNKNOWN
21+
22+
class PowerModeStreamHandler(private val context: Context) : EventChannel.StreamHandler {
23+
24+
private var lowPowerModeEventSink: EventChannel.EventSink? = null
25+
private var powerSavingReceiver: BroadcastReceiver? = null
26+
27+
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
28+
lowPowerModeEventSink = events
29+
30+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
31+
setupPowerSavingReceiver()
32+
}
33+
}
34+
35+
override fun onCancel(p0: Any?) {
36+
context.unregisterReceiver(powerSavingReceiver)
37+
}
38+
39+
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
40+
private fun setupPowerSavingReceiver() {
41+
powerSavingReceiver = object : BroadcastReceiver() {
42+
override fun onReceive(context: Context, intent: Intent?) {
43+
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
44+
lowPowerModeEventSink?.success(powerManager.isPowerSaveMode)
45+
}
46+
}
47+
val filter = IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
48+
context.registerReceiver(powerSavingReceiver, filter)
49+
}
50+
51+
}
52+
53+
class BatteryStateStreamHandler(private val context: Context) : EventChannel.StreamHandler {
54+
55+
private var batteryStateEventSink: EventChannel.EventSink? = null
56+
private var batteryStateReceiver: BroadcastReceiver? = null
57+
58+
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
59+
batteryStateEventSink = events
60+
61+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
62+
setupBatteryStateReceiver()
63+
}
64+
}
65+
66+
override fun onCancel(p0: Any?) {
67+
context.unregisterReceiver(batteryStateReceiver)
68+
}
69+
70+
@RequiresApi(Build.VERSION_CODES.M)
71+
private fun setupBatteryStateReceiver() {
72+
batteryStateReceiver = object : BroadcastReceiver() {
73+
override fun onReceive(context: Context, intent: Intent?) {
74+
val event = when (intent?.action) {
75+
ACTION_BATTERY_CHANGED ->
76+
when (intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)) {
77+
BATTERY_STATUS_CHARGING -> CHARGING.name
78+
BATTERY_STATUS_FULL -> FULL.name
79+
BATTERY_STATUS_DISCHARGING, BATTERY_STATUS_NOT_CHARGING -> DISCHARGING.name
80+
else -> UNKNOWN.name
81+
}
82+
83+
else -> DISCHARGING.name
84+
}
85+
batteryStateEventSink?.success(event)
86+
}
87+
}
88+
val filterBatteryState = IntentFilter()
89+
filterBatteryState.addAction(ACTION_BATTERY_CHANGED)
90+
context.registerReceiver(batteryStateReceiver, filterBatteryState)
91+
}
92+
93+
}
94+
95+
class BatteryLevelStreamHandler(private val context: Context) : EventChannel.StreamHandler {
96+
97+
private var batteryLevelEventSink: EventChannel.EventSink? = null
98+
private var batteryLevelReceiver: BroadcastReceiver? = null
99+
100+
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
101+
batteryLevelEventSink = events
102+
103+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
104+
setupBatteryLevelReceiver()
105+
}
106+
}
107+
108+
override fun onCancel(p0: Any?) {
109+
context.unregisterReceiver(batteryLevelReceiver)
110+
}
111+
112+
113+
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
114+
private fun setupBatteryLevelReceiver() {
115+
116+
batteryLevelReceiver = object : BroadcastReceiver() {
117+
118+
override fun onReceive(context: Context, intent: Intent?) {
119+
val batteryPct = intent?.let { i ->
120+
val level: Int = i.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
121+
val scale: Int = i.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
122+
level * 100 / scale.toFloat()
123+
}
124+
batteryLevelEventSink?.success(batteryPct?.toDouble())
125+
}
126+
}
127+
val filter = IntentFilter(ACTION_BATTERY_CHANGED)
128+
context.registerReceiver(batteryLevelReceiver, filter)
129+
130+
}
131+
132+
}

0 commit comments

Comments
 (0)