From cacbdf5313eaacd4e3b965a15d5e896b32334298 Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Tue, 5 Mar 2019 14:15:22 -0800 Subject: [PATCH 1/5] Guard against NewAPI failures --- .../engine/android/FlutterSurfaceView.java | 3 +- .../engine/android/FlutterTextureView.java | 3 +- .../embedding/engine/android/FlutterView.java | 3 + .../plugin/platform/PlatformPlugin.java | 15 +- .../io/flutter/view/AccessibilityBridge.java | 31 +- .../android/io/flutter/view/FlutterView.java | 10 +- .../io/flutter/view/ResourceExtractor.java | 61 +- .../io/flutter/view/ResourceUpdater.java | 32 +- tools/android_lint/baseline.xml | 556 +++--------------- tools/android_lint/project.xml | 150 ++--- 10 files changed, 260 insertions(+), 604 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/android/FlutterSurfaceView.java b/shell/platform/android/io/flutter/embedding/engine/android/FlutterSurfaceView.java index dc52f9e6d46f9..c565bf26f786e 100644 --- a/shell/platform/android/io/flutter/embedding/engine/android/FlutterSurfaceView.java +++ b/shell/platform/android/io/flutter/embedding/engine/android/FlutterSurfaceView.java @@ -11,6 +11,7 @@ import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; +import android.support.v4.view.ViewCompat; import java.nio.ByteBuffer; @@ -134,7 +135,7 @@ public void detachFromRenderer() { if (flutterRenderer != null) { // If we're attached to an Android window then we were rendering a Flutter UI. Now that // this FlutterSurfaceView is detached from the FlutterRenderer, we need to stop rendering. - if (isAttachedToWindow()) { + if (ViewCompat.isAttachedToWindow(this)) { disconnectSurfaceFromRenderer(); } diff --git a/shell/platform/android/io/flutter/embedding/engine/android/FlutterTextureView.java b/shell/platform/android/io/flutter/embedding/engine/android/FlutterTextureView.java index c12c2fa4274fc..4cf685238c98b 100644 --- a/shell/platform/android/io/flutter/embedding/engine/android/FlutterTextureView.java +++ b/shell/platform/android/io/flutter/embedding/engine/android/FlutterTextureView.java @@ -12,6 +12,7 @@ import android.util.Log; import android.view.Surface; import android.view.TextureView; +import android.support.v4.view.ViewCompat; import java.nio.ByteBuffer; @@ -145,7 +146,7 @@ public void detachFromRenderer() { if (flutterRenderer != null) { // If we're attached to an Android window then we were rendering a Flutter UI. Now that // this FlutterTextureView is detached from the FlutterRenderer, we need to stop rendering. - if (isAttachedToWindow()) { + if (ViewCompat.isAttachedToWindow(this)) { disconnectSurfaceFromRenderer(); } diff --git a/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java index c7d86cbf2e6ab..e963bf36fe037 100644 --- a/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java @@ -180,6 +180,9 @@ protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) */ @Override public final WindowInsets onApplyWindowInsets(WindowInsets insets) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH) { + return null; + } WindowInsets newInsets = super.onApplyWindowInsets(insets); // Status bar (top) and left/right system insets should partially obscure the content (padding). diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java index e9d44001ef0f5..e1e5f9f9cdbaa 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java @@ -132,12 +132,15 @@ private void setSystemChromeApplicationSwitcherDescription(PlatformChannel.AppSw return; } - @SuppressWarnings("deprecation") - TaskDescription taskDescription = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) - ? new TaskDescription(description.label, 0, description.color) - : new TaskDescription(description.label, null, description.color); - - activity.setTaskDescription(taskDescription); + // Linter refuses to believe we're only executing this code in API 28 unless we use distinct if blocks and + // hardcode the API 28 constant. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P && Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + activity.setTaskDescription(new TaskDescription(description.label)); + } + if (Build.VERSION.SDK_INT >= 28) { + TaskDescription taskDescription = new TaskDescription(description.label, 0, description.color); + activity.setTaskDescription(taskDescription); + } } private void setSystemChromeEnabledSystemUIOverlays(List overlaysToShow) { diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index ac5e2f8f3d995..5547f991bd5cc 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -233,17 +233,19 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { } result.setMovementGranularities(granularities); } - if (object.hasAction(Action.SET_SELECTION)) { - result.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); - } - if (object.hasAction(Action.COPY)) { - result.addAction(AccessibilityNodeInfo.ACTION_COPY); - } - if (object.hasAction(Action.CUT)) { - result.addAction(AccessibilityNodeInfo.ACTION_CUT); - } - if (object.hasAction(Action.PASTE)) { - result.addAction(AccessibilityNodeInfo.ACTION_PASTE); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) { + if (object.hasAction(Action.SET_SELECTION)) { + result.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); + } + if (object.hasAction(Action.COPY)) { + result.addAction(AccessibilityNodeInfo.ACTION_COPY); + } + if (object.hasAction(Action.CUT)) { + result.addAction(AccessibilityNodeInfo.ACTION_CUT); + } + if (object.hasAction(Action.PASTE)) { + result.addAction(AccessibilityNodeInfo.ACTION_PASTE); + } } if (object.hasFlag(Flag.IS_BUTTON)) { @@ -316,7 +318,7 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { // GridView. Right now, we're only supporting ListViews and only if they have scroll children. if (object.hasFlag(Flag.HAS_IMPLICIT_SCROLLING)) { if (object.hasAction(Action.SCROLL_LEFT) || object.hasAction(Action.SCROLL_RIGHT)) { - if (shouldSetCollectionInfo(object)) { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT && shouldSetCollectionInfo(object)) { result.setCollectionInfo(AccessibilityNodeInfo.CollectionInfo.obtain( 0, // rows object.scrollChildren, // columns @@ -325,7 +327,7 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { result.setClassName("android.widget.HorizontalScrollView"); } } else { - if (shouldSetCollectionInfo(object)) { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 && shouldSetCollectionInfo(object)) { result.setCollectionInfo(AccessibilityNodeInfo.CollectionInfo.obtain( object.scrollChildren, // rows 0, // columns @@ -504,6 +506,7 @@ public boolean performAction(int virtualViewId, int action, Bundle arguments) { case AccessibilityNodeInfo.ACTION_SET_SELECTION: { final Map selection = new HashMap<>(); final boolean hasSelection = arguments != null + && Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 && arguments.containsKey( AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT) && arguments.containsKey( @@ -557,7 +560,7 @@ boolean performCursorMoveAction( SemanticsObject object, int virtualViewId, Bundle arguments, boolean forward) { final int granularity = arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); - final boolean extendSelection = arguments.getBoolean( + final boolean extendSelection = Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 && arguments.getBoolean( AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); switch (granularity) { case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index 8df25207422ba..adeaf1fad8be0 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -655,6 +655,9 @@ else if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { // but when the inset is just the hidden nav bar, we want to provide a zero inset so the space // can be used. int calculateBottomKeyboardInset(WindowInsets insets) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH) { + return 0; + } int screenHeight = getRootView().getHeight(); // Magic number due to this being a heuristic. This should be replaced, but we have not // found a clean way to do it yet (Sept. 2018) @@ -673,6 +676,9 @@ int calculateBottomKeyboardInset(WindowInsets insets) { // the wider than expected padding when the status and navigation bars are hidden. @Override public final WindowInsets onApplyWindowInsets(WindowInsets insets) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH) { + return null; + } boolean statusBarHidden = (SYSTEM_UI_FLAG_FULLSCREEN & getWindowSystemUiVisibility()) != 0; boolean navigationBarHidden = @@ -963,7 +969,7 @@ public void onChange(boolean selfChange) { @Override public void onChange(boolean selfChange, Uri uri) { - String value = Settings.Global.getString(getContext().getContentResolver(), + String value = Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT ? null : Settings.Global.getString(getContext().getContentResolver(), Settings.Global.TRANSITION_ANIMATION_SCALE); if (value != null && value.equals("0")) { mAccessibilityFeatureFlags |= AccessibilityFeature.DISABLE_ANIMATIONS.value; @@ -974,6 +980,8 @@ public void onChange(boolean selfChange, Uri uri) { } } + // This is guarded at instantiation time. + @SuppressWarnings("NewApi") class TouchExplorationListener implements AccessibilityManager.TouchExplorationStateChangeListener { @Override public void onTouchExplorationStateChanged(boolean enabled) { diff --git a/shell/platform/android/io/flutter/view/ResourceExtractor.java b/shell/platform/android/io/flutter/view/ResourceExtractor.java index 40fc75982a972..53daee001e86a 100644 --- a/shell/platform/android/io/flutter/view/ResourceExtractor.java +++ b/shell/platform/android/io/flutter/view/ResourceExtractor.java @@ -33,7 +33,8 @@ class ResourceExtractor { @SuppressWarnings("deprecation") static long getVersionCode(PackageInfo packageInfo) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + // Linter needs 28 hardcoded + if (Build.VERSION.SDK_INT >= 28) { return packageInfo.getLongVersionCode(); } else { return packageInfo.versionCode; @@ -188,9 +189,17 @@ private boolean extractAPK(File dataDir) { output.getParentFile().mkdirs(); } - try (InputStream is = manager.open(asset); - OutputStream os = new FileOutputStream(output)) { + InputStream is = manager.open(asset); + OutputStream os = new FileOutputStream(output); + try { copy(is, os); + } finally { + if (is != null) { + is.close(); + } + if (os != null) { + os.close(); + } } Log.i(TAG, "Extracted baseline resource " + resource); @@ -242,7 +251,7 @@ private boolean extractUpdate(File dataDir) { for (String asset : mResources) { String resource = null; ZipEntry entry = null; - if (asset.endsWith(".so")) { + if (asset.endsWith(".so") && Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) { // Replicate library lookup logic. for (String abi : Build.SUPPORTED_ABIS) { resource = "lib/" + abi + "/" + asset; @@ -281,8 +290,13 @@ private boolean extractUpdate(File dataDir) { try { if (entry.getName().endsWith(".bzdiff40")) { ByteArrayOutputStream diff = new ByteArrayOutputStream(); - try (InputStream is = zipFile.getInputStream(entry)) { + InputStream is = zipFile.getInputStream(entry); + try { copy(is, diff); + } finally { + if (is != null) { + is.close(); + } } ByteArrayOutputStream orig = new ByteArrayOutputStream(); @@ -297,26 +311,49 @@ private boolean extractUpdate(File dataDir) { throw new IOException("Could not find APK resource " + resource); } - try (InputStream is = apkFile.getInputStream(origEntry)) { - copy(is, orig); + InputStream apkInputStream = apkFile.getInputStream(origEntry); + try { + copy(apkInputStream, orig); + } finally { + if (apkInputStream != null) { + apkInputStream.close(); + } } } else { - try (InputStream is = manager.open(asset)) { - copy(is, orig); + InputStream assetInputStream = manager.open(asset); + try { + copy(assetInputStream, orig); } catch (FileNotFoundException e) { throw new IOException("Could not find APK resource " + resource); + } finally { + if (assetInputStream != null) { + assetInputStream.close(); + } } } - try (OutputStream os = new FileOutputStream(output)) { + OutputStream os = new FileOutputStream(output); + try { os.write(BSDiff.bspatch(orig.toByteArray(), diff.toByteArray())); + } finally { + if (os != null) { + os.close(); + } } } else { - try (InputStream is = zipFile.getInputStream(entry); - OutputStream os = new FileOutputStream(output)) { + InputStream is = zipFile.getInputStream(entry); + OutputStream os = new FileOutputStream(output); + try { copy(is, os); + } finally { + if (is != null) { + is.close(); + } + if (os != null) { + os.close(); + } } } diff --git a/shell/platform/android/io/flutter/view/ResourceUpdater.java b/shell/platform/android/io/flutter/view/ResourceUpdater.java index 30db64e14b1a8..9541cc8becedb 100644 --- a/shell/platform/android/io/flutter/view/ResourceUpdater.java +++ b/shell/platform/android/io/flutter/view/ResourceUpdater.java @@ -129,9 +129,11 @@ protected Void doInBackground(String... unused) { return null; } - try (InputStream input = connection.getInputStream()) { + InputStream input = connection.getInputStream(); + try { Log.i(TAG, "Downloading update " + unresolvedURL); - try (OutputStream output = new FileOutputStream(localFile)) { + OutputStream output = new FileOutputStream(localFile); + try { int count; byte[] data = new byte[1024]; while ((count = input.read(data)) != -1) { @@ -140,6 +142,14 @@ protected Void doInBackground(String... unused) { long totalMillis = new Date().getTime() - startMillis; Log.i(TAG, "Update downloaded in " + totalMillis / 100 / 10. + "s"); + } finally { + if (output != null) { + output.close(); + } + } + } finally { + if (input != null) { + input.close(); } } @@ -326,11 +336,19 @@ public boolean validateManifest(JSONObject manifest) { }; for (String fn : checksumFiles) { AssetManager manager = context.getResources().getAssets(); - try (InputStream is = manager.open(fn)) { - int count = 0; - byte[] buffer = new byte[BUFFER_SIZE]; - while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) { - checksum.update(buffer, 0, count); + InputStream is = null; + try { + try { + is = manager.open(fn); + int count = 0; + byte[] buffer = new byte[BUFFER_SIZE]; + while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) { + checksum.update(buffer, 0, count); + } + } finally { + if (is != null) { + is.close(); + } } } catch (IOException e) { // Skip missing files. diff --git a/tools/android_lint/baseline.xml b/tools/android_lint/baseline.xml index 2a81ee20380c5..71b8a3c3f4ad4 100644 --- a/tools/android_lint/baseline.xml +++ b/tools/android_lint/baseline.xml @@ -7,8 +7,8 @@ errorLine1=" assert object.id > ROOT_NODE_ID;" errorLine2=" ~~~~~~"> @@ -18,8 +18,8 @@ errorLine1=" assert object.id == ROOT_NODE_ID;" errorLine2=" ~~~~~~"> @@ -29,8 +29,8 @@ errorLine1=" assert !(hasCheckedState && hasToggledState);" errorLine2=" ~~~~~~"> @@ -40,8 +40,8 @@ errorLine1=" assert objects.containsKey(0);" errorLine2=" ~~~~~~"> @@ -51,8 +51,8 @@ errorLine1=" assert(object.scrollIndex + visibleChildren <= object.scrollChildren);" errorLine2=" ~~~~~~"> @@ -62,8 +62,8 @@ errorLine1=" assert(!object.childrenInHitTestOrder.get(object.scrollIndex).hasFlag(Flag.IS_HIDDEN));" errorLine2=" ~~~~~~"> @@ -73,8 +73,8 @@ errorLine1=" assert virtualViewId != ROOT_NODE_ID;" errorLine2=" ~~~~~~"> @@ -84,8 +84,8 @@ errorLine1=" assert objects.containsKey(object.id);" errorLine2=" ~~~~~~"> @@ -95,8 +95,8 @@ errorLine1=" assert objects.get(object.id) == object;" errorLine2=" ~~~~~~"> @@ -106,8 +106,8 @@ errorLine1=" assert hadPreviousConfig;" errorLine2=" ~~~~~~"> @@ -117,8 +117,8 @@ errorLine1=" assert action.overrideId == -1;" errorLine2=" ~~~~~~"> @@ -128,8 +128,8 @@ errorLine1=" assert !globalGeometryDirty;" errorLine2=" ~~~~~~"> @@ -139,7 +139,7 @@ errorLine1=" assert packet.position() % (POINTER_DATA_FIELD_COUNT * BYTE_PER_FIELD) == 0;" errorLine2=" ~~~~~~"> @@ -150,85 +150,19 @@ errorLine1=" assert 0 <= value;" errorLine2=" ~~~~~~"> - - - - - - - - - - - - - - - - - - - - - - - - @@ -238,40 +172,18 @@ errorLine1=" AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT));" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - - - - - - - - @@ -282,7 +194,7 @@ errorLine1=" return ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -293,7 +205,7 @@ errorLine1=" return ActivityInfo.SCREEN_ORIENTATION_FULL_USER;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -304,7 +216,7 @@ errorLine1=" view.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -315,8 +227,8 @@ errorLine1=" enabledOverlays |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -326,7 +238,7 @@ errorLine1=" return direction == View.LAYOUT_DIRECTION_LTR || direction == View.LAYOUT_DIRECTION_RTL;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -337,348 +249,18 @@ errorLine1=" return direction == View.LAYOUT_DIRECTION_LTR || direction == View.LAYOUT_DIRECTION_RTL;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -689,7 +271,7 @@ errorLine1=" <application android:label="Flutter Shell" android:name="FlutterApplication" android:debuggable="true">" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -700,7 +282,7 @@ errorLine1=" System.load(lib.getAbsolutePath());" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -711,7 +293,7 @@ errorLine1=" private static ResourceUpdater sResourceUpdater;" errorLine2=" ~~~~~~"> @@ -722,7 +304,7 @@ errorLine1=" private static ResourceExtractor sResourceExtractor;" errorLine2=" ~~~~~~"> @@ -733,7 +315,7 @@ errorLine1=" private class CleanTask extends AsyncTask<Void, Void, Void> {" errorLine2=" ~~~~~~~~~"> @@ -744,8 +326,8 @@ errorLine1=" private class ExtractTask extends AsyncTask<Void, Void, Void> {" errorLine2=" ~~~~~~~~~~~"> @@ -755,7 +337,7 @@ errorLine1=" private class DownloadTask extends AsyncTask<String, String, Void> {" errorLine2=" ~~~~~~~~~~~~"> @@ -766,8 +348,8 @@ errorLine1=" Log.i(TAG," errorLine2=" ^"> @@ -777,7 +359,7 @@ errorLine1=" Log.println(level, tag, errorMessage + details);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -788,7 +370,7 @@ errorLine1=" Log.i(TAG, "Cleaning " + mFilesToDelete.length + " resources.");" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -799,8 +381,8 @@ errorLine1=" Log.i(TAG, "Extracted baseline resource " + resource);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -810,8 +392,8 @@ errorLine1=" Log.i(TAG, "Extracted override resource " + entry.getName());" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -821,7 +403,7 @@ errorLine1=" Log.i(TAG, "Checking for updates at " + unresolvedURL);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -832,7 +414,7 @@ errorLine1=" Log.i(TAG, "Resolved update URL " + resolvedURL);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -843,7 +425,7 @@ errorLine1=" Log.i(TAG, "HTTP response code " + responseCode);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -854,8 +436,8 @@ errorLine1=" Log.i(TAG, "Downloading update " + unresolvedURL);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -865,8 +447,8 @@ errorLine1=" Log.i(TAG, "Update downloaded in " + totalMillis / 100 / 10. + "s");" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -876,7 +458,7 @@ errorLine1=" objects = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -887,7 +469,7 @@ errorLine1=" customAccessibilityActions = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -898,7 +480,7 @@ errorLine1=" this.pendingReplies = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -909,7 +491,7 @@ errorLine1=" vdControllers = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -920,8 +502,8 @@ errorLine1=" public boolean onTouchEvent(MotionEvent event) {" errorLine2=" ~~~~~~~~~~~~"> @@ -931,7 +513,7 @@ errorLine1=" public boolean onTouchEvent(MotionEvent event) {" errorLine2=" ~~~~~~~~~~~~"> diff --git a/tools/android_lint/project.xml b/tools/android_lint/project.xml index 6d8fffe439f3e..07f57505243d5 100644 --- a/tools/android_lint/project.xml +++ b/tools/android_lint/project.xml @@ -1,81 +1,81 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d47b8fe9d65ee09d7fd507ab3502574bafb1124d Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Tue, 5 Mar 2019 15:29:53 -0800 Subject: [PATCH 2/5] Review fixup. --- .../engine/android/FlutterSurfaceView.java | 3 +- .../engine/android/FlutterTextureView.java | 3 +- .../embedding/engine/android/FlutterView.java | 5 +- .../android/io/flutter/view/FlutterView.java | 16 +- .../io/flutter/view/ResourceExtractor.java | 2 +- tools/android_lint/baseline.xml | 94 +++++------ tools/android_lint/project.xml | 150 +++++++++--------- 7 files changed, 134 insertions(+), 139 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/android/FlutterSurfaceView.java b/shell/platform/android/io/flutter/embedding/engine/android/FlutterSurfaceView.java index c565bf26f786e..cbff0b4ac828c 100644 --- a/shell/platform/android/io/flutter/embedding/engine/android/FlutterSurfaceView.java +++ b/shell/platform/android/io/flutter/embedding/engine/android/FlutterSurfaceView.java @@ -11,7 +11,6 @@ import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; -import android.support.v4.view.ViewCompat; import java.nio.ByteBuffer; @@ -135,7 +134,7 @@ public void detachFromRenderer() { if (flutterRenderer != null) { // If we're attached to an Android window then we were rendering a Flutter UI. Now that // this FlutterSurfaceView is detached from the FlutterRenderer, we need to stop rendering. - if (ViewCompat.isAttachedToWindow(this)) { + if (getWindowToken() != null) { disconnectSurfaceFromRenderer(); } diff --git a/shell/platform/android/io/flutter/embedding/engine/android/FlutterTextureView.java b/shell/platform/android/io/flutter/embedding/engine/android/FlutterTextureView.java index 4cf685238c98b..f39c6d4e77a82 100644 --- a/shell/platform/android/io/flutter/embedding/engine/android/FlutterTextureView.java +++ b/shell/platform/android/io/flutter/embedding/engine/android/FlutterTextureView.java @@ -12,7 +12,6 @@ import android.util.Log; import android.view.Surface; import android.view.TextureView; -import android.support.v4.view.ViewCompat; import java.nio.ByteBuffer; @@ -146,7 +145,7 @@ public void detachFromRenderer() { if (flutterRenderer != null) { // If we're attached to an Android window then we were rendering a Flutter UI. Now that // this FlutterTextureView is detached from the FlutterRenderer, we need to stop rendering. - if (ViewCompat.isAttachedToWindow(this)) { + if (getWindowToken() != null) { disconnectSurfaceFromRenderer(); } diff --git a/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java index e963bf36fe037..8cd1a9cfd2987 100644 --- a/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java @@ -4,6 +4,7 @@ package io.flutter.embedding.engine.android; +import android.annotation.TargetApi; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; @@ -179,10 +180,8 @@ protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) * the wider than expected padding when the status and navigation bars are hidden. */ @Override + @TargetApi(20) public final WindowInsets onApplyWindowInsets(WindowInsets insets) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH) { - return null; - } WindowInsets newInsets = super.onApplyWindowInsets(insets); // Status bar (top) and left/right system insets should partially obscure the content (padding). diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index adeaf1fad8be0..f970735886cd9 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -4,6 +4,7 @@ package io.flutter.view; +import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.res.Configuration; @@ -654,10 +655,8 @@ else if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { // be padded. When the on-screen keyboard is detected, we want to include the full inset // but when the inset is just the hidden nav bar, we want to provide a zero inset so the space // can be used. + @TargetApi(20) int calculateBottomKeyboardInset(WindowInsets insets) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH) { - return 0; - } int screenHeight = getRootView().getHeight(); // Magic number due to this being a heuristic. This should be replaced, but we have not // found a clean way to do it yet (Sept. 2018) @@ -675,10 +674,8 @@ int calculateBottomKeyboardInset(WindowInsets insets) { // This callback is not present in API < 20, which means lower API devices will see // the wider than expected padding when the status and navigation bars are hidden. @Override + @TargetApi(20) public final WindowInsets onApplyWindowInsets(WindowInsets insets) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH) { - return null; - } boolean statusBarHidden = (SYSTEM_UI_FLAG_FULLSCREEN & getWindowSystemUiVisibility()) != 0; boolean navigationBarHidden = @@ -969,8 +966,9 @@ public void onChange(boolean selfChange) { @Override public void onChange(boolean selfChange, Uri uri) { - String value = Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT ? null : Settings.Global.getString(getContext().getContentResolver(), - Settings.Global.TRANSITION_ANIMATION_SCALE); + String value = Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 ? null + : Settings.Global.getString(getContext().getContentResolver(), + Settings.Global.TRANSITION_ANIMATION_SCALE); if (value != null && value.equals("0")) { mAccessibilityFeatureFlags |= AccessibilityFeature.DISABLE_ANIMATIONS.value; } else { @@ -981,7 +979,7 @@ public void onChange(boolean selfChange, Uri uri) { } // This is guarded at instantiation time. - @SuppressWarnings("NewApi") + @TargetApi(19) class TouchExplorationListener implements AccessibilityManager.TouchExplorationStateChangeListener { @Override public void onTouchExplorationStateChanged(boolean enabled) { diff --git a/shell/platform/android/io/flutter/view/ResourceExtractor.java b/shell/platform/android/io/flutter/view/ResourceExtractor.java index 53daee001e86a..3fd773499462a 100644 --- a/shell/platform/android/io/flutter/view/ResourceExtractor.java +++ b/shell/platform/android/io/flutter/view/ResourceExtractor.java @@ -33,7 +33,7 @@ class ResourceExtractor { @SuppressWarnings("deprecation") static long getVersionCode(PackageInfo packageInfo) { - // Linter needs 28 hardcoded + // Linter needs P (28) hardcoded or else it will fail these lines. if (Build.VERSION.SDK_INT >= 28) { return packageInfo.getLongVersionCode(); } else { diff --git a/tools/android_lint/baseline.xml b/tools/android_lint/baseline.xml index 71b8a3c3f4ad4..8bf692f003497 100644 --- a/tools/android_lint/baseline.xml +++ b/tools/android_lint/baseline.xml @@ -7,7 +7,7 @@ errorLine1=" assert object.id > ROOT_NODE_ID;" errorLine2=" ~~~~~~"> @@ -18,7 +18,7 @@ errorLine1=" assert object.id == ROOT_NODE_ID;" errorLine2=" ~~~~~~"> @@ -29,7 +29,7 @@ errorLine1=" assert !(hasCheckedState && hasToggledState);" errorLine2=" ~~~~~~"> @@ -40,7 +40,7 @@ errorLine1=" assert objects.containsKey(0);" errorLine2=" ~~~~~~"> @@ -51,7 +51,7 @@ errorLine1=" assert(object.scrollIndex + visibleChildren <= object.scrollChildren);" errorLine2=" ~~~~~~"> @@ -62,7 +62,7 @@ errorLine1=" assert(!object.childrenInHitTestOrder.get(object.scrollIndex).hasFlag(Flag.IS_HIDDEN));" errorLine2=" ~~~~~~"> @@ -73,7 +73,7 @@ errorLine1=" assert virtualViewId != ROOT_NODE_ID;" errorLine2=" ~~~~~~"> @@ -84,7 +84,7 @@ errorLine1=" assert objects.containsKey(object.id);" errorLine2=" ~~~~~~"> @@ -95,7 +95,7 @@ errorLine1=" assert objects.get(object.id) == object;" errorLine2=" ~~~~~~"> @@ -106,7 +106,7 @@ errorLine1=" assert hadPreviousConfig;" errorLine2=" ~~~~~~"> @@ -117,7 +117,7 @@ errorLine1=" assert action.overrideId == -1;" errorLine2=" ~~~~~~"> @@ -128,7 +128,7 @@ errorLine1=" assert !globalGeometryDirty;" errorLine2=" ~~~~~~"> @@ -139,7 +139,7 @@ errorLine1=" assert packet.position() % (POINTER_DATA_FIELD_COUNT * BYTE_PER_FIELD) == 0;" errorLine2=" ~~~~~~"> @@ -150,7 +150,7 @@ errorLine1=" assert 0 <= value;" errorLine2=" ~~~~~~"> @@ -161,7 +161,7 @@ errorLine1=" AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT));" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -172,7 +172,7 @@ errorLine1=" AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT));" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -183,7 +183,7 @@ errorLine1=" return ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -194,7 +194,7 @@ errorLine1=" return ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -205,7 +205,7 @@ errorLine1=" return ActivityInfo.SCREEN_ORIENTATION_FULL_USER;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -216,7 +216,7 @@ errorLine1=" view.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -227,7 +227,7 @@ errorLine1=" enabledOverlays |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -238,7 +238,7 @@ errorLine1=" return direction == View.LAYOUT_DIRECTION_LTR || direction == View.LAYOUT_DIRECTION_RTL;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -249,7 +249,7 @@ errorLine1=" return direction == View.LAYOUT_DIRECTION_LTR || direction == View.LAYOUT_DIRECTION_RTL;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -260,7 +260,7 @@ errorLine1=" <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -271,7 +271,7 @@ errorLine1=" <application android:label="Flutter Shell" android:name="FlutterApplication" android:debuggable="true">" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -282,7 +282,7 @@ errorLine1=" System.load(lib.getAbsolutePath());" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -293,7 +293,7 @@ errorLine1=" private static ResourceUpdater sResourceUpdater;" errorLine2=" ~~~~~~"> @@ -304,7 +304,7 @@ errorLine1=" private static ResourceExtractor sResourceExtractor;" errorLine2=" ~~~~~~"> @@ -315,7 +315,7 @@ errorLine1=" private class CleanTask extends AsyncTask<Void, Void, Void> {" errorLine2=" ~~~~~~~~~"> @@ -326,7 +326,7 @@ errorLine1=" private class ExtractTask extends AsyncTask<Void, Void, Void> {" errorLine2=" ~~~~~~~~~~~"> @@ -337,7 +337,7 @@ errorLine1=" private class DownloadTask extends AsyncTask<String, String, Void> {" errorLine2=" ~~~~~~~~~~~~"> @@ -348,7 +348,7 @@ errorLine1=" Log.i(TAG," errorLine2=" ^"> @@ -359,7 +359,7 @@ errorLine1=" Log.println(level, tag, errorMessage + details);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -370,7 +370,7 @@ errorLine1=" Log.i(TAG, "Cleaning " + mFilesToDelete.length + " resources.");" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -381,7 +381,7 @@ errorLine1=" Log.i(TAG, "Extracted baseline resource " + resource);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -392,7 +392,7 @@ errorLine1=" Log.i(TAG, "Extracted override resource " + entry.getName());" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -403,7 +403,7 @@ errorLine1=" Log.i(TAG, "Checking for updates at " + unresolvedURL);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -414,7 +414,7 @@ errorLine1=" Log.i(TAG, "Resolved update URL " + resolvedURL);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -425,7 +425,7 @@ errorLine1=" Log.i(TAG, "HTTP response code " + responseCode);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -436,7 +436,7 @@ errorLine1=" Log.i(TAG, "Downloading update " + unresolvedURL);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -447,7 +447,7 @@ errorLine1=" Log.i(TAG, "Update downloaded in " + totalMillis / 100 / 10. + "s");" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -458,7 +458,7 @@ errorLine1=" objects = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -469,7 +469,7 @@ errorLine1=" customAccessibilityActions = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -480,7 +480,7 @@ errorLine1=" this.pendingReplies = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -491,7 +491,7 @@ errorLine1=" vdControllers = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -502,7 +502,7 @@ errorLine1=" public boolean onTouchEvent(MotionEvent event) {" errorLine2=" ~~~~~~~~~~~~"> @@ -513,7 +513,7 @@ errorLine1=" public boolean onTouchEvent(MotionEvent event) {" errorLine2=" ~~~~~~~~~~~~"> diff --git a/tools/android_lint/project.xml b/tools/android_lint/project.xml index 07f57505243d5..e8e86e8391751 100644 --- a/tools/android_lint/project.xml +++ b/tools/android_lint/project.xml @@ -1,81 +1,81 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From edbe7b07e7f8032f0b66449c140fe6ad998416fe Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Tue, 5 Mar 2019 16:37:37 -0800 Subject: [PATCH 3/5] Ignore try-with-resoruces failures Revert those failures. Also actually fix up the relative paths in the linter XML files. --- .../io/flutter/view/ResourceExtractor.java | 56 ++----- .../io/flutter/view/ResourceUpdater.java | 32 +--- tools/android_lint/baseline.xml | 106 ++++++------- tools/android_lint/lint.xml | 11 ++ tools/android_lint/project.xml | 150 +++++++++--------- 5 files changed, 156 insertions(+), 199 deletions(-) create mode 100644 tools/android_lint/lint.xml diff --git a/shell/platform/android/io/flutter/view/ResourceExtractor.java b/shell/platform/android/io/flutter/view/ResourceExtractor.java index 3fd773499462a..5d8a304ed750a 100644 --- a/shell/platform/android/io/flutter/view/ResourceExtractor.java +++ b/shell/platform/android/io/flutter/view/ResourceExtractor.java @@ -189,17 +189,9 @@ private boolean extractAPK(File dataDir) { output.getParentFile().mkdirs(); } - InputStream is = manager.open(asset); - OutputStream os = new FileOutputStream(output); - try { + try (InputStream is = manager.open(asset); + OutputStream os = new FileOutputStream(output)) { copy(is, os); - } finally { - if (is != null) { - is.close(); - } - if (os != null) { - os.close(); - } } Log.i(TAG, "Extracted baseline resource " + resource); @@ -290,13 +282,8 @@ private boolean extractUpdate(File dataDir) { try { if (entry.getName().endsWith(".bzdiff40")) { ByteArrayOutputStream diff = new ByteArrayOutputStream(); - InputStream is = zipFile.getInputStream(entry); - try { + try (InputStream is = zipFile.getInputStream(entry)) { copy(is, diff); - } finally { - if (is != null) { - is.close(); - } } ByteArrayOutputStream orig = new ByteArrayOutputStream(); @@ -311,49 +298,26 @@ private boolean extractUpdate(File dataDir) { throw new IOException("Could not find APK resource " + resource); } - InputStream apkInputStream = apkFile.getInputStream(origEntry); - try { - copy(apkInputStream, orig); - } finally { - if (apkInputStream != null) { - apkInputStream.close(); - } + try (InputStream is = apkFile.getInputStream(origEntry)) { + copy(is, orig); } } else { - InputStream assetInputStream = manager.open(asset); - try { - copy(assetInputStream, orig); + try (InputStream is = manager.open(asset)) { + copy(is, orig); } catch (FileNotFoundException e) { throw new IOException("Could not find APK resource " + resource); - } finally { - if (assetInputStream != null) { - assetInputStream.close(); - } } } - OutputStream os = new FileOutputStream(output); - try { + try (OutputStream os = new FileOutputStream(output)) { os.write(BSDiff.bspatch(orig.toByteArray(), diff.toByteArray())); - } finally { - if (os != null) { - os.close(); - } } } else { - InputStream is = zipFile.getInputStream(entry); - OutputStream os = new FileOutputStream(output); - try { + try (InputStream is = zipFile.getInputStream(entry); + OutputStream os = new FileOutputStream(output)) { copy(is, os); - } finally { - if (is != null) { - is.close(); - } - if (os != null) { - os.close(); - } } } diff --git a/shell/platform/android/io/flutter/view/ResourceUpdater.java b/shell/platform/android/io/flutter/view/ResourceUpdater.java index 9541cc8becedb..30db64e14b1a8 100644 --- a/shell/platform/android/io/flutter/view/ResourceUpdater.java +++ b/shell/platform/android/io/flutter/view/ResourceUpdater.java @@ -129,11 +129,9 @@ protected Void doInBackground(String... unused) { return null; } - InputStream input = connection.getInputStream(); - try { + try (InputStream input = connection.getInputStream()) { Log.i(TAG, "Downloading update " + unresolvedURL); - OutputStream output = new FileOutputStream(localFile); - try { + try (OutputStream output = new FileOutputStream(localFile)) { int count; byte[] data = new byte[1024]; while ((count = input.read(data)) != -1) { @@ -142,14 +140,6 @@ protected Void doInBackground(String... unused) { long totalMillis = new Date().getTime() - startMillis; Log.i(TAG, "Update downloaded in " + totalMillis / 100 / 10. + "s"); - } finally { - if (output != null) { - output.close(); - } - } - } finally { - if (input != null) { - input.close(); } } @@ -336,19 +326,11 @@ public boolean validateManifest(JSONObject manifest) { }; for (String fn : checksumFiles) { AssetManager manager = context.getResources().getAssets(); - InputStream is = null; - try { - try { - is = manager.open(fn); - int count = 0; - byte[] buffer = new byte[BUFFER_SIZE]; - while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) { - checksum.update(buffer, 0, count); - } - } finally { - if (is != null) { - is.close(); - } + try (InputStream is = manager.open(fn)) { + int count = 0; + byte[] buffer = new byte[BUFFER_SIZE]; + while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) { + checksum.update(buffer, 0, count); } } catch (IOException e) { // Skip missing files. diff --git a/tools/android_lint/baseline.xml b/tools/android_lint/baseline.xml index 8bf692f003497..da71870ebac7a 100644 --- a/tools/android_lint/baseline.xml +++ b/tools/android_lint/baseline.xml @@ -7,7 +7,7 @@ errorLine1=" assert object.id > ROOT_NODE_ID;" errorLine2=" ~~~~~~"> @@ -18,7 +18,7 @@ errorLine1=" assert object.id == ROOT_NODE_ID;" errorLine2=" ~~~~~~"> @@ -29,7 +29,7 @@ errorLine1=" assert !(hasCheckedState && hasToggledState);" errorLine2=" ~~~~~~"> @@ -40,7 +40,7 @@ errorLine1=" assert objects.containsKey(0);" errorLine2=" ~~~~~~"> @@ -51,7 +51,7 @@ errorLine1=" assert(object.scrollIndex + visibleChildren <= object.scrollChildren);" errorLine2=" ~~~~~~"> @@ -62,7 +62,7 @@ errorLine1=" assert(!object.childrenInHitTestOrder.get(object.scrollIndex).hasFlag(Flag.IS_HIDDEN));" errorLine2=" ~~~~~~"> @@ -73,7 +73,7 @@ errorLine1=" assert virtualViewId != ROOT_NODE_ID;" errorLine2=" ~~~~~~"> @@ -84,7 +84,7 @@ errorLine1=" assert objects.containsKey(object.id);" errorLine2=" ~~~~~~"> @@ -95,7 +95,7 @@ errorLine1=" assert objects.get(object.id) == object;" errorLine2=" ~~~~~~"> @@ -106,7 +106,7 @@ errorLine1=" assert hadPreviousConfig;" errorLine2=" ~~~~~~"> @@ -117,7 +117,7 @@ errorLine1=" assert action.overrideId == -1;" errorLine2=" ~~~~~~"> @@ -128,7 +128,7 @@ errorLine1=" assert !globalGeometryDirty;" errorLine2=" ~~~~~~"> @@ -139,7 +139,7 @@ errorLine1=" assert packet.position() % (POINTER_DATA_FIELD_COUNT * BYTE_PER_FIELD) == 0;" errorLine2=" ~~~~~~"> @@ -150,7 +150,7 @@ errorLine1=" assert 0 <= value;" errorLine2=" ~~~~~~"> @@ -161,7 +161,7 @@ errorLine1=" AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT));" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -172,7 +172,7 @@ errorLine1=" AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT));" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -183,7 +183,7 @@ errorLine1=" return ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -194,7 +194,7 @@ errorLine1=" return ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -205,7 +205,7 @@ errorLine1=" return ActivityInfo.SCREEN_ORIENTATION_FULL_USER;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -216,7 +216,7 @@ errorLine1=" view.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -227,7 +227,7 @@ errorLine1=" enabledOverlays |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -238,7 +238,7 @@ errorLine1=" return direction == View.LAYOUT_DIRECTION_LTR || direction == View.LAYOUT_DIRECTION_RTL;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -249,7 +249,7 @@ errorLine1=" return direction == View.LAYOUT_DIRECTION_LTR || direction == View.LAYOUT_DIRECTION_RTL;" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -260,7 +260,7 @@ errorLine1=" <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -271,7 +271,7 @@ errorLine1=" <application android:label="Flutter Shell" android:name="FlutterApplication" android:debuggable="true">" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -282,7 +282,7 @@ errorLine1=" System.load(lib.getAbsolutePath());" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -293,7 +293,7 @@ errorLine1=" private static ResourceUpdater sResourceUpdater;" errorLine2=" ~~~~~~"> @@ -304,7 +304,7 @@ errorLine1=" private static ResourceExtractor sResourceExtractor;" errorLine2=" ~~~~~~"> @@ -315,7 +315,7 @@ errorLine1=" private class CleanTask extends AsyncTask<Void, Void, Void> {" errorLine2=" ~~~~~~~~~"> @@ -326,7 +326,7 @@ errorLine1=" private class ExtractTask extends AsyncTask<Void, Void, Void> {" errorLine2=" ~~~~~~~~~~~"> @@ -337,7 +337,7 @@ errorLine1=" private class DownloadTask extends AsyncTask<String, String, Void> {" errorLine2=" ~~~~~~~~~~~~"> @@ -348,7 +348,7 @@ errorLine1=" Log.i(TAG," errorLine2=" ^"> @@ -359,7 +359,7 @@ errorLine1=" Log.println(level, tag, errorMessage + details);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -370,7 +370,7 @@ errorLine1=" Log.i(TAG, "Cleaning " + mFilesToDelete.length + " resources.");" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -381,8 +381,8 @@ errorLine1=" Log.i(TAG, "Extracted baseline resource " + resource);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -392,8 +392,8 @@ errorLine1=" Log.i(TAG, "Extracted override resource " + entry.getName());" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -403,7 +403,7 @@ errorLine1=" Log.i(TAG, "Checking for updates at " + unresolvedURL);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -414,7 +414,7 @@ errorLine1=" Log.i(TAG, "Resolved update URL " + resolvedURL);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -425,7 +425,7 @@ errorLine1=" Log.i(TAG, "HTTP response code " + responseCode);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -436,8 +436,8 @@ errorLine1=" Log.i(TAG, "Downloading update " + unresolvedURL);" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -447,8 +447,8 @@ errorLine1=" Log.i(TAG, "Update downloaded in " + totalMillis / 100 / 10. + "s");" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -458,7 +458,7 @@ errorLine1=" objects = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -469,7 +469,7 @@ errorLine1=" customAccessibilityActions = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -480,7 +480,7 @@ errorLine1=" this.pendingReplies = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -491,7 +491,7 @@ errorLine1=" vdControllers = new HashMap<>();" errorLine2=" ~~~~~~~~~~~~~~~"> @@ -502,8 +502,8 @@ errorLine1=" public boolean onTouchEvent(MotionEvent event) {" errorLine2=" ~~~~~~~~~~~~"> @@ -513,8 +513,8 @@ errorLine1=" public boolean onTouchEvent(MotionEvent event) {" errorLine2=" ~~~~~~~~~~~~"> diff --git a/tools/android_lint/lint.xml b/tools/android_lint/lint.xml new file mode 100644 index 0000000000000..241207161d5d6 --- /dev/null +++ b/tools/android_lint/lint.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/tools/android_lint/project.xml b/tools/android_lint/project.xml index e8e86e8391751..6d8fffe439f3e 100644 --- a/tools/android_lint/project.xml +++ b/tools/android_lint/project.xml @@ -1,81 +1,81 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7ea55c8b892d175072b30061c67d90b89483ddd0 Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Thu, 7 Mar 2019 17:14:32 -0800 Subject: [PATCH 4/5] More misc. review cleanup. --- .../embedding/engine/android/FlutterView.java | 2 + .../io/flutter/view/AccessibilityBridge.java | 34 +++++++++- .../android/io/flutter/view/FlutterView.java | 4 ++ .../io/flutter/view/ResourceExtractor.java | 6 +- tools/android_lint/baseline.xml | 62 ++++++------------- 5 files changed, 62 insertions(+), 46 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java index 8cd1a9cfd2987..7e586670e477f 100644 --- a/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java @@ -13,6 +13,7 @@ import android.provider.Settings; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.RequiresApi; import android.text.format.DateFormat; import android.util.AttributeSet; import android.util.Log; @@ -181,6 +182,7 @@ protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) */ @Override @TargetApi(20) + @RequiresApi(20) public final WindowInsets onApplyWindowInsets(WindowInsets insets) { WindowInsets newInsets = super.onApplyWindowInsets(insets); diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index 5547f991bd5cc..add434080c054 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -4,12 +4,15 @@ package io.flutter.view; +import android.annotation.TargetApi; import android.app.Activity; import android.graphics.Rect; import android.opengl.Matrix; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.annotation.NonNull; +import android.support.annotation.RequiresApi; import android.util.Log; import android.view.View; import android.view.accessibility.AccessibilityEvent; @@ -84,10 +87,12 @@ enum Action { SHOW_ON_SCREEN(1 << 8), MOVE_CURSOR_FORWARD_BY_CHARACTER(1 << 9), MOVE_CURSOR_BACKWARD_BY_CHARACTER(1 << 10), + /** These actions are only supported on Android 4.3 and above. */ SET_SELECTION(1 << 11), COPY(1 << 12), CUT(1 << 13), PASTE(1 << 14), + /** End 4.3 only supported actions. */ DID_GAIN_ACCESSIBILITY_FOCUS(1 << 15), DID_LOSE_ACCESSIBILITY_FOCUS(1 << 16), CUSTOM_ACTION(1 << 17), @@ -233,6 +238,9 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { } result.setMovementGranularities(granularities); } + + // These are non-ops on older devices. Attempting to interact with the text will cause Talkback to read the + // contents of the text box instead. if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) { if (object.hasAction(Action.SET_SELECTION)) { result.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); @@ -314,6 +322,9 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { // We should prefer setCollectionInfo to the class names, as this way we get "In List" // and "Out of list" announcements. But we don't always know the counts, so we // can fallback to the generic scroll view class names. + // + // On older APIs, we always fall back to the generic scroll view class names here. + // // TODO(dnfield): We should add semantics properties for rows and columns in 2 dimensional lists, e.g. // GridView. Right now, we're only supporting ListViews and only if they have scroll children. if (object.hasFlag(Flag.HAS_IMPLICIT_SCROLLING)) { @@ -467,9 +478,21 @@ public boolean performAction(int virtualViewId, int action, Bundle arguments) { return true; } case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { + // Text selection APIs aren't available until API 18. We can't handle the case here so return false + // instead. It's extremely unlikely that this case would ever be triggered in the first place in API < + // 18. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { + return false; + } return performCursorMoveAction(object, virtualViewId, arguments, false); } case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { + // Text selection APIs aren't available until API 18. We can't handle the case here so return false + // instead. It's extremely unlikely that this case would ever be triggered in the first place in API < + // 18. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { + return false; + } return performCursorMoveAction(object, virtualViewId, arguments, true); } case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { @@ -504,9 +527,14 @@ public boolean performAction(int virtualViewId, int action, Bundle arguments) { return true; } case AccessibilityNodeInfo.ACTION_SET_SELECTION: { + // Text selection APIs aren't available until API 18. We can't handle the case here so return false + // instead. It's extremely unlikely that this case would ever be triggered in the first place in API < + // 18. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { + return false; + } final Map selection = new HashMap<>(); final boolean hasSelection = arguments != null - && Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 && arguments.containsKey( AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT) && arguments.containsKey( @@ -556,11 +584,13 @@ public boolean performAction(int virtualViewId, int action, Bundle arguments) { return false; } + @RequiresApi(18) + @TargetApi(18) boolean performCursorMoveAction( SemanticsObject object, int virtualViewId, Bundle arguments, boolean forward) { final int granularity = arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); - final boolean extendSelection = Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 && arguments.getBoolean( + final boolean extendSelection = arguments.getBoolean( AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); switch (granularity) { case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index f970735886cd9..6161a23c5f4af 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -18,6 +18,7 @@ import android.os.Handler; import android.os.LocaleList; import android.provider.Settings; +import android.support.annotation.RequiresApi; import android.text.format.DateFormat; import android.util.AttributeSet; import android.util.Log; @@ -656,6 +657,7 @@ else if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { // but when the inset is just the hidden nav bar, we want to provide a zero inset so the space // can be used. @TargetApi(20) + @RequiresApi(20) int calculateBottomKeyboardInset(WindowInsets insets) { int screenHeight = getRootView().getHeight(); // Magic number due to this being a heuristic. This should be replaced, but we have not @@ -675,6 +677,7 @@ int calculateBottomKeyboardInset(WindowInsets insets) { // the wider than expected padding when the status and navigation bars are hidden. @Override @TargetApi(20) + @RequiresApi(20) public final WindowInsets onApplyWindowInsets(WindowInsets insets) { boolean statusBarHidden = (SYSTEM_UI_FLAG_FULLSCREEN & getWindowSystemUiVisibility()) != 0; @@ -980,6 +983,7 @@ public void onChange(boolean selfChange, Uri uri) { // This is guarded at instantiation time. @TargetApi(19) + @RequiresApi(19) class TouchExplorationListener implements AccessibilityManager.TouchExplorationStateChangeListener { @Override public void onTouchExplorationStateChanged(boolean enabled) { diff --git a/shell/platform/android/io/flutter/view/ResourceExtractor.java b/shell/platform/android/io/flutter/view/ResourceExtractor.java index 5d8a304ed750a..48600d41b096e 100644 --- a/shell/platform/android/io/flutter/view/ResourceExtractor.java +++ b/shell/platform/android/io/flutter/view/ResourceExtractor.java @@ -30,6 +30,8 @@ class ResourceExtractor { private static final String TAG = "ResourceExtractor"; private static final String TIMESTAMP_PREFIX = "res_timestamp-"; + // Build.SUPPORTED_ABIS is only available in later Android API versions. + private static final String[] SUPPORTED_ABIS = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? new String[0] : Build.SUPPORTED_ABIS; @SuppressWarnings("deprecation") static long getVersionCode(PackageInfo packageInfo) { @@ -243,9 +245,9 @@ private boolean extractUpdate(File dataDir) { for (String asset : mResources) { String resource = null; ZipEntry entry = null; - if (asset.endsWith(".so") && Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) { + if (asset.endsWith(".so")) { // Replicate library lookup logic. - for (String abi : Build.SUPPORTED_ABIS) { + for (String abi : SUPPORTED_ABIS) { resource = "lib/" + abi + "/" + asset; entry = zipFile.getEntry(resource); if (entry == null) { diff --git a/tools/android_lint/baseline.xml b/tools/android_lint/baseline.xml index da71870ebac7a..93bc535f5737d 100644 --- a/tools/android_lint/baseline.xml +++ b/tools/android_lint/baseline.xml @@ -8,7 +8,7 @@ errorLine2=" ~~~~~~"> @@ -19,7 +19,7 @@ errorLine2=" ~~~~~~"> @@ -30,7 +30,7 @@ errorLine2=" ~~~~~~"> @@ -41,7 +41,7 @@ errorLine2=" ~~~~~~"> @@ -52,7 +52,7 @@ errorLine2=" ~~~~~~"> @@ -63,7 +63,7 @@ errorLine2=" ~~~~~~"> @@ -74,7 +74,7 @@ errorLine2=" ~~~~~~"> @@ -85,7 +85,7 @@ errorLine2=" ~~~~~~"> @@ -96,7 +96,7 @@ errorLine2=" ~~~~~~"> @@ -107,7 +107,7 @@ errorLine2=" ~~~~~~"> @@ -118,7 +118,7 @@ errorLine2=" ~~~~~~"> @@ -129,7 +129,7 @@ errorLine2=" ~~~~~~"> @@ -155,28 +155,6 @@ column="9"/> - - - - - - - - @@ -349,7 +327,7 @@ errorLine2=" ^"> @@ -382,7 +360,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -393,7 +371,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -459,7 +437,7 @@ errorLine2=" ~~~~~~~~~~~~~~~"> @@ -470,7 +448,7 @@ errorLine2=" ~~~~~~~~~~~~~~~"> @@ -503,7 +481,7 @@ errorLine2=" ~~~~~~~~~~~~"> @@ -514,7 +492,7 @@ errorLine2=" ~~~~~~~~~~~~"> From 01b24cff75a616669ea5fc9e386ab92ebc5dba77 Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Fri, 8 Mar 2019 10:50:49 -0800 Subject: [PATCH 5/5] Use fallback logic for SUPPORTED_ABIS --- .../io/flutter/view/ResourceExtractor.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/view/ResourceExtractor.java b/shell/platform/android/io/flutter/view/ResourceExtractor.java index 48600d41b096e..ecbd026c9db09 100644 --- a/shell/platform/android/io/flutter/view/ResourceExtractor.java +++ b/shell/platform/android/io/flutter/view/ResourceExtractor.java @@ -4,6 +4,8 @@ package io.flutter.view; +import static java.util.Arrays.asList; + import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -16,6 +18,7 @@ import org.json.JSONObject; import java.io.*; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.concurrent.CancellationException; @@ -30,8 +33,7 @@ class ResourceExtractor { private static final String TAG = "ResourceExtractor"; private static final String TIMESTAMP_PREFIX = "res_timestamp-"; - // Build.SUPPORTED_ABIS is only available in later Android API versions. - private static final String[] SUPPORTED_ABIS = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? new String[0] : Build.SUPPORTED_ABIS; + private static final String[] SUPPORTED_ABIS = getSupportedAbis(); @SuppressWarnings("deprecation") static long getVersionCode(PackageInfo packageInfo) { @@ -406,4 +408,14 @@ private String getAPKPath() { return null; } } + + private static String[] getSupportedAbis() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Build.SUPPORTED_ABIS.length > 0) { + return Build.SUPPORTED_ABIS; + } else { + ArrayList cpuAbis = new ArrayList(asList(Build.CPU_ABI, Build.CPU_ABI2)); + cpuAbis.removeAll(asList(null, "")); + return cpuAbis.toArray(new String[0]); + } + } }