| // Copyright 2014 The Flutter 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.integration.platformviews; |
| |
| import android.Manifest; |
| import android.content.pm.PackageManager; |
| import android.os.Build; |
| import android.os.Bundle; |
| import android.view.MotionEvent; |
| import android.view.View; |
| import android.view.ViewGroup; |
| |
| import java.lang.StringBuilder; |
| import java.util.HashMap; |
| |
| import io.flutter.embedding.android.FlutterActivity; |
| import io.flutter.embedding.android.FlutterImageView; |
| import io.flutter.embedding.android.FlutterSurfaceView; |
| import io.flutter.embedding.android.FlutterTextureView; |
| import io.flutter.embedding.android.FlutterView; |
| import io.flutter.embedding.engine.dart.DartExecutor; |
| import io.flutter.embedding.engine.FlutterEngine; |
| import io.flutter.plugin.common.MethodCall; |
| import io.flutter.plugin.common.MethodChannel; |
| import io.flutter.plugins.GeneratedPluginRegistrant; |
| |
| public class MainActivity extends FlutterActivity implements MethodChannel.MethodCallHandler { |
| final static int STORAGE_PERMISSION_CODE = 1; |
| |
| MethodChannel mMethodChannel; |
| |
| // The method result to complete with the Android permission request result. |
| // This is null when not waiting for the Android permission request; |
| private MethodChannel.Result permissionResult; |
| |
| private View getFlutterView() { |
| return findViewById(FLUTTER_VIEW_ID); |
| } |
| |
| private String getViewName(View view) { |
| if (view instanceof FlutterImageView) { |
| return "FlutterImageView"; |
| } |
| if (view instanceof FlutterSurfaceView) { |
| return "FlutterSurfaceView"; |
| } |
| if (view instanceof FlutterTextureView) { |
| return "FlutterTextureView"; |
| } |
| if (view instanceof FlutterView) { |
| return "FlutterView"; |
| } |
| if (view instanceof ViewGroup) { |
| return "ViewGroup"; |
| } |
| return "View"; |
| } |
| |
| private void recurseViewHierarchy(View current, String padding, StringBuilder builder) { |
| if (current.getVisibility() != View.VISIBLE || current.getAlpha() == 0) { |
| return; |
| } |
| String name = getViewName(current); |
| builder.append(padding); |
| builder.append("|-"); |
| builder.append(name); |
| builder.append("\n"); |
| |
| if (current instanceof ViewGroup) { |
| ViewGroup viewGroup = (ViewGroup) current; |
| for (int index = 0; index < viewGroup.getChildCount(); index++) { |
| recurseViewHierarchy(viewGroup.getChildAt(index), padding + " ", builder); |
| } |
| } |
| } |
| |
| /** |
| * Serializes the view hierarchy, so it can be sent to Dart over the method channel. |
| * |
| * Notation: |
| * |- <view-name> |
| * |- ... child view ordered by z order. |
| * |
| * Example output: |
| * |- FlutterView |
| * |- FlutterImageView |
| * |- ViewGroup |
| * |- View |
| */ |
| private String getSerializedViewHierarchy() { |
| View root = getFlutterView(); |
| StringBuilder builder = new StringBuilder(); |
| recurseViewHierarchy(root, "", builder); |
| return builder.toString(); |
| } |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| } |
| |
| @Override |
| public void configureFlutterEngine(FlutterEngine flutterEngine) { |
| DartExecutor executor = flutterEngine.getDartExecutor(); |
| flutterEngine |
| .getPlatformViewsController() |
| .getRegistry() |
| .registerViewFactory("simple_view", new SimpleViewFactory(executor)); |
| mMethodChannel = new MethodChannel(executor, "android_views_integration"); |
| mMethodChannel.setMethodCallHandler(this); |
| GeneratedPluginRegistrant.registerWith(flutterEngine); |
| } |
| |
| @Override |
| public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) { |
| switch(methodCall.method) { |
| case "getStoragePermission": |
| if (permissionResult != null) { |
| result.error("error", "already waiting for permissions", null); |
| return; |
| } |
| permissionResult = result; |
| getExternalStoragePermissions(); |
| return; |
| case "synthesizeEvent": |
| synthesizeEvent(methodCall); |
| result.success(null); |
| return; |
| case "getViewHierarchy": |
| String viewHierarchy = getSerializedViewHierarchy(); |
| result.success(viewHierarchy); |
| return; |
| } |
| result.notImplemented(); |
| } |
| |
| @SuppressWarnings("unchecked") |
| public void synthesizeEvent(MethodCall methodCall) { |
| MotionEvent event = MotionEventCodec.decode((HashMap<String, Object>) methodCall.arguments()); |
| getFlutterView().dispatchTouchEvent(event); |
| // TODO(egarciad): This can be cleaned up. |
| mMethodChannel.invokeMethod("onTouch", MotionEventCodec.encode(event)); |
| } |
| |
| @Override |
| public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { |
| if (requestCode != STORAGE_PERMISSION_CODE || permissionResult == null) |
| return; |
| boolean permisisonGranted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED; |
| sendPermissionResult(permisisonGranted); |
| } |
| |
| private void getExternalStoragePermissions() { |
| if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) |
| return; |
| |
| if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) |
| == PackageManager.PERMISSION_GRANTED) { |
| sendPermissionResult(true); |
| return; |
| } |
| |
| requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE); |
| } |
| |
| private void sendPermissionResult(boolean result) { |
| if (permissionResult == null) |
| return; |
| permissionResult.success(result); |
| permissionResult = null; |
| } |
| } |