Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit e61ba6e

Browse files
author
Chris Yang
authored
[device_info] Support v2 android embedding. (#2163)
1 parent 3ad2d83 commit e61ba6e

File tree

14 files changed

+301
-108
lines changed

14 files changed

+301
-108
lines changed

packages/device_info/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 0.4.1
2+
3+
* Support the v2 Android embedding.
4+
* Update to AndroidX.
5+
* Migrate to using the new e2e test binding.
6+
* Add a e2e test.
7+
8+
19
## 0.4.0+4
210

311
* Define clang module for iOS.

packages/device_info/android/build.gradle

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,29 @@ android {
4545
disable 'InvalidPackage'
4646
}
4747
}
48+
49+
// TODO(cyanglaz): Remove this hack once androidx.lifecycle is included on stable. https://github.com/flutter/flutter/issues/42348
50+
afterEvaluate {
51+
def containsEmbeddingDependencies = false
52+
for (def configuration : configurations.all) {
53+
for (def dependency : configuration.dependencies) {
54+
if (dependency.group == 'io.flutter' &&
55+
dependency.name.startsWith('flutter_embedding') &&
56+
dependency.isTransitive())
57+
{
58+
containsEmbeddingDependencies = true
59+
break
60+
}
61+
}
62+
}
63+
if (!containsEmbeddingDependencies) {
64+
android {
65+
dependencies {
66+
def lifecycle_version = "1.1.1"
67+
api "android.arch.lifecycle:runtime:$lifecycle_version"
68+
api "android.arch.lifecycle:common:$lifecycle_version"
69+
api "android.arch.lifecycle:common-java8:$lifecycle_version"
70+
}
71+
}
72+
}
73+
}

packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java

Lines changed: 21 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -4,120 +4,43 @@
44

55
package io.flutter.plugins.deviceinfo;
66

7-
import android.annotation.SuppressLint;
8-
import android.content.Context;
9-
import android.os.Build;
10-
import android.os.Build.VERSION;
11-
import android.os.Build.VERSION_CODES;
12-
import android.provider.Settings;
13-
import io.flutter.plugin.common.MethodCall;
7+
import android.content.ContentResolver;
8+
import io.flutter.embedding.engine.plugins.FlutterPlugin;
9+
import io.flutter.plugin.common.BinaryMessenger;
1410
import io.flutter.plugin.common.MethodChannel;
15-
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
16-
import io.flutter.plugin.common.MethodChannel.Result;
1711
import io.flutter.plugin.common.PluginRegistry.Registrar;
18-
import java.util.Arrays;
19-
import java.util.HashMap;
20-
import java.util.Map;
2112

