[device_info] add PackageManager's SystemFeatures to AndroidDeviceInfo (#2567)
There's a variety of scenarios where checking at runtime which system
features are available is useful. System features are device
capabilities that do not change at runtime (for example, FEATURE_BLUETOOTH
is always present if the device has a bluetooth radio, even if Bluetooth
is presently disabled), so DeviceInfo seems like the right place to put
this.
diff --git a/packages/device_info/CHANGELOG.md b/packages/device_info/CHANGELOG.md
index 00dcd29..68aeed8 100644
--- a/packages/device_info/CHANGELOG.md
+++ b/packages/device_info/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.4.2
+
+* Add systemFeatures to AndroidDeviceInfo.
+
## 0.4.1+5
* Make the pedantic dev_dependency explicit.
diff --git a/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java b/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java
index 8ad0f5d..a0435a4 100644
--- a/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java
+++ b/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java
@@ -4,7 +4,7 @@
package io.flutter.plugins.deviceinfo;
-import android.content.ContentResolver;
+import android.content.Context;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodChannel;
@@ -18,14 +18,13 @@
/** Plugin registration. */
public static void registerWith(Registrar registrar) {
DeviceInfoPlugin plugin = new DeviceInfoPlugin();
- plugin.setupMethodChannel(registrar.messenger(), registrar.context().getContentResolver());
+ plugin.setupMethodChannel(registrar.messenger(), registrar.context());
}
@Override
public void onAttachedToEngine(FlutterPlugin.FlutterPluginBinding binding) {
setupMethodChannel(
- binding.getFlutterEngine().getDartExecutor(),
- binding.getApplicationContext().getContentResolver());
+ binding.getFlutterEngine().getDartExecutor(), binding.getApplicationContext());
}
@Override
@@ -33,9 +32,10 @@
tearDownChannel();
}
- private void setupMethodChannel(BinaryMessenger messenger, ContentResolver contentResolver) {
+ private void setupMethodChannel(BinaryMessenger messenger, Context context) {
channel = new MethodChannel(messenger, "plugins.flutter.io/device_info");
- final MethodCallHandlerImpl handler = new MethodCallHandlerImpl(contentResolver);
+ final MethodCallHandlerImpl handler =
+ new MethodCallHandlerImpl(context.getContentResolver(), context.getPackageManager());
channel.setMethodCallHandler(handler);
}
diff --git a/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java b/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java
index 22ea1f0..800ca6d 100644
--- a/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java
+++ b/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java
@@ -6,6 +6,8 @@
import android.annotation.SuppressLint;
import android.content.ContentResolver;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
import io.flutter.plugin.common.MethodCall;
@@ -20,14 +22,16 @@
*/
class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
- private ContentResolver contentResolver;
+ private final ContentResolver contentResolver;
+ private final PackageManager packageManager;
/** Substitute for missing values. */
private static final String[] EMPTY_STRING_LIST = new String[] {};
- /** Constructs DeviceInfo. The {@code contentResolver} must not be null. */
- MethodCallHandlerImpl(ContentResolver contentResolver) {
+ /** Constructs DeviceInfo. {@code contentResolver} and {@code packageManager} must not be null. */
+ MethodCallHandlerImpl(ContentResolver contentResolver, PackageManager packageManager) {
this.contentResolver = contentResolver;
+ this.packageManager = packageManager;
}
@Override
@@ -60,6 +64,8 @@
build.put("isPhysicalDevice", !isEmulator());
build.put("androidId", getAndroidId());
+ build.put("systemFeatures", Arrays.asList(getSystemFeatures()));
+
Map<String, Object> version = new HashMap<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
version.put("baseOS", Build.VERSION.BASE_OS);
@@ -78,6 +84,18 @@
}
}
+ private String[] getSystemFeatures() {
+ FeatureInfo[] featureInfos = packageManager.getSystemAvailableFeatures();
+ if (featureInfos == null) {
+ return EMPTY_STRING_LIST;
+ }
+ String[] features = new String[featureInfos.length];
+ for (int i = 0; i < featureInfos.length; i++) {
+ features[i] = featureInfos[i].name;
+ }
+ return features;
+ }
+
/**
* Returns the Android hardware device ID that is unique between the device + user and app
* signing. This key will change if the app is uninstalled or its data is cleared. Device factory
diff --git a/packages/device_info/example/lib/main.dart b/packages/device_info/example/lib/main.dart
index 528604b..1c1064a 100644
--- a/packages/device_info/example/lib/main.dart
+++ b/packages/device_info/example/lib/main.dart
@@ -85,6 +85,7 @@
'type': build.type,
'isPhysicalDevice': build.isPhysicalDevice,
'androidId': build.androidId,
+ 'systemFeatures': build.systemFeatures,
};
}
@@ -114,7 +115,6 @@
Platform.isAndroid ? 'Android Device Info' : 'iOS Device Info'),
),
body: ListView(
- shrinkWrap: true,
children: _deviceData.keys.map((String property) {
return Row(
children: <Widget>[
@@ -132,6 +132,7 @@
padding: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
child: Text(
'${_deviceData[property]}',
+ maxLines: 10,
overflow: TextOverflow.ellipsis,
),
)),
diff --git a/packages/device_info/lib/device_info.dart b/packages/device_info/lib/device_info.dart
index e775227..25b7d46 100644
--- a/packages/device_info/lib/device_info.dart
+++ b/packages/device_info/lib/device_info.dart
@@ -62,9 +62,11 @@
this.type,
this.isPhysicalDevice,
this.androidId,
+ List<String> systemFeatures,
}) : supported32BitAbis = List<String>.unmodifiable(supported32BitAbis),
supported64BitAbis = List<String>.unmodifiable(supported64BitAbis),
- supportedAbis = List<String>.unmodifiable(supportedAbis);
+ supportedAbis = List<String>.unmodifiable(supportedAbis),
+ systemFeatures = List<String>.unmodifiable(systemFeatures);
/// Android operating system version values derived from `android.os.Build.VERSION`.
final AndroidBuildVersion version;
@@ -126,6 +128,22 @@
/// The Android hardware device ID that is unique between the device + user and app signing.
final String androidId;
+ /// Describes what features are available on the current device.
+ ///
+ /// This can be used to check if the device has, for example, a front-facing
+ /// camera, or a touchscreen. However, in many cases this is not the best
+ /// API to use. For example, if you are interested in bluetooth, this API
+ /// can tell you if the device has a bluetooth radio, but it cannot tell you
+ /// if bluetooth is currently enabled, or if you have been granted the
+ /// necessary permissions to use it. Please *only* use this if there is no
+ /// other way to determine if a feature is supported.
+ ///
+ /// This data comes from Android's PackageManager.getSystemAvailableFeatures,
+ /// and many of the common feature strings to look for are available in
+ /// PackageManager's public documentation:
+ /// https://developer.android.com/reference/android/content/pm/PackageManager
+ final List<String> systemFeatures;
+
/// Deserializes from the message received from [_kChannel].
static AndroidDeviceInfo _fromMap(Map<String, dynamic> map) {
return AndroidDeviceInfo._(
@@ -150,6 +168,7 @@
type: map['type'],
isPhysicalDevice: map['isPhysicalDevice'],
androidId: map['androidId'],
+ systemFeatures: _fromList(map['systemFeatures']),
);
}
diff --git a/packages/device_info/pubspec.yaml b/packages/device_info/pubspec.yaml
index b862a7d..06a530b 100644
--- a/packages/device_info/pubspec.yaml
+++ b/packages/device_info/pubspec.yaml
@@ -2,7 +2,7 @@
description: Flutter plugin providing detailed information about the device
(make, model, etc.), and Android or iOS version the app is running on.
homepage: https://github.com/flutter/plugins/tree/master/packages/device_info
-version: 0.4.1+5
+version: 0.4.2
flutter:
plugin: