diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 6f06235bebb23..e117640bc9c5b 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -89,6 +89,23 @@ shared_library("flutter_shell_native") { ldflags = [ "-Wl,--version-script=" + rebase_path("android_exports.lst") ] } +action("gen_android_build_config_java") { + script = "$flutter_root/tools/gen_android_buildconfig.py" + + build_config_java = "$target_gen_dir/io/flutter/BuildConfig.java" + + outputs = [ + build_config_java, + ] + + args = [ + "--out", + rebase_path(build_config_java), + "--runtime-mode", + flutter_runtime_mode, + ] +} + action("flutter_shell_java") { script = "//build/android/gyp/javac.py" depfile = "$target_gen_dir/$target_name.d" @@ -173,6 +190,8 @@ action("flutter_shell_java") { "io/flutter/view/VsyncWaiter.java", ] + sources += get_target_outputs(":gen_android_build_config_java") + sources += [ "$flutter_root/third_party/bsdiff/io/flutter/util/BSDiff.java" ] android_support_jars = [ @@ -208,6 +227,10 @@ action("flutter_shell_java") { ] args += rebase_path(sources, root_build_dir) + + deps = [ + ":gen_android_build_config_java", + ] } action("icudtl_object") { diff --git a/shell/platform/android/io/flutter/plugin/common/BasicMessageChannel.java b/shell/platform/android/io/flutter/plugin/common/BasicMessageChannel.java index 74a193880eb31..35200a22ed1c5 100644 --- a/shell/platform/android/io/flutter/plugin/common/BasicMessageChannel.java +++ b/shell/platform/android/io/flutter/plugin/common/BasicMessageChannel.java @@ -7,6 +7,7 @@ import android.util.Log; import java.nio.ByteBuffer; +import io.flutter.BuildConfig; import io.flutter.plugin.common.BinaryMessenger.BinaryReply; import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler; @@ -39,9 +40,17 @@ public final class BasicMessageChannel { * @param codec a {@link MessageCodec}. */ public BasicMessageChannel(BinaryMessenger messenger, String name, MessageCodec codec) { - assert messenger != null; - assert name != null; - assert codec != null; + if (BuildConfig.DEBUG) { + if (messenger == null) { + throw new AssertionError("Parameter messenger must not be null."); + } + if (name == null) { + throw new AssertionError("Parameter name must not be null."); + } + if (codec == null) { + throw new AssertionError("Parameter codec must not be null."); + } + } this.messenger = messenger; this.name = name; this.codec = codec; diff --git a/shell/platform/android/io/flutter/plugin/common/EventChannel.java b/shell/platform/android/io/flutter/plugin/common/EventChannel.java index 57443a0aa1816..72fd371296cd0 100644 --- a/shell/platform/android/io/flutter/plugin/common/EventChannel.java +++ b/shell/platform/android/io/flutter/plugin/common/EventChannel.java @@ -5,6 +5,8 @@ package io.flutter.plugin.common; import android.util.Log; + +import io.flutter.BuildConfig; import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler; import io.flutter.plugin.common.BinaryMessenger.BinaryReply; @@ -55,9 +57,17 @@ public EventChannel(BinaryMessenger messenger, String name) { * @param codec a {@link MessageCodec}. */ public EventChannel(BinaryMessenger messenger, String name, MethodCodec codec) { - assert messenger != null; - assert name != null; - assert codec != null; + if (BuildConfig.DEBUG) { + if (messenger == null) { + throw new AssertionError("Parameter messenger must not be null."); + } + if (name == null) { + throw new AssertionError("Parameter name must not be null."); + } + if (codec == null) { + throw new AssertionError("Parameter codec must not be null."); + } + } this.messenger = messenger; this.name = name; this.codec = codec; diff --git a/shell/platform/android/io/flutter/plugin/common/FlutterException.java b/shell/platform/android/io/flutter/plugin/common/FlutterException.java index 61eb12c13c11b..5b643c7561e21 100644 --- a/shell/platform/android/io/flutter/plugin/common/FlutterException.java +++ b/shell/platform/android/io/flutter/plugin/common/FlutterException.java @@ -4,6 +4,8 @@ package io.flutter.plugin.common; +import io.flutter.BuildConfig; + /** * Thrown to indicate that a Flutter method invocation failed on the Flutter side. */ @@ -13,7 +15,9 @@ public class FlutterException extends RuntimeException { FlutterException(String code, String message, Object details) { super(message); - assert code != null; + if (BuildConfig.DEBUG && code == null) { + throw new AssertionError("Parameter code must not be null."); + } this.code = code; this.details = details; } diff --git a/shell/platform/android/io/flutter/plugin/common/MethodCall.java b/shell/platform/android/io/flutter/plugin/common/MethodCall.java index 9206ba5ecee25..376576d181f3c 100644 --- a/shell/platform/android/io/flutter/plugin/common/MethodCall.java +++ b/shell/platform/android/io/flutter/plugin/common/MethodCall.java @@ -8,6 +8,8 @@ import java.util.Map; import org.json.JSONObject; +import io.flutter.BuildConfig; + /** * Command object representing a method call on a {@link MethodChannel}. */ @@ -33,7 +35,9 @@ public final class MethodCall { * @param arguments the arguments, a value supported by the channel's message codec. */ public MethodCall(String method, Object arguments) { - assert method != null; + if (BuildConfig.DEBUG && method == null) { + throw new AssertionError("Parameter method must not be null."); + } this.method = method; this.arguments = arguments; } diff --git a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java index 9f725e7bdf545..9ffcdaa2074a7 100644 --- a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java +++ b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java @@ -7,8 +7,11 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; + +import io.flutter.BuildConfig; import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler; import io.flutter.plugin.common.BinaryMessenger.BinaryReply; + import java.nio.ByteBuffer; /** @@ -53,9 +56,17 @@ public MethodChannel(BinaryMessenger messenger, String name) { * @param codec a {@link MessageCodec}. */ public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) { - assert messenger != null; - assert name != null; - assert codec != null; + if (BuildConfig.DEBUG) { + if (messenger == null) { + throw new AssertionError("Parameter messenger must not be null."); + } + if (name == null) { + throw new AssertionError("Parameter name must not be null."); + } + if (codec == null) { + throw new AssertionError("Parameter codec must not be null."); + } + } this.messenger = messenger; this.name = name; this.codec = codec; diff --git a/shell/platform/android/io/flutter/plugin/common/StandardMessageCodec.java b/shell/platform/android/io/flutter/plugin/common/StandardMessageCodec.java index c22ea07a9aa87..dfe11e86c49ae 100644 --- a/shell/platform/android/io/flutter/plugin/common/StandardMessageCodec.java +++ b/shell/platform/android/io/flutter/plugin/common/StandardMessageCodec.java @@ -4,6 +4,8 @@ package io.flutter.plugin.common; +import io.flutter.BuildConfig; + import java.io.ByteArrayOutputStream; import java.math.BigInteger; import java.nio.ByteBuffer; @@ -15,8 +17,6 @@ import java.util.Map; import java.util.Map.Entry; -import android.util.Log; - /** * MessageCodec using the Flutter standard binary encoding. * @@ -109,7 +109,9 @@ public Object decodeMessage(ByteBuffer message) { * Uses an expanding code of 1 to 5 bytes to optimize for small values. */ protected static final void writeSize(ByteArrayOutputStream stream, int value) { - assert 0 <= value; + if (BuildConfig.DEBUG && 0 > value) { + throw new AssertionError("Attempted to write a negative size."); + } if (value < 254) { stream.write(value); } else if (value <= 0xffff) { diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index a589f54d4ca5d..ebd9552b43fc1 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -26,6 +26,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeProvider; +import io.flutter.BuildConfig; import io.flutter.embedding.engine.systemchannels.AccessibilityChannel; import io.flutter.plugin.platform.PlatformViewsAccessibilityDelegate; import io.flutter.util.Predicate; @@ -594,10 +595,14 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { } if (semanticsNode.parent != null) { - assert semanticsNode.id > ROOT_NODE_ID; + if (BuildConfig.DEBUG && semanticsNode.id <= ROOT_NODE_ID) { + throw new AssertionError("Semantics node id is not > ROOT_NODE_ID."); + } result.setParent(rootAccessibilityView, semanticsNode.parent.id); } else { - assert semanticsNode.id == ROOT_NODE_ID; + if (BuildConfig.DEBUG && semanticsNode.id != ROOT_NODE_ID) { + throw new AssertionError("Semantics node id does not equal ROOT_NODE_ID."); + } result.setParent(rootAccessibilityView); } @@ -706,7 +711,9 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { boolean hasCheckedState = semanticsNode.hasFlag(Flag.HAS_CHECKED_STATE); boolean hasToggledState = semanticsNode.hasFlag(Flag.HAS_TOGGLED_STATE); - assert !(hasCheckedState && hasToggledState); + if (BuildConfig.DEBUG && (hasCheckedState && hasToggledState)) { + throw new AssertionError("Expected semanticsNode to have checked state and toggled state."); + } result.setCheckable(hasCheckedState || hasToggledState); if (hasCheckedState) { result.setChecked(semanticsNode.hasFlag(Flag.IS_CHECKED)); @@ -1055,7 +1062,9 @@ public AccessibilityNodeInfo findFocus(int focus) { * Returns the {@link SemanticsNode} at the root of Flutter's semantics tree. */ private SemanticsNode getRootSemanticsNode() { - assert flutterSemanticsTree.containsKey(0); + if (BuildConfig.DEBUG && !flutterSemanticsTree.containsKey(0)) { + throw new AssertionError("Attempted to getRootSemanticsNode without a root sematnics node."); + } return flutterSemanticsTree.get(0); } @@ -1317,8 +1326,14 @@ void updateSemantics(@NonNull ByteBuffer buffer, @NonNull String[] strings) { visibleChildren += 1; } } - assert(object.scrollIndex + visibleChildren <= object.scrollChildren); - assert(!object.childrenInHitTestOrder.get(object.scrollIndex).hasFlag(Flag.IS_HIDDEN)); + if (BuildConfig.DEBUG) { + if (object.scrollIndex + visibleChildren > object.scrollChildren) { + throw new AssertionError("Scroll index is out of bounds."); + } + if (object.childrenInHitTestOrder.get(object.scrollIndex).hasFlag(Flag.IS_HIDDEN)) { + throw new AssertionError("Attempted to move Accessibility Focus to hidden child."); + } + } // The setToIndex should be the index of the last visible child. Because we counted all // children, including the first index we need to subtract one. // @@ -1470,7 +1485,9 @@ private void createAndSendWindowChangeEvent(@NonNull SemanticsNode route) { * invoked to create an {@link AccessibilityEvent} for the {@link #rootAccessibilityView}. */ private AccessibilityEvent obtainAccessibilityEvent(int virtualViewId, int eventType) { - assert virtualViewId != ROOT_NODE_ID; + if (BuildConfig.DEBUG && virtualViewId == ROOT_NODE_ID) { + throw new AssertionError("VirtualView node must not be the root node."); + } AccessibilityEvent event = AccessibilityEvent.obtain(eventType); event.setPackageName(rootAccessibilityView.getContext().getPackageName()); event.setSource(rootAccessibilityView, virtualViewId); @@ -1482,8 +1499,14 @@ private AccessibilityEvent obtainAccessibilityEvent(int virtualViewId, int event * semantics tree. */ private void willRemoveSemanticsNode(SemanticsNode semanticsNodeToBeRemoved) { - assert flutterSemanticsTree.containsKey(semanticsNodeToBeRemoved.id); - assert flutterSemanticsTree.get(semanticsNodeToBeRemoved.id) == semanticsNodeToBeRemoved; + if (BuildConfig.DEBUG) { + if (!flutterSemanticsTree.containsKey(semanticsNodeToBeRemoved.id)) { + throw new AssertionError("Attempted to remove a node that is not in the tree."); + } + if (flutterSemanticsTree.get(semanticsNodeToBeRemoved.id) != semanticsNodeToBeRemoved) { + throw new AssertionError("Flutter semantics tree failed to get expected node when searching by id."); + } + } // TODO(mattcarroll): should parent be set to "null" here? Changing the parent seems like the // behavior of a method called "removeSemanticsNode()". The same is true // for null'ing accessibilityFocusedSemanticsNode, inputFocusedSemanticsNode, @@ -1779,7 +1802,9 @@ private boolean hasFlag(@NonNull Flag flag) { } private boolean hadFlag(@NonNull Flag flag) { - assert hadPreviousConfig; + if (BuildConfig.DEBUG && !hadPreviousConfig) { + throw new AssertionError("Attempted to check hadFlag but had no previous config."); + } return (previousFlags & flag.value) != 0; } @@ -1909,7 +1934,9 @@ private void updateWith(@NonNull ByteBuffer buffer, @NonNull String[] strings) { } else { // If we receive a different overrideId it means that we were passed // a standard action to override that we don't yet support. - assert action.overrideId == -1; + if (BuildConfig.DEBUG && action.overrideId != -1) { + throw new AssertionError("Expected action.overrideId to be -1."); + } customAccessibilityActions.add(action); } customAccessibilityActions.add(action); @@ -1931,7 +1958,9 @@ private void ensureInverseTransform() { } private Rect getGlobalRect() { - assert !globalGeometryDirty; + if (BuildConfig.DEBUG && globalGeometryDirty) { + throw new AssertionError("Attempted to getGlobalRect with a dirty geometry."); + } return globalRect; } @@ -2052,8 +2081,14 @@ private void updateRecursively(float[] ancestorTransform, Set vis globalGeometryDirty = false; } - assert globalTransform != null; - assert globalRect != null; + if (BuildConfig.DEBUG) { + if (globalTransform == null) { + throw new AssertionError("Expected globalTransform to not be null."); + } + if (globalRect == null) { + throw new AssertionError("Expected globalRect to not be null."); + } + } if (childrenInTraversalOrder != null) { for (int i = 0; i < childrenInTraversalOrder.size(); ++i) { diff --git a/shell/platform/android/io/flutter/view/ResourceExtractor.java b/shell/platform/android/io/flutter/view/ResourceExtractor.java index 424ace596be93..e7ff841148dd1 100644 --- a/shell/platform/android/io/flutter/view/ResourceExtractor.java +++ b/shell/platform/android/io/flutter/view/ResourceExtractor.java @@ -13,8 +13,11 @@ import android.os.AsyncTask; import android.os.Build; import android.util.Log; + +import io.flutter.BuildConfig; import io.flutter.util.BSDiff; import io.flutter.util.PathUtils; + import org.json.JSONObject; import java.io.*; @@ -95,7 +98,9 @@ ResourceExtractor addResources(Collection resources) { } ResourceExtractor start() { - assert mExtractTask == null; + if (BuildConfig.DEBUG && mExtractTask != null) { + throw new AssertionError("Attempted to start resource extraction while another extraction was in progress."); + } mExtractTask = new ExtractTask(); mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); return this; diff --git a/tools/android_lint/baseline.xml b/tools/android_lint/baseline.xml index bc6c463610096..15319be270cfb 100644 --- a/tools/android_lint/baseline.xml +++ b/tools/android_lint/baseline.xml @@ -1,160 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -228,7 +74,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -254,28 +100,6 @@ column="82"/> - - - - - - - - @@ -305,18 +129,7 @@ errorLine2=" ~~~~~~~~~~~"> - - - - @@ -327,7 +140,7 @@ errorLine2=" ^"> @@ -360,76 +173,10 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - - - - - - - - - - - - - - - - - - - - - - - - @@ -448,7 +195,7 @@ errorLine2=" ~~~~~~~~~~~~~~~"> @@ -470,7 +217,7 @@ errorLine2=" ~~~~~~~~~~~~~~~"> @@ -481,7 +228,7 @@ errorLine2=" ~~~~~~~~~~~~"> @@ -492,7 +239,7 @@ errorLine2=" ~~~~~~~~~~~~"> diff --git a/tools/android_lint/project.xml b/tools/android_lint/project.xml index 6d8fffe439f3e..ac975123ca266 100644 --- a/tools/android_lint/project.xml +++ b/tools/android_lint/project.xml @@ -13,6 +13,13 @@ + + + + + + + @@ -29,13 +36,6 @@ - - - - - - - @@ -43,7 +43,9 @@ + + @@ -66,7 +68,6 @@ - @@ -77,5 +78,6 @@ + diff --git a/tools/gen_android_buildconfig.py b/tools/gen_android_buildconfig.py new file mode 100644 index 0000000000000..648ec8a59293a --- /dev/null +++ b/tools/gen_android_buildconfig.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# Copyright 2013 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. + +import argparse +import os +import sys + +BUILD_CONFIG_TEMPLATE = """ +// Copyright 2013 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. + + +// THIS FILE IS AUTO_GENERATED +// DO NOT EDIT THE VALUES HERE - SEE $flutter_root/tools/gen_android_buildconfig.py +package io.flutter; + +public final class BuildConfig {{ + private BuildConfig() {{}} + + public final static boolean DEBUG = {0}; + public final static boolean PROFILE = {1}; + public final static boolean RELEASE = {2}; +}} +""" + +def main(): + parser = argparse.ArgumentParser(description='Generate BuildConfig.java for Android') + parser.add_argument('--runtime-mode', type=str, required=True) + parser.add_argument('--out', type=str, required=True) + + args = parser.parse_args() + + release ='release' in args.runtime_mode.lower() + profile = not release and 'profile' in args.runtime_mode.lower() + debug = not release and not profile and 'debug' in args.runtime_mode.lower() + assert debug or profile or release + + with open(os.path.abspath(args.out), 'w+') as output_file: + output_file.write(BUILD_CONFIG_TEMPLATE.format(str(debug).lower(), str(profile).lower(), str(release).lower())) + +if __name__ == '__main__': + sys.exit(main())