2213
/** DeviceInfoPlugin */
23-
public class DeviceInfoPlugin implements MethodCallHandler {
24-
private final Context context;
14+
public class DeviceInfoPlugin implements FlutterPlugin {
2515

26-
/** Substitute for missing values. */
27-
private static final String[] EMPTY_STRING_LIST = new String[] {};
16+
MethodChannel channel;
2817

2918
/** Plugin registration. */
3019
public static void registerWith(Registrar registrar) {
31-
final MethodChannel channel =
32-
new MethodChannel(registrar.messenger(), "plugins.flutter.io/device_info");
33-
channel.setMethodCallHandler(new DeviceInfoPlugin(registrar.context()));
20+
DeviceInfoPlugin plugin = new DeviceInfoPlugin();
21+
plugin.setupMethodChannel(registrar.messenger(), registrar.context().getContentResolver());
3422
}
3523

36-
/** Do not allow direct instantiation. */
37-
private DeviceInfoPlugin(Context context) {
38-
this.context = context;
24+
@Override
25+
public void onAttachedToEngine(FlutterPlugin.FlutterPluginBinding binding) {
26+
setupMethodChannel(
27+
binding.getFlutterEngine().getDartExecutor(),
28+
binding.getApplicationContext().getContentResolver());
3929
}
4030

4131
@Override
42-
public void onMethodCall(MethodCall call, Result result) {
43-
if (call.method.equals("getAndroidDeviceInfo")) {
44-
Map<String, Object> build = new HashMap<>();
45-
build.put("board", Build.BOARD);
46-
build.put("bootloader", Build.BOOTLOADER);
47-
build.put("brand", Build.BRAND);
48-
build.put("device", Build.DEVICE);
49-
build.put("display", Build.DISPLAY);
50-
build.put("fingerprint", Build.FINGERPRINT);
51-
build.put("hardware", Build.HARDWARE);
52-
build.put("host", Build.HOST);
53-
build.put("id", Build.ID);
54-
build.put("manufacturer", Build.MANUFACTURER);
55-
build.put("model", Build.MODEL);
56-
build.put("product", Build.PRODUCT);
57-
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
58-
build.put("supported32BitAbis", Arrays.asList(Build.SUPPORTED_32_BIT_ABIS));
59-
build.put("supported64BitAbis", Arrays.asList(Build.SUPPORTED_64_BIT_ABIS));
60-
build.put("supportedAbis", Arrays.asList(Build.SUPPORTED_ABIS));
61-
} else {
62-
build.put("supported32BitAbis", Arrays.asList(EMPTY_STRING_LIST));
63-
build.put("supported64BitAbis", Arrays.asList(EMPTY_STRING_LIST));
64-
build.put("supportedAbis", Arrays.asList(EMPTY_STRING_LIST));
65-
}
66-
build.put("tags", Build.TAGS);
67-
build.put("type", Build.TYPE);
68-
build.put("isPhysicalDevice", !isEmulator());
69-
build.put("androidId", getAndroidId());
70-
71-
Map<String, Object> version = new HashMap<>();
72-
if (VERSION.SDK_INT >= VERSION_CODES.M) {
73-
version.put("baseOS", VERSION.BASE_OS);
74-
version.put("previewSdkInt", VERSION.PREVIEW_SDK_INT);
75-
version.put("securityPatch", VERSION.SECURITY_PATCH);
76-
}
77-
version.put("codename", VERSION.CODENAME);
78-
version.put("incremental", VERSION.INCREMENTAL);
79-
version.put("release", VERSION.RELEASE);
80-
version.put("sdkInt", VERSION.SDK_INT);
81-
build.put("version", version);
82-
83-
result.success(build);
84-
} else {
85-
result.notImplemented();
86-
}
32+
public void onDetachedFromEngine(FlutterPlugin.FlutterPluginBinding binding) {
33+
tearDownChannel();
8734
}
8835

89-
/**
90-
* Returns the Android hardware device ID that is unique between the device + user and app
91-
* signing. This key will change if the app is uninstalled or its data is cleared. Device factory
92-
* reset will also result in a value change.
93-
*
94-
* @return The android ID
95-
*/
96-
@SuppressLint("HardwareIds")
97-
private String getAndroidId() {
98-
return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
36+
private void setupMethodChannel(BinaryMessenger messenger, ContentResolver contentResolver) {
37+
channel = new MethodChannel(messenger, "plugins.flutter.io/device_info");
38+
final MethodCallHandlerImpl handler = new MethodCallHandlerImpl(contentResolver);
39+
channel.setMethodCallHandler(handler);
9940
}
10041

101-
/**
102-
* A simple emulator-detection based on the flutter tools detection logic and a couple of legacy
103-
* detection systems
104-
*/
105-
private boolean isEmulator() {
106-
return (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
107-
|| Build.FINGERPRINT.startsWith("generic")
108-
|| Build.FINGERPRINT.startsWith("unknown")
109-
|| Build.HARDWARE.contains("goldfish")
110-
|| Build.HARDWARE.contains("ranchu")
111-
|| Build.MODEL.contains("google_sdk")
112-
|| Build.MODEL.contains("Emulator")
113-
|| Build.MODEL.contains("Android SDK built for x86")
114-
|| Build.MANUFACTURER.contains("Genymotion")
115-
|| Build.PRODUCT.contains("sdk_google")
116-
|| Build.PRODUCT.contains("google_sdk")
117-
|| Build.PRODUCT.contains("sdk")
118-
|| Build.PRODUCT.contains("sdk_x86")
119-
|| Build.PRODUCT.contains("vbox86p")
120-
|| Build.PRODUCT.contains("emulator")
121-
|| Build.PRODUCT.contains("simulator");
42+
private void tearDownChannel() {
43+
channel.setMethodCallHandler(null);
44+
channel = null;
12245
}
12346
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright 2017 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.deviceinfo;
6+
7+
import android.annotation.SuppressLint;
8+
import android.content.ContentResolver;
9+
import android.os.Build;
10+
import android.provider.Settings;
11+
import io.flutter.plugin.common.MethodCall;
12+
import io.flutter.plugin.common.MethodChannel;
13+
import java.util.Arrays;
14+
import java.util.HashMap;
15+
import java.util.Map;
16+
17+
/**
18+
* The implementation of {@link MethodChannel.MethodCallHandler} for the plugin. Responsible for
19+
* receiving method calls from method channel.
20+
*/
21+
class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
22+
23+
private ContentResolver contentResolver;
24+
25+
/** Substitute for missing values. */
26+
private static final String[] EMPTY_STRING_LIST = new String[] {};
27+
28+
/** Constructs DeviceInfo. The {@code contentResolver} must not be null. */
29+
MethodCallHandlerImpl(ContentResolver contentResolver) {
30+
this.contentResolver = contentResolver;
31+
}
32+
33+
@Override
34+
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
35+
if (call.method.equals("getAndroidDeviceInfo")) {
36+
Map<String, Object> build = new HashMap<>();
37+
build.put("board", Build.BOARD);
38+
build.put("bootloader", Build.BOOTLOADER);
39+
build.put("brand", Build.BRAND);
40+
build.put("device", Build.DEVICE);
41+
build.put("display", Build.DISPLAY);
42+
build.put("fingerprint", Build.FINGERPRINT);
43+
build.put("hardware", Build.HARDWARE);
44+
build.put("host", Build.HOST);
45+
build.put("id", Build.ID);
46+
build.put("manufacturer", Build.MANUFACTURER);
47+
build.put("model", Build.MODEL);
48+
build.put("product", Build.PRODUCT);
49+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
50+
build.put("supported32BitAbis", Arrays.asList(Build.SUPPORTED_32_BIT_ABIS));
51+
build.put("supported64BitAbis", Arrays.asList(Build.SUPPORTED_64_BIT_ABIS));
52+
build.put("supportedAbis", Arrays.asList(Build.SUPPORTED_ABIS));
53+
} else {
54+
build.put("supported32BitAbis", Arrays.asList(EMPTY_STRING_LIST));
55+
build.put("supported64BitAbis", Arrays.asList(EMPTY_STRING_LIST));
56+
build.put("supportedAbis", Arrays.asList(EMPTY_STRING_LIST));
57+
}
58+
build.put("tags", Build.TAGS);
59+
build.put("type", Build.TYPE);
60+
build.put("isPhysicalDevice", !isEmulator());
61+
build.put("androidId", getAndroidId());
62+
63+
Map<String, Object> version = new HashMap<>();
64+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
65+
version.put("baseOS", Build.VERSION.BASE_OS);
66+
version.put("previewSdkInt", Build.VERSION.PREVIEW_SDK_INT);
67+
version.put("securityPatch", Build.VERSION.SECURITY_PATCH);
68+
}
69+
version.put("codename", Build.VERSION.CODENAME);
70+
version.put("incremental", Build.VERSION.INCREMENTAL);
71+
version.put("release", Build.VERSION.RELEASE);
72+
version.put("sdkInt", Build.VERSION.SDK_INT);
73+
build.put("version", version);
74+
75+
result.success(build);
76+
} else {
77+
result.notImplemented();
78+
}
79+
}
80+
81+
/**
82+
* Returns the Android hardware device ID that is unique between the device + user and app
83+
* signing. This key will change if the app is uninstalled or its data is cleared. Device factory
84+
* reset will also result in a value change.
85+
*
86+
* @return The android ID
87+
*/
88+
@SuppressLint("HardwareIds")
89+
private String getAndroidId() {
90+
return Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID);
91+
}
92+
93+
/**
94+
* A simple emulator-detection based on the flutter tools detection logic and a couple of legacy
95+
* detection systems
96+
*/
97+
private boolean isEmulator() {
98+
return (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
99+
|| Build.FINGERPRINT.startsWith("generic")
100+
|| Build.FINGERPRINT.startsWith("unknown")
101+
|| Build.HARDWARE.contains("goldfish")
102+
|| Build.HARDWARE.contains("ranchu")
103+
|| Build.MODEL.contains("google_sdk")
104+
|| Build.MODEL.contains("Emulator")
105+
|| Build.MODEL.contains("Android SDK built for x86")
106+
|| Build.MANUFACTURER.contains("Genymotion")
107+
|| Build.PRODUCT.contains("sdk_google")
108+
|| Build.PRODUCT.contains("google_sdk")
109+
|| Build.PRODUCT.contains("sdk")
110+
|| Build.PRODUCT.contains("sdk_x86")
111+
|| Build.PRODUCT.contains("vbox86p")
112+
|| Build.PRODUCT.contains("emulator")
113+
|| Build.PRODUCT.contains("simulator");
114+
}
115+
}

packages/device_info/example/android/app/src/main/AndroidManifest.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,19 @@
44
<uses-permission android:name="android.permission.INTERNET"/>
55

66
<application android:name="io.flutter.app.FlutterApplication" android:label="device_info_example" android:icon="@mipmap/ic_launcher">
7-
<activity android:name="io.flutter.plugins.deviceinfoexample.MainActivity"
7+
<activity android:name=".EmbeddingV1Activity"
88
android:launchMode="singleTop"
99
android:theme="@android:style/Theme.Black.NoTitleBar"
1010
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
1111
android:hardwareAccelerated="true"
12+
android:exported="true"
1213
android:windowSoftInputMode="adjustResize">
14+
</activity>
15+
<activity android:name=".MainActivity"
16+
android:theme="@android:style/Theme.Black.NoTitleBar"
17+
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
18+
android:hardwareAccelerated="true"
19+
android:windowSoftInputMode="adjustResize">
1320
<intent-filter>
1421
<action android:name="android.intent.action.MAIN"/>
1522
<category android:name="android.intent.category.LAUNCHER"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2017 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.deviceinfoexample;
6+
7+
import android.os.Bundle;
8+
import io.flutter.app.FlutterActivity;
9+
import io.flutter.plugins.GeneratedPluginRegistrant;
10+
11+
public class EmbeddingV1Activity extends FlutterActivity {
12+
@Override
13+
protected void onCreate(Bundle savedInstanceState) {
14+
super.onCreate(savedInstanceState);
15+
GeneratedPluginRegistrant.registerWith(this);
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.flutter.plugins.deviceinfoexample;
2+
3+
import androidx.test.rule.ActivityTestRule;
4+
import dev.flutter.plugins.e2e.FlutterRunner;
5+
import org.junit.Rule;
6+
import org.junit.runner.RunWith;
7+
8+
@RunWith(FlutterRunner.class)
9+
public class EmbeddingV1ActivityTest {
10+
@Rule
11+
public ActivityTestRule<EmbeddingV1Activity> rule =
12+
new ActivityTestRule<>(EmbeddingV1Activity.class);
13+
}
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1-
// Copyright 2017 The Chromium Authors. All rights reserved.
1+
// Copyright 2019 The Chromium Authors. All rights reserved.
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

55
package io.flutter.plugins.deviceinfoexample;
66

7-
import android.os.Bundle;
8-
import io.flutter.app.FlutterActivity;
9-
import io.flutter.plugins.GeneratedPluginRegistrant;
7+
import io.flutter.embedding.android.FlutterActivity;
8+
import io.flutter.embedding.engine.FlutterEngine;
9+
import io.flutter.plugins.deviceinfo.DeviceInfoPlugin;
1010

1111
public class MainActivity extends FlutterActivity {
12+
13+
// TODO(cyanglaz): Remove this once v2 of GeneratedPluginRegistrant rolls to stable.
14+
// https://github.com/flutter/flutter/issues/42694
1215
@Override
13-
protected void onCreate(Bundle savedInstanceState) {
14-
super.onCreate(savedInstanceState);
15-
GeneratedPluginRegistrant.registerWith(this);
16+
public void configureFlutterEngine(FlutterEngine flutterEngine) {
17+
super.configureFlutterEngine(flutterEngine);
18+
flutterEngine.getPlugins().add(new DeviceInfoPlugin());
1619
}
1720
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2019 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.deviceinfoexample;
6+
7+
import androidx.test.rule.ActivityTestRule;
8+
import dev.flutter.plugins.e2e.FlutterRunner;
9+
import org.junit.Rule;
10+
import org.junit.runner.RunWith;
11+
12+
@RunWith(FlutterRunner.class)
13+
public class MainActivityTest {
14+
@Rule public ActivityTestRule<MainActivity> rule = new ActivityTestRule<>(MainActivity.class);
15+
}

0 commit comments

Comments
 (0)