Skip to content

Commit

Permalink
[device_info] Support v2 android embedding. (flutter#2163)
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Yang authored and Park Sung Min committed Dec 17, 2019
1 parent 8af33b3 commit a3bbef7
Show file tree
Hide file tree
Showing 14 changed files with 301 additions and 108 deletions.
8 changes: 8 additions & 0 deletions packages/device_info/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 0.4.1

* Support the v2 Android embedding.
* Update to AndroidX.
* Migrate to using the new e2e test binding.
* Add a e2e test.


## 0.4.0+4

* Define clang module for iOS.
Expand Down
26 changes: 26 additions & 0 deletions packages/device_info/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,29 @@ android {
disable 'InvalidPackage'
}
}

// TODO(cyanglaz): Remove this hack once androidx.lifecycle is included on stable. https://github.com/flutter/flutter/issues/42348
afterEvaluate {
def containsEmbeddingDependencies = false
for (def configuration : configurations.all) {
for (def dependency : configuration.dependencies) {
if (dependency.group == 'io.flutter' &&
dependency.name.startsWith('flutter_embedding') &&
dependency.isTransitive())
{
containsEmbeddingDependencies = true
break
}
}
}
if (!containsEmbeddingDependencies) {
android {
dependencies {
def lifecycle_version = "1.1.1"
api "android.arch.lifecycle:runtime:$lifecycle_version"
api "android.arch.lifecycle:common:$lifecycle_version"
api "android.arch.lifecycle:common-java8:$lifecycle_version"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,120 +4,43 @@

package io.flutter.plugins.deviceinfo;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.provider.Settings;
import io.flutter.plugin.common.MethodCall;
import android.content.ContentResolver;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/** DeviceInfoPlugin */
public class DeviceInfoPlugin implements MethodCallHandler {
private final Context context;
public class DeviceInfoPlugin implements FlutterPlugin {

/** Substitute for missing values. */
private static final String[] EMPTY_STRING_LIST = new String[] {};
MethodChannel channel;

/** Plugin registration. */
public static void registerWith(Registrar registrar) {
final MethodChannel channel =
new MethodChannel(registrar.messenger(), "plugins.flutter.io/device_info");
channel.setMethodCallHandler(new DeviceInfoPlugin(registrar.context()));
DeviceInfoPlugin plugin = new DeviceInfoPlugin();
plugin.setupMethodChannel(registrar.messenger(), registrar.context().getContentResolver());
}

/** Do not allow direct instantiation. */
private DeviceInfoPlugin(Context context) {
this.context = context;
@Override
public void onAttachedToEngine(FlutterPlugin.FlutterPluginBinding binding) {
setupMethodChannel(
binding.getFlutterEngine().getDartExecutor(),
binding.getApplicationContext().getContentResolver());
}

@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getAndroidDeviceInfo")) {
Map<String, Object> build = new HashMap<>();
build.put("board", Build.BOARD);
build.put("bootloader", Build.BOOTLOADER);
build.put("brand", Build.BRAND);
build.put("device", Build.DEVICE);
build.put("display", Build.DISPLAY);
build.put("fingerprint", Build.FINGERPRINT);
build.put("hardware", Build.HARDWARE);
build.put("host", Build.HOST);
build.put("id", Build.ID);
build.put("manufacturer", Build.MANUFACTURER);
build.put("model", Build.MODEL);
build.put("product", Build.PRODUCT);
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
build.put("supported32BitAbis", Arrays.asList(Build.SUPPORTED_32_BIT_ABIS));
build.put("supported64BitAbis", Arrays.asList(Build.SUPPORTED_64_BIT_ABIS));
build.put("supportedAbis", Arrays.asList(Build.SUPPORTED_ABIS));
} else {
build.put("supported32BitAbis", Arrays.asList(EMPTY_STRING_LIST));
build.put("supported64BitAbis", Arrays.asList(EMPTY_STRING_LIST));
build.put("supportedAbis", Arrays.asList(EMPTY_STRING_LIST));
}
build.put("tags", Build.TAGS);
build.put("type", Build.TYPE);
build.put("isPhysicalDevice", !isEmulator());
build.put("androidId", getAndroidId());

Map<String, Object> version = new HashMap<>();
if (VERSION.SDK_INT >= VERSION_CODES.M) {
version.put("baseOS", VERSION.BASE_OS);
version.put("previewSdkInt", VERSION.PREVIEW_SDK_INT);
version.put("securityPatch", VERSION.SECURITY_PATCH);
}
version.put("codename", VERSION.CODENAME);
version.put("incremental", VERSION.INCREMENTAL);
version.put("release", VERSION.RELEASE);
version.put("sdkInt", VERSION.SDK_INT);
build.put("version", version);

result.success(build);
} else {
result.notImplemented();
}
public void onDetachedFromEngine(FlutterPlugin.FlutterPluginBinding binding) {
tearDownChannel();
}

/**
* 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
* reset will also result in a value change.
*
* @return The android ID
*/
@SuppressLint("HardwareIds")
private String getAndroidId() {
return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
private void setupMethodChannel(BinaryMessenger messenger, ContentResolver contentResolver) {
channel = new MethodChannel(messenger, "plugins.flutter.io/device_info");
final MethodCallHandlerImpl handler = new MethodCallHandlerImpl(contentResolver);
channel.setMethodCallHandler(handler);
}

/**
* A simple emulator-detection based on the flutter tools detection logic and a couple of legacy
* detection systems
*/
private boolean isEmulator() {
return (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
|| Build.FINGERPRINT.startsWith("generic")
|| Build.FINGERPRINT.startsWith("unknown")
|| Build.HARDWARE.contains("goldfish")
|| Build.HARDWARE.contains("ranchu")
|| Build.MODEL.contains("google_sdk")
|| Build.MODEL.contains("Emulator")
|| Build.MODEL.contains("Android SDK built for x86")
|| Build.MANUFACTURER.contains("Genymotion")
|| Build.PRODUCT.contains("sdk_google")
|| Build.PRODUCT.contains("google_sdk")
|| Build.PRODUCT.contains("sdk")
|| Build.PRODUCT.contains("sdk_x86")
|| Build.PRODUCT.contains("vbox86p")
|| Build.PRODUCT.contains("emulator")
|| Build.PRODUCT.contains("simulator");
private void tearDownChannel() {
channel.setMethodCallHandler(null);
channel = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// 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 io.flutter.plugins.deviceinfo;

import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.os.Build;
import android.provider.Settings;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
* The implementation of {@link MethodChannel.MethodCallHandler} for the plugin. Responsible for
* receiving method calls from method channel.
*/
class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {

private ContentResolver contentResolver;

/** 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) {
this.contentResolver = contentResolver;
}

@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
if (call.method.equals("getAndroidDeviceInfo")) {
Map<String, Object> build = new HashMap<>();
build.put("board", Build.BOARD);
build.put("bootloader", Build.BOOTLOADER);
build.put("brand", Build.BRAND);
build.put("device", Build.DEVICE);
build.put("display", Build.DISPLAY);
build.put("fingerprint", Build.FINGERPRINT);
build.put("hardware", Build.HARDWARE);
build.put("host", Build.HOST);
build.put("id", Build.ID);
build.put("manufacturer", Build.MANUFACTURER);
build.put("model", Build.MODEL);
build.put("product", Build.PRODUCT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
build.put("supported32BitAbis", Arrays.asList(Build.SUPPORTED_32_BIT_ABIS));
build.put("supported64BitAbis", Arrays.asList(Build.SUPPORTED_64_BIT_ABIS));
build.put("supportedAbis", Arrays.asList(Build.SUPPORTED_ABIS));
} else {
build.put("supported32BitAbis", Arrays.asList(EMPTY_STRING_LIST));
build.put("supported64BitAbis", Arrays.asList(EMPTY_STRING_LIST));
build.put("supportedAbis", Arrays.asList(EMPTY_STRING_LIST));
}
build.put("tags", Build.TAGS);
build.put("type", Build.TYPE);
build.put("isPhysicalDevice", !isEmulator());
build.put("androidId", getAndroidId());

Map<String, Object> version = new HashMap<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
version.put("baseOS", Build.VERSION.BASE_OS);
version.put("previewSdkInt", Build.VERSION.PREVIEW_SDK_INT);
version.put("securityPatch", Build.VERSION.SECURITY_PATCH);
}
version.put("codename", Build.VERSION.CODENAME);
version.put("incremental", Build.VERSION.INCREMENTAL);
version.put("release", Build.VERSION.RELEASE);
version.put("sdkInt", Build.VERSION.SDK_INT);
build.put("version", version);

result.success(build);
} else {
result.notImplemented();
}
}

/**
* 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
* reset will also result in a value change.
*
* @return The android ID
*/
@SuppressLint("HardwareIds")
private String getAndroidId() {
return Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID);
}

/**
* A simple emulator-detection based on the flutter tools detection logic and a couple of legacy
* detection systems
*/
private boolean isEmulator() {
return (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
|| Build.FINGERPRINT.startsWith("generic")
|| Build.FINGERPRINT.startsWith("unknown")
|| Build.HARDWARE.contains("goldfish")
|| Build.HARDWARE.contains("ranchu")
|| Build.MODEL.contains("google_sdk")
|| Build.MODEL.contains("Emulator")
|| Build.MODEL.contains("Android SDK built for x86")
|| Build.MANUFACTURER.contains("Genymotion")
|| Build.PRODUCT.contains("sdk_google")
|| Build.PRODUCT.contains("google_sdk")
|| Build.PRODUCT.contains("sdk")
|| Build.PRODUCT.contains("sdk_x86")
|| Build.PRODUCT.contains("vbox86p")
|| Build.PRODUCT.contains("emulator")
|| Build.PRODUCT.contains("simulator");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@
<uses-permission android:name="android.permission.INTERNET"/>

<application android:name="io.flutter.app.FlutterApplication" android:label="device_info_example" android:icon="@mipmap/ic_launcher">
<activity android:name="io.flutter.plugins.deviceinfoexample.MainActivity"
<activity android:name=".EmbeddingV1Activity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
android:hardwareAccelerated="true"
android:exported="true"
android:windowSoftInputMode="adjustResize">
</activity>
<activity android:name=".MainActivity"
android:theme="@android:style/Theme.Black.NoTitleBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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 io.flutter.plugins.deviceinfoexample;

import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class EmbeddingV1Activity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.flutter.plugins.deviceinfoexample;

import androidx.test.rule.ActivityTestRule;
import dev.flutter.plugins.e2e.FlutterRunner;
import org.junit.Rule;
import org.junit.runner.RunWith;

@RunWith(FlutterRunner.class)
public class EmbeddingV1ActivityTest {
@Rule
public ActivityTestRule<EmbeddingV1Activity> rule =
new ActivityTestRule<>(EmbeddingV1Activity.class);
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Copyright 2019 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 io.flutter.plugins.deviceinfoexample;

import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.deviceinfo.DeviceInfoPlugin;

public class MainActivity extends FlutterActivity {

// TODO(cyanglaz): Remove this once v2 of GeneratedPluginRegistrant rolls to stable.
// https://github.com/flutter/flutter/issues/42694
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
public void configureFlutterEngine(FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
flutterEngine.getPlugins().add(new DeviceInfoPlugin());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2019 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 io.flutter.plugins.deviceinfoexample;

import androidx.test.rule.ActivityTestRule;
import dev.flutter.plugins.e2e.FlutterRunner;
import org.junit.Rule;
import org.junit.runner.RunWith;

@RunWith(FlutterRunner.class)
public class MainActivityTest {
@Rule public ActivityTestRule<MainActivity> rule = new ActivityTestRule<>(MainActivity.class);
}
Loading

0 comments on commit a3bbef7

Please sign in to comment.