From 1f24eaa4979da9c58cf6d77763395027048d923b Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 29 Feb 2024 09:00:01 -0800 Subject: [PATCH] Reapply "Bump everything to Android 21" (#51056) (#51070) This reverts commit c9381fb8ef4ca7542cb99b5f668aa9d6415fc7f6. Reverted in https://github.com/flutter/engine/pull/51056 because it caused failures in the framework. No changes, but framework test has been updated to use an actual robolectric implementation to avoid those failures. This should not land until https://github.com/flutter/flutter/pull/144348 has landed in the framework. @gaaclarke @johnmccutchan fyi --- shell/platform/android/AndroidManifest.xml | 2 +- shell/platform/android/build.gradle | 2 +- .../flutter/app/FlutterActivityDelegate.java | 11 +- .../android/AndroidTouchProcessor.java | 4 +- .../embedding/android/FlutterActivity.java | 13 +- .../embedding/android/FlutterFragment.java | 35 +-- .../android/FlutterFragmentActivity.java | 15 +- .../embedding/android/FlutterImageView.java | 3 - .../embedding/android/FlutterView.java | 64 +---- .../flutter/embedding/engine/FlutterJNI.java | 31 +-- .../PlayStoreDeferredComponentManager.java | 21 +- .../engine/loader/FlutterLoader.java | 16 +- .../engine/loader/ResourceExtractor.java | 16 +- .../mutatorsstack/FlutterMutatorView.java | 2 - .../engine/renderer/FlutterRenderer.java | 20 +- .../systemchannels/LocalizationChannel.java | 4 +- .../editing/InputConnectionAdaptor.java | 9 - .../localization/LocalizationPlugin.java | 70 ++---- .../plugin/platform/PlatformPlugin.java | 31 +-- .../platform/PlatformViewsController.java | 7 - .../platform/SingleViewPresentation.java | 7 +- .../platform/VirtualDisplayController.java | 1 - .../android/io/flutter/util/PathUtils.java | 8 +- .../android/io/flutter/util/TraceSection.java | 2 - .../android/io/flutter/util/ViewUtils.java | 16 -- .../io/flutter/view/AccessibilityBridge.java | 221 ++++++------------ .../view/AccessibilityViewEmbedder.java | 30 +-- .../android/io/flutter/view/FlutterView.java | 56 +---- .../android/io/flutter/view/VsyncWaiter.java | 3 - .../android/FlutterActivityTest.java | 2 +- ...PlayStoreDeferredComponentManagerTest.java | 2 - .../editing/InputConnectionAdaptorTest.java | 8 - .../plugin/editing/TextInputPluginTest.java | 3 - .../localization/LocalizationPluginTest.java | 25 +- .../plugin/platform/PlatformPluginTest.java | 17 -- .../platform/SingleViewPresentationTest.java | 5 +- .../flutter/view/AccessibilityBridgeTest.java | 6 - .../test/io/flutter/view/VsyncWaiterTest.java | 3 - .../platform/android/test_runner/build.gradle | 2 +- .../android/app/build.gradle | 2 +- testing/scenario_app/android/app/build.gradle | 2 +- .../scenariosui/ExternalTextureTests.java | 4 - .../ExternalTextureFlutterActivity.java | 7 +- tools/android_lint/baseline.xml | 55 ----- tools/android_lint/project.xml | 3 + 45 files changed, 196 insertions(+), 670 deletions(-) diff --git a/shell/platform/android/AndroidManifest.xml b/shell/platform/android/AndroidManifest.xml index 82f4b0a7c5da9..aca92f0ec7887 100644 --- a/shell/platform/android/AndroidManifest.xml +++ b/shell/platform/android/AndroidManifest.xml @@ -5,7 +5,7 @@ --> - + diff --git a/shell/platform/android/build.gradle b/shell/platform/android/build.gradle index 5f76a937bdb7e..004e3728f2dc2 100644 --- a/shell/platform/android/build.gradle +++ b/shell/platform/android/build.gradle @@ -23,7 +23,7 @@ android { compileSdkVersion 34 defaultConfig { - minSdkVersion 19 + minSdkVersion 21 } sourceSets { diff --git a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java index b57e20c061dfa..fcb553bbe8a2f 100644 --- a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java +++ b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java @@ -17,7 +17,6 @@ import android.content.res.Configuration; import android.content.res.Resources.NotFoundException; import android.graphics.drawable.Drawable; -import android.os.Build; import android.os.Bundle; import android.util.TypedValue; import android.view.View; @@ -137,12 +136,10 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { @Override public void onCreate(Bundle savedInstanceState) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Window window = activity.getWindow(); - window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - window.setStatusBarColor(0x40000000); - window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); - } + Window window = activity.getWindow(); + window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(0x40000000); + window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); String[] args = getArgsFromIntent(activity.getIntent()); FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args); diff --git a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java index f7c4db3e09658..8ef7237a7a9e9 100644 --- a/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java +++ b/shell/platform/android/io/flutter/embedding/android/AndroidTouchProcessor.java @@ -204,9 +204,7 @@ public boolean onTouchEvent(@NonNull MotionEvent event, @NonNull Matrix transfor public boolean onGenericMotionEvent(@NonNull MotionEvent event, @NonNull Context context) { // Method isFromSource is only available in API 18+ (Jelly Bean MR2) // Mouse hover support is not implemented for API < 18. - boolean isPointerEvent = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 - && event.isFromSource(InputDevice.SOURCE_CLASS_POINTER); + boolean isPointerEvent = event.isFromSource(InputDevice.SOURCE_CLASS_POINTER); boolean isMovementEvent = (event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE || event.getActionMasked() == MotionEvent.ACTION_SCROLL); diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index acdfc1ca3aca5..0135a9d4ec0d4 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -49,7 +49,6 @@ import io.flutter.embedding.engine.plugins.activity.ActivityControlSurface; import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister; import io.flutter.plugin.platform.PlatformPlugin; -import io.flutter.util.ViewUtils; import java.util.ArrayList; import java.util.List; @@ -216,7 +215,7 @@ public class FlutterActivity extends Activity *

This ID can be used to lookup {@code FlutterView} in the Android view hierarchy. For more, * see {@link android.view.View#findViewById}. */ - public static final int FLUTTER_VIEW_ID = ViewUtils.generateViewId(0xF1F2); + public static final int FLUTTER_VIEW_ID = View.generateViewId(); /** * Creates an {@link Intent} that launches a {@code FlutterActivity}, which creates a {@link @@ -773,12 +772,10 @@ private View createFlutterView() { } private void configureStatusBarForFullscreenFlutterExperience() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Window window = getWindow(); - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - window.setStatusBarColor(0x40000000); - window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); - } + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(0x40000000); + window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); } @Override diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index 586d60c9c6980..376142b9c7e55 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -8,7 +8,6 @@ import android.content.ComponentCallbacks2; import android.content.Context; import android.content.Intent; -import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -17,7 +16,6 @@ import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; @@ -27,7 +25,6 @@ import io.flutter.embedding.engine.FlutterShellArgs; import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener; import io.flutter.plugin.platform.PlatformPlugin; -import io.flutter.util.ViewUtils; import java.util.ArrayList; import java.util.List; @@ -107,7 +104,7 @@ public class FlutterFragment extends Fragment *

This ID can be used to lookup {@code FlutterView} in the Android view hierarchy. For more, * see {@link android.view.View#findViewById}. */ - public static final int FLUTTER_VIEW_ID = ViewUtils.generateViewId(0xF1F2); + public static final int FLUTTER_VIEW_ID = View.generateViewId(); private static final String TAG = "FlutterFragment"; @@ -170,18 +167,15 @@ public class FlutterFragment extends Fragment protected static final String ARG_SHOULD_AUTOMATICALLY_HANDLE_ON_BACK_PRESSED = "should_automatically_handle_on_back_pressed"; - @RequiresApi(18) private final OnWindowFocusChangeListener onWindowFocusChangeListener = - Build.VERSION.SDK_INT >= 18 - ? new OnWindowFocusChangeListener() { - @Override - public void onWindowFocusChanged(boolean hasFocus) { - if (stillAttachedForEvent("onWindowFocusChanged")) { - delegate.onWindowFocusChanged(hasFocus); - } - } + new OnWindowFocusChangeListener() { + @Override + public void onWindowFocusChanged(boolean hasFocus) { + if (stillAttachedForEvent("onWindowFocusChanged")) { + delegate.onWindowFocusChanged(hasFocus); } - : null; + } + }; /** * Creates a {@code FlutterFragment} with a default configuration. @@ -1128,20 +1122,15 @@ public void onStop() { @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - if (Build.VERSION.SDK_INT >= 18) { - view.getViewTreeObserver().addOnWindowFocusChangeListener(onWindowFocusChangeListener); - } + view.getViewTreeObserver().addOnWindowFocusChangeListener(onWindowFocusChangeListener); } @Override public void onDestroyView() { super.onDestroyView(); - if (Build.VERSION.SDK_INT >= 18) { - // onWindowFocusChangeListener is API 18+ only. - requireView() - .getViewTreeObserver() - .removeOnWindowFocusChangeListener(onWindowFocusChangeListener); - } + requireView() + .getViewTreeObserver() + .removeOnWindowFocusChangeListener(onWindowFocusChangeListener); if (stillAttachedForEvent("onDestroyView")) { delegate.onDestroyView(); } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java index 2a782ac7fc958..65fb752f20816 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java @@ -27,7 +27,6 @@ import android.content.pm.PackageManager; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; -import android.os.Build; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; @@ -45,7 +44,6 @@ import io.flutter.embedding.engine.FlutterShellArgs; import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister; import io.flutter.plugin.platform.PlatformPlugin; -import io.flutter.util.ViewUtils; import java.util.ArrayList; import java.util.List; @@ -67,8 +65,7 @@ public class FlutterFragmentActivity extends FragmentActivity // FlutterFragment management. private static final String TAG_FLUTTER_FRAGMENT = "flutter_fragment"; // TODO(mattcarroll): replace ID with R.id when build system supports R.java - public static final int FRAGMENT_CONTAINER_ID = - ViewUtils.generateViewId(609893468); // random number + public static final int FRAGMENT_CONTAINER_ID = View.generateViewId(); /** * Creates an {@link Intent} that launches a {@code FlutterFragmentActivity}, which executes a @@ -600,12 +597,10 @@ protected FlutterFragment createFlutterFragment() { } private void configureStatusBarForFullscreenFlutterExperience() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Window window = getWindow(); - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - window.setStatusBarColor(0x40000000); - window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); - } + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(0x40000000); + window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); } @Override diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index dcdf04e08bd21..9fd0f600ac3e4 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -39,7 +39,6 @@ * an {@link android.media.Image} and renders it to the {@link android.graphics.Canvas} in {@code * onDraw}. */ -@TargetApi(19) public class FlutterImageView extends View implements RenderSurface { private static final String TAG = "FlutterImageView"; @@ -99,7 +98,6 @@ private static void logW(String format, Object... args) { Log.w(TAG, String.format(Locale.US, format, args)); } - @TargetApi(19) @SuppressLint("WrongConstant") // RGBA_8888 is a valid constant. @NonNull private static ImageReader createImageReader(int width, int height) { @@ -187,7 +185,6 @@ public void resume() { * Acquires the next image to be drawn to the {@link android.graphics.Canvas}. Returns true if * there's an image available in the queue. */ - @TargetApi(19) public boolean acquireLatestImage() { if (!isAttachedToFlutterRenderer) { return false; diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 4cfa3c8839ddc..1e576b9a21095 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -290,7 +290,6 @@ public FlutterView(@NonNull Context context, @NonNull FlutterTextureView flutter *

{@code FlutterView} requires an {@code Activity} instead of a generic {@code Context} to be * compatible with {@link PlatformViewsController}. */ - @TargetApi(19) public FlutterView(@NonNull Context context, @NonNull FlutterImageView flutterImageView) { this(context, null, flutterImageView); } @@ -357,7 +356,6 @@ private FlutterView( init(); } - @TargetApi(19) private FlutterView( @NonNull Context context, @Nullable AttributeSet attrs, @@ -643,8 +641,7 @@ else if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { // // This method is replaced by Android API 30 (R/11) getInsets() method which can take the // android.view.WindowInsets.Type.ime() flag to find the keyboard inset. - @TargetApi(20) - @RequiresApi(20) + private int guessBottomKeyboardInset(WindowInsets insets) { int screenHeight = getRootView().getHeight(); // Magic number due to this being a heuristic. This should be replaced, but we have not @@ -670,8 +667,7 @@ private int guessBottomKeyboardInset(WindowInsets insets) { * wider than expected padding when the status and navigation bars are hidden. */ @Override - @TargetApi(20) - @RequiresApi(20) + // The annotations to suppress "InlinedApi" and "NewApi" lints prevent lint warnings // caused by usage of Android Q APIs. These calls are safe because they are // guarded. @@ -802,53 +798,6 @@ navigationBarVisible && guessBottomKeyboardInset(insets) == 0 sendViewportMetricsToFlutter(); return newInsets; } - - /** - * Invoked when Android's desired window insets change, i.e., padding. - * - *

{@code fitSystemWindows} is an earlier version of {@link - * #onApplyWindowInsets(WindowInsets)}. See that method for more details about how window insets - * relate to Flutter. - */ - @Override - @SuppressWarnings("deprecation") - protected boolean fitSystemWindows(@NonNull Rect insets) { - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { - // Status bar, left/right system insets partially obscure content (padding). - viewportMetrics.viewPaddingTop = insets.top; - viewportMetrics.viewPaddingRight = insets.right; - viewportMetrics.viewPaddingBottom = 0; - viewportMetrics.viewPaddingLeft = insets.left; - - // Bottom system inset (keyboard) should adjust scrollable bottom edge (inset). - viewportMetrics.viewInsetTop = 0; - viewportMetrics.viewInsetRight = 0; - viewportMetrics.viewInsetBottom = insets.bottom; - viewportMetrics.viewInsetLeft = 0; - - Log.v( - TAG, - "Updating window insets (fitSystemWindows()):\n" - + "Status bar insets: Top: " - + viewportMetrics.viewPaddingTop - + ", Left: " - + viewportMetrics.viewPaddingLeft - + ", Right: " - + viewportMetrics.viewPaddingRight - + "\n" - + "Keyboard insets: Bottom: " - + viewportMetrics.viewInsetBottom - + ", Left: " - + viewportMetrics.viewInsetLeft - + ", Right: " - + viewportMetrics.viewInsetRight); - - sendViewportMetricsToFlutter(); - return true; - } else { - return super.fitSystemWindows(insets); - } - } // ------- End: Process View configuration that Flutter cares about. -------- // -------- Start: Process UI I/O that Flutter cares about. ------- @@ -930,14 +879,7 @@ public boolean onTouchEvent(@NonNull MotionEvent event) { return super.onTouchEvent(event); } - // TODO(abarth): This version check might not be effective in some - // versions of Android that statically compile code and will be upset - // at the lack of |requestUnbufferedDispatch|. Instead, we should factor - // version-dependent code into separate classes for each supported - // version and dispatch dynamically. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - requestUnbufferedDispatch(event); - } + requestUnbufferedDispatch(event); return androidTouchProcessor.onTouchEvent(event); } diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index bb6ffd0f7b7ed..db17bcc16b4d1 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -1297,22 +1297,17 @@ public String[] computePlatformResolvedLocale(@NonNull String[] strings) { String countryCode = strings[i + 1]; String scriptCode = strings[i + 2]; // Convert to Locales via LocaleBuilder if available (API 21+) to include scriptCode. - if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - Locale.Builder localeBuilder = new Locale.Builder(); - if (!languageCode.isEmpty()) { - localeBuilder.setLanguage(languageCode); - } - if (!countryCode.isEmpty()) { - localeBuilder.setRegion(countryCode); - } - if (!scriptCode.isEmpty()) { - localeBuilder.setScript(scriptCode); - } - supportedLocales.add(localeBuilder.build()); - } else { - // Pre-API 21, we fall back on scriptCode-less locales. - supportedLocales.add(new Locale(languageCode, countryCode)); + Locale.Builder localeBuilder = new Locale.Builder(); + if (!languageCode.isEmpty()) { + localeBuilder.setLanguage(languageCode); + } + if (!countryCode.isEmpty()) { + localeBuilder.setRegion(countryCode); + } + if (!scriptCode.isEmpty()) { + localeBuilder.setScript(scriptCode); } + supportedLocales.add(localeBuilder.build()); } Locale result = localizationPlugin.resolveNativeLocale(supportedLocales); @@ -1323,11 +1318,7 @@ public String[] computePlatformResolvedLocale(@NonNull String[] strings) { String[] output = new String[localeDataLength]; output[0] = result.getLanguage(); output[1] = result.getCountry(); - if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - output[2] = result.getScript(); - } else { - output[2] = ""; - } + output[2] = result.getScript(); return output; } diff --git a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java index 705becaa96c19..c1eb7ce9a0dc3 100644 --- a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java +++ b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java @@ -412,12 +412,7 @@ public void loadDartLibrary(int loadingUnitId, @NonNull String componentName) { } // Possible values: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 - String abi; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - abi = Build.SUPPORTED_ABIS[0]; - } else { - abi = Build.CPU_ABI; - } + String abi = Build.SUPPORTED_ABIS[0]; String pathAbi = abi.replace("-", "_"); // abis are represented with underscores in paths. // TODO(garyq): Optimize this apk/file discovery process to use less i/o and be more @@ -431,14 +426,12 @@ public void loadDartLibrary(int loadingUnitId, @NonNull String componentName) { Queue searchFiles = new LinkedList<>(); // Downloaded modules are stored here searchFiles.add(context.getFilesDir()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - // The initial installed apks are provided by `sourceDirs` in ApplicationInfo. - // The jniLibs we want are in the splits not the baseDir. These - // APKs are only searched as a fallback, as base libs generally do not need - // to be fully path referenced. - for (String path : context.getApplicationInfo().splitSourceDirs) { - searchFiles.add(new File(path)); - } + // The initial installed apks are provided by `sourceDirs` in ApplicationInfo. + // The jniLibs we want are in the splits not the baseDir. These + // APKs are only searched as a fallback, as base libs generally do not need + // to be fully path referenced. + for (String path : context.getApplicationInfo().splitSourceDirs) { + searchFiles.add(new File(path)); } while (!searchFiles.isEmpty()) { diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java index 82a3b8c20ec6c..7ee076e32f8ff 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/FlutterLoader.java @@ -16,7 +16,6 @@ import android.os.Looper; import android.os.SystemClock; import android.util.DisplayMetrics; -import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import io.flutter.BuildConfig; @@ -168,18 +167,9 @@ public void startInitialization(@NonNull Context applicationContext, @NonNull Se initStartTimestampMillis = SystemClock.uptimeMillis(); flutterApplicationInfo = ApplicationInfoLoader.load(appContext); - VsyncWaiter waiter; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 /* 17 */) { - final DisplayManager dm = - (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE); - waiter = VsyncWaiter.getInstance(dm, flutterJNI); - } else { - float fps = - ((WindowManager) appContext.getSystemService(Context.WINDOW_SERVICE)) - .getDefaultDisplay() - .getRefreshRate(); - waiter = VsyncWaiter.getInstance(fps, flutterJNI); - } + final DisplayManager dm = + (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE); + VsyncWaiter waiter = VsyncWaiter.getInstance(dm, flutterJNI); waiter.init(); // Use a background thread for initialization tasks that require disk access. diff --git a/shell/platform/android/io/flutter/embedding/engine/loader/ResourceExtractor.java b/shell/platform/android/io/flutter/embedding/engine/loader/ResourceExtractor.java index a0b7382edf3da..f71ac56df918b 100644 --- a/shell/platform/android/io/flutter/embedding/engine/loader/ResourceExtractor.java +++ b/shell/platform/android/io/flutter/embedding/engine/loader/ResourceExtractor.java @@ -4,8 +4,6 @@ package io.flutter.embedding.engine.loader; -import static java.util.Arrays.asList; - import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; @@ -16,7 +14,6 @@ import io.flutter.BuildConfig; import io.flutter.Log; import java.io.*; -import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.concurrent.CancellationException; @@ -26,7 +23,7 @@ class ResourceExtractor { private static final String TAG = "ResourceExtractor"; private static final String TIMESTAMP_PREFIX = "res_timestamp-"; - private static final String[] SUPPORTED_ABIS = getSupportedAbis(); + private static final String[] SUPPORTED_ABIS = Build.SUPPORTED_ABIS; @SuppressWarnings("deprecation") static long getVersionCode(@NonNull PackageInfo packageInfo) { @@ -249,15 +246,4 @@ private static void copy(@NonNull InputStream in, @NonNull OutputStream out) thr out.write(buf, 0, i); } } - - @SuppressWarnings("deprecation") - private static String[] getSupportedAbis() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - 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]); - } - } } diff --git a/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java b/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java index c195b28728e9b..b6eaa3d434725 100644 --- a/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java +++ b/shell/platform/android/io/flutter/embedding/engine/mutatorsstack/FlutterMutatorView.java @@ -3,7 +3,6 @@ import static android.view.View.OnFocusChangeListener; import android.annotation.SuppressLint; -import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; import android.graphics.Matrix; @@ -23,7 +22,6 @@ * A view that applies the {@link io.flutter.embedding.engine.mutatorsstack.FlutterMutatorsStack} to * its children. */ -@TargetApi(19) public class FlutterMutatorView extends FrameLayout { private FlutterMutatorsStack mutatorsStack; private float screenDensity; diff --git a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java index 616443597dd0f..b58e92069bfb5 100644 --- a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java +++ b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java @@ -307,18 +307,11 @@ final class SurfaceTextureRegistryEntry textureWrapper.markDirty(); scheduleEngineFrame(); }; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - // The callback relies on being executed on the UI thread (unsynchronised read of - // mNativeView and also the engine code check for platform thread in - // Shell::OnPlatformViewMarkTextureFrameAvailable), so we explicitly pass a Handler for the - // current thread. - this.surfaceTexture().setOnFrameAvailableListener(onFrameListener, new Handler()); - } else { - // Android documentation states that the listener can be called on an arbitrary thread. But - // in practice, versions of Android that predate the newer API will call the listener on the - // thread where the SurfaceTexture was constructed. - this.surfaceTexture().setOnFrameAvailableListener(onFrameListener); - } + // The callback relies on being executed on the UI thread (unsynchronised read of + // mNativeView and also the engine code check for platform thread in + // Shell::OnPlatformViewMarkTextureFrameAvailable), so we explicitly pass a Handler for the + // current thread. + this.surfaceTexture().setOnFrameAvailableListener(onFrameListener, new Handler()); } @Override @@ -901,7 +894,6 @@ public long id() { } @Override - @TargetApi(19) public void release() { if (released) { return; @@ -915,7 +907,6 @@ public void release() { } @Override - @TargetApi(19) public void pushImage(Image image) { if (released) { return; @@ -976,7 +967,6 @@ public Image acquireLatestImage() { } @Override - @TargetApi(19) protected void finalize() throws Throwable { try { if (released) { diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java index dbd94b719f074..ed6c56129c4ce 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/LocalizationChannel.java @@ -4,7 +4,6 @@ package io.flutter.embedding.engine.systemchannels; -import android.os.Build; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; @@ -91,8 +90,7 @@ public void sendLocales(@NonNull List locales) { + ")"); data.add(locale.getLanguage()); data.add(locale.getCountry()); - // locale.getScript() was added in API 21. - data.add(Build.VERSION.SDK_INT >= 21 ? locale.getScript() : ""); + data.add(locale.getScript()); data.add(locale.getVariant()); } channel.invokeMethod("setLocale", data); diff --git a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java index 222158fcd7d10..3f868e74b44c8 100644 --- a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java +++ b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java @@ -118,9 +118,6 @@ private ExtractedText getExtractedText(ExtractedTextRequest request) { } private CursorAnchorInfo getCursorAnchorInfo() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return null; - } if (mCursorAnchorInfoBuilder == null) { mCursorAnchorInfoBuilder = new CursorAnchorInfo.Builder(); } else { @@ -226,9 +223,6 @@ public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { @Override public boolean requestCursorUpdates(int cursorUpdateMode) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return false; - } if ((cursorUpdateMode & CURSOR_UPDATE_IMMEDIATE) != 0) { mImm.updateCursorAnchorInfo(mFlutterView, getCursorAnchorInfo()); } @@ -569,9 +563,6 @@ public void didChangeEditingState( mEditable.getComposingStart(), mEditable.getComposingEnd()); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return; - } if (mExtractRequest != null) { mImm.updateExtractedText( mFlutterView, mExtractRequest.token, getExtractedText(mExtractRequest)); diff --git a/shell/platform/android/io/flutter/plugin/localization/LocalizationPlugin.java b/shell/platform/android/io/flutter/plugin/localization/LocalizationPlugin.java index acb1e904ca629..0998ee74f48a4 100644 --- a/shell/platform/android/io/flutter/plugin/localization/LocalizationPlugin.java +++ b/shell/platform/android/io/flutter/plugin/localization/LocalizationPlugin.java @@ -7,7 +7,6 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.res.Configuration; -import android.content.res.Resources; import android.os.Build; import android.os.LocaleList; import androidx.annotation.NonNull; @@ -39,19 +38,9 @@ public String getStringResource(@NonNull String key, @Nullable String localeStri if (localeString != null) { Locale locale = localeFromString(localeString); - // setLocale and createConfigurationContext is only available on API >= 17 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - Configuration config = new Configuration(context.getResources().getConfiguration()); - config.setLocale(locale); - localContext = context.createConfigurationContext(config); - } else { - // In API < 17, we have to update the locale in Configuration. - Resources resources = context.getResources(); - Configuration config = resources.getConfiguration(); - savedLocale = config.locale; - config.locale = locale; - resources.updateConfiguration(config, null); - } + Configuration config = new Configuration(context.getResources().getConfiguration()); + config.setLocale(locale); + localContext = context.createConfigurationContext(config); } String packageName = context.getPackageName(); @@ -61,14 +50,6 @@ public String getStringResource(@NonNull String key, @Nullable String localeStri stringToReturn = localContext.getResources().getString(resId); } - // In API < 17, we had to restore the original locale after using. - if (localeString != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { - Resources resources = context.getResources(); - Configuration config = resources.getConfiguration(); - config.locale = savedLocale; - resources.updateConfiguration(config, null); - } - return stringToReturn; } }; @@ -200,31 +181,26 @@ public void sendLocalesToFlutter(@NonNull Configuration config) { */ @NonNull public static Locale localeFromString(@NonNull String localeString) { - // Use Locale.forLanguageTag if available (API 21+). - if (false && Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - return Locale.forLanguageTag(localeString); - } else { - // Normalize the locale string, replace all underscores with hyphens. - localeString = localeString.replace('_', '-'); - - // Pre-API 21, we fall back to manually parsing the locale tag. - String parts[] = localeString.split("-", -1); - - // Assume the first part is always the language code. - String languageCode = parts[0]; - String scriptCode = ""; - String countryCode = ""; - int index = 1; - if (parts.length > index && parts[index].length() == 4) { - scriptCode = parts[index]; - index++; - } - if (parts.length > index && parts[index].length() >= 2 && parts[index].length() <= 3) { - countryCode = parts[index]; - index++; - } - // Ignore the rest of the locale for this purpose. - return new Locale(languageCode, countryCode, scriptCode); + // Normalize the locale string, replace all underscores with hyphens. + localeString = localeString.replace('_', '-'); + + // Pre-API 21, we fall back to manually parsing the locale tag. + String parts[] = localeString.split("-", -1); + + // Assume the first part is always the language code. + String languageCode = parts[0]; + String scriptCode = ""; + String countryCode = ""; + int index = 1; + if (parts.length > index && parts[index].length() == 4) { + scriptCode = parts[index]; + index++; + } + if (parts.length > index && parts[index].length() >= 2 && parts[index].length() <= 3) { + countryCode = parts[index]; + index++; } + // Ignore the rest of the locale for this purpose. + return new Locale(languageCode, countryCode, scriptCode); } } diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java index 9100476b7449e..d3926440fac43 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java @@ -4,7 +4,6 @@ package io.flutter.plugin.platform; -import android.annotation.TargetApi; import android.app.Activity; import android.app.ActivityManager.TaskDescription; import android.content.ClipData; @@ -206,9 +205,7 @@ private void playSystemSound(@NonNull PlatformChannel.SoundType soundType) { } break; case SELECTION_CLICK: - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - view.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); - } + view.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); break; } } @@ -220,20 +217,10 @@ private void setSystemChromePreferredOrientations(int androidOrientation) { @SuppressWarnings("deprecation") private void setSystemChromeApplicationSwitcherDescription( PlatformChannel.AppSwitcherDescription description) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return; - } - - // 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) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { activity.setTaskDescription( new TaskDescription(description.label, /* icon= */ null, description.color)); - } - if (Build.VERSION.SDK_INT >= 28) { + } else { TaskDescription taskDescription = new TaskDescription(description.label, 0, description.color); activity.setTaskDescription(taskDescription); @@ -291,8 +278,7 @@ private void setSystemChromeEnabledSystemUIMode(PlatformChannel.SystemUiMode sys | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; - } else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + } else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE) { // IMMERSIVE // Available starting at 19 // Should not show overlays, swipe from edges to reveal overlays, needs onChange callback @@ -307,8 +293,7 @@ private void setSystemChromeEnabledSystemUIMode(PlatformChannel.SystemUiMode sys | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; - } else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE_STICKY - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + } else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE_STICKY) { // STICKY IMMERSIVE // Available starting at 19 // Should not show overlays, swipe from edges to reveal overlays. The app will also receive @@ -352,10 +337,7 @@ private void setSystemChromeEnabledSystemUIOverlays( | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; - // The SYSTEM_UI_FLAG_IMMERSIVE_STICKY flag was introduced in API 19, so we - // apply it - // if desired, and if the current Android version is 19 or greater. - if (overlaysToShow.size() == 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (overlaysToShow.size() == 0) { enabledOverlays |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; } @@ -397,7 +379,6 @@ private void restoreSystemChromeSystemUIOverlays() { } @SuppressWarnings("deprecation") - @TargetApi(21) private void setSystemChromeSystemUIOverlayStyle( PlatformChannel.SystemChromeStyle systemChromeStyle) { Window window = activity.getWindow(); diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java index 0ce64f0c9cb51..e04e5679d5df6 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java @@ -156,7 +156,6 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega private final PlatformViewsChannel.PlatformViewsHandler channelHandler = new PlatformViewsChannel.PlatformViewsHandler() { - @TargetApi(19) @Override // TODO(egarciad): Remove the need for this. // https://github.com/flutter/flutter/issues/96679 @@ -173,7 +172,6 @@ public void createForPlatformViewLayer( // not applicable to fallback from TLHC to HC. } - @TargetApi(20) @Override public long createForTextureLayer( @NonNull PlatformViewsChannel.PlatformViewCreationRequest request) { @@ -419,7 +417,6 @@ public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) { view.dispatchTouchEvent(event); } - @TargetApi(17) @Override public void setDirection(int viewId, int direction) { if (!validateDirection(direction)) { @@ -504,7 +501,6 @@ private void ensureValidRequest( // Creates a platform view based on `request`, performs configuration that's common to // all display modes, and adds it to `platformViews`. - @TargetApi(19) @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public PlatformView createPlatformView( @NonNull PlatformViewsChannel.PlatformViewCreationRequest request, boolean wrapContext) { @@ -1080,7 +1076,6 @@ private void initializeRootImageViewIfNeeded() { * testing. */ @VisibleForTesting - @TargetApi(Build.VERSION_CODES.KITKAT) void initializePlatformViewIfNeeded(int viewId) { final PlatformView platformView = platformViews.get(viewId); if (platformView == null) { @@ -1292,7 +1287,6 @@ private void finishFrame(boolean isFrameRenderedUsingImageReaders) { * for public use, and is only visible for testing. */ @VisibleForTesting - @TargetApi(19) @NonNull public FlutterOverlaySurface createOverlaySurface(@NonNull PlatformOverlayView imageView) { final int id = nextOverlayLayerId++; @@ -1307,7 +1301,6 @@ public FlutterOverlaySurface createOverlaySurface(@NonNull PlatformOverlayView i * *

This member is not intended for public use, and is only visible for testing. */ - @TargetApi(19) @NonNull public FlutterOverlaySurface createOverlaySurface() { // Overlay surfaces have the same size as the background surface. diff --git a/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java b/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java index b7ca559ac7c64..c272f859286ee 100644 --- a/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java +++ b/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java @@ -7,7 +7,6 @@ import static android.content.Context.WINDOW_SERVICE; import static android.view.View.OnFocusChangeListener; -import android.annotation.TargetApi; import android.app.AlertDialog; import android.app.Presentation; import android.content.Context; @@ -15,7 +14,6 @@ import android.content.MutableContextWrapper; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; -import android.os.Build; import android.os.Bundle; import android.view.Display; import android.view.Gravity; @@ -51,7 +49,6 @@ * EmbeddedView */ @Keep -@TargetApi(Build.VERSION_CODES.KITKAT) class SingleViewPresentation extends Presentation { private static final String TAG = "PlatformViewsController"; @@ -123,9 +120,7 @@ public SingleViewPresentation( .setFlags( WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - getWindow().setType(WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION); - } + getWindow().setType(WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION); } /** diff --git a/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java b/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java index d041382044895..44389b9044fab 100644 --- a/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java +++ b/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java @@ -19,7 +19,6 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -@TargetApi(21) class VirtualDisplayController { private static String TAG = "VirtualDisplayController"; diff --git a/shell/platform/android/io/flutter/util/PathUtils.java b/shell/platform/android/io/flutter/util/PathUtils.java index 5f3f7bd6845e4..2427a6285b21c 100644 --- a/shell/platform/android/io/flutter/util/PathUtils.java +++ b/shell/platform/android/io/flutter/util/PathUtils.java @@ -32,12 +32,8 @@ public static String getDataDirectory(@NonNull Context applicationContext) { @NonNull public static String getCacheDirectory(@NonNull Context applicationContext) { File cacheDir; - if (Build.VERSION.SDK_INT >= 21) { - cacheDir = applicationContext.getCodeCacheDir(); - if (cacheDir == null) { - cacheDir = applicationContext.getCacheDir(); - } - } else { + cacheDir = applicationContext.getCodeCacheDir(); + if (cacheDir == null) { cacheDir = applicationContext.getCacheDir(); } if (cacheDir == null) { diff --git a/shell/platform/android/io/flutter/util/TraceSection.java b/shell/platform/android/io/flutter/util/TraceSection.java index 83352f872267c..5ea2355d4d243 100644 --- a/shell/platform/android/io/flutter/util/TraceSection.java +++ b/shell/platform/android/io/flutter/util/TraceSection.java @@ -4,11 +4,9 @@ package io.flutter.util; -import android.annotation.TargetApi; import androidx.annotation.NonNull; import androidx.tracing.Trace; -@TargetApi(19) public final class TraceSection implements AutoCloseable { /** * Factory used to support the try-with-resource construct. diff --git a/shell/platform/android/io/flutter/util/ViewUtils.java b/shell/platform/android/io/flutter/util/ViewUtils.java index 7915f28ff427d..d26039f814d5d 100644 --- a/shell/platform/android/io/flutter/util/ViewUtils.java +++ b/shell/platform/android/io/flutter/util/ViewUtils.java @@ -7,7 +7,6 @@ import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; -import android.os.Build; import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; @@ -59,21 +58,6 @@ public static Activity getActivity(@Nullable Context context) { return null; } - /** - * Generates a view id. - * - *

In API level 17 and above, this ID is unique. Below 17, the fallback id is used instead. - * - * @param fallbackId the fallback id. - * @return the view id. - */ - public static int generateViewId(int fallbackId) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - return View.generateViewId(); - } - return fallbackId; - } - /** * Determines if the current view or any descendant view has focus. * diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index dc5c257ade591..84b0a48d4a2e1 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -379,8 +379,6 @@ public void onAccessibilityStateChanged(boolean accessibilityEnabled) { // Listener that is notified when accessibility touch exploration is turned on/off. // This is guarded at instantiation time. - @TargetApi(19) - @RequiresApi(19) private final AccessibilityManager.TouchExplorationStateChangeListener touchExplorationStateChangeListener; @@ -400,10 +398,8 @@ public void onChange(boolean selfChange, Uri uri) { } // Retrieve the current value of TRANSITION_ANIMATION_SCALE from the OS. String value = - Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 - ? null - : Settings.Global.getString( - contentResolver, Settings.Global.TRANSITION_ANIMATION_SCALE); + Settings.Global.getString( + contentResolver, Settings.Global.TRANSITION_ANIMATION_SCALE); boolean shouldAnimationsBeDisabled = value != null && value.equals("0"); if (shouldAnimationsBeDisabled) { @@ -451,40 +447,34 @@ public AccessibilityBridge( // Tell Flutter whether touch exploration is initially active or not. Then register a listener // to be notified of changes in the future. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - touchExplorationStateChangeListener = - new AccessibilityManager.TouchExplorationStateChangeListener() { - @Override - public void onTouchExplorationStateChanged(boolean isTouchExplorationEnabled) { - if (isReleased) { - return; - } - if (!isTouchExplorationEnabled) { - setAccessibleNavigation(false); - onTouchExplorationExit(); - } + touchExplorationStateChangeListener = + new AccessibilityManager.TouchExplorationStateChangeListener() { + @Override + public void onTouchExplorationStateChanged(boolean isTouchExplorationEnabled) { + if (isReleased) { + return; + } + if (!isTouchExplorationEnabled) { + setAccessibleNavigation(false); + onTouchExplorationExit(); + } - if (onAccessibilityChangeListener != null) { - onAccessibilityChangeListener.onAccessibilityChanged( - accessibilityManager.isEnabled(), isTouchExplorationEnabled); - } + if (onAccessibilityChangeListener != null) { + onAccessibilityChangeListener.onAccessibilityChanged( + accessibilityManager.isEnabled(), isTouchExplorationEnabled); } - }; - touchExplorationStateChangeListener.onTouchExplorationStateChanged( - accessibilityManager.isTouchExplorationEnabled()); - this.accessibilityManager.addTouchExplorationStateChangeListener( - touchExplorationStateChangeListener); - } else { - touchExplorationStateChangeListener = null; - } + } + }; + touchExplorationStateChangeListener.onTouchExplorationStateChanged( + accessibilityManager.isTouchExplorationEnabled()); + this.accessibilityManager.addTouchExplorationStateChangeListener( + touchExplorationStateChangeListener); // Tell Flutter whether animations should initially be enabled or disabled. Then register a // listener to be notified of changes in the future. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - animationScaleObserver.onChange(false); - Uri transitionUri = Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE); - this.contentResolver.registerContentObserver(transitionUri, false, animationScaleObserver); - } + animationScaleObserver.onChange(false); + Uri transitionUri = Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE); + this.contentResolver.registerContentObserver(transitionUri, false, animationScaleObserver); // Tells Flutter whether the text should be bolded or not. If the user changes bold text // setting, the configuration will change and trigger a re-build of the accesibiltyBridge. @@ -507,10 +497,8 @@ public void release() { platformViewsAccessibilityDelegate.detachAccessibilityBridge(); setOnAccessibilityChangeListener(null); accessibilityManager.removeAccessibilityStateChangeListener(accessibilityStateChangeListener); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - accessibilityManager.removeTouchExplorationStateChangeListener( - touchExplorationStateChangeListener); - } + accessibilityManager.removeTouchExplorationStateChangeListener( + touchExplorationStateChangeListener); contentResolver.unregisterContentObserver(animationScaleObserver); accessibilityChannel.setAccessibilityMessageHandler(null); } @@ -669,11 +657,9 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { } // Work around for https://github.com/flutter/flutter/issues/21030 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - result.setViewIdResourceName(""); - if (semanticsNode.identifier != null) { - result.setViewIdResourceName(semanticsNode.identifier); - } + result.setViewIdResourceName(""); + if (semanticsNode.identifier != null) { + result.setViewIdResourceName(semanticsNode.identifier); } result.setPackageName(rootAccessibilityView.getContext().getPackageName()); result.setClassName("android.view.View"); @@ -692,20 +678,16 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { if (!semanticsNode.hasFlag(Flag.IS_READ_ONLY)) { result.setClassName("android.widget.EditText"); } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - result.setEditable(!semanticsNode.hasFlag(Flag.IS_READ_ONLY)); - if (semanticsNode.textSelectionBase != -1 && semanticsNode.textSelectionExtent != -1) { - result.setTextSelection( - semanticsNode.textSelectionBase, semanticsNode.textSelectionExtent); - } - // Text fields will always be created as a live region when they have input focus, - // so that updates to the label trigger polite announcements. This makes it easy to - // follow a11y guidelines for text fields on Android. - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 - && accessibilityFocusedSemanticsNode != null - && accessibilityFocusedSemanticsNode.id == virtualViewId) { - result.setLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE); - } + result.setEditable(!semanticsNode.hasFlag(Flag.IS_READ_ONLY)); + if (semanticsNode.textSelectionBase != -1 && semanticsNode.textSelectionExtent != -1) { + result.setTextSelection(semanticsNode.textSelectionBase, semanticsNode.textSelectionExtent); + } + // Text fields will always be created as a live region when they have input focus, + // so that updates to the label trigger polite announcements. This makes it easy to + // follow a11y guidelines for text fields on Android. + if (accessibilityFocusedSemanticsNode != null + && accessibilityFocusedSemanticsNode.id == virtualViewId) { + result.setLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE); } // Cursor movements @@ -727,8 +709,7 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { granularities |= AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD; } result.setMovementGranularities(granularities); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP - && semanticsNode.maxValueLength >= 0) { + if (semanticsNode.maxValueLength >= 0) { // Account for the fact that Flutter is counting Unicode scalar values and Android // is counting UTF16 words. final int length = semanticsNode.value == null ? 0 : semanticsNode.value.length(); @@ -740,26 +721,21 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { // 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 (semanticsNode.hasAction(Action.SET_SELECTION)) { - result.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); - } - if (semanticsNode.hasAction(Action.COPY)) { - result.addAction(AccessibilityNodeInfo.ACTION_COPY); - } - if (semanticsNode.hasAction(Action.CUT)) { - result.addAction(AccessibilityNodeInfo.ACTION_CUT); - } - if (semanticsNode.hasAction(Action.PASTE)) { - result.addAction(AccessibilityNodeInfo.ACTION_PASTE); - } + if (semanticsNode.hasAction(Action.SET_SELECTION)) { + result.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); + } + if (semanticsNode.hasAction(Action.COPY)) { + result.addAction(AccessibilityNodeInfo.ACTION_COPY); + } + if (semanticsNode.hasAction(Action.CUT)) { + result.addAction(AccessibilityNodeInfo.ACTION_CUT); + } + if (semanticsNode.hasAction(Action.PASTE)) { + result.addAction(AccessibilityNodeInfo.ACTION_PASTE); } - // Set text API isn't available until API 21. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (semanticsNode.hasAction(Action.SET_TEXT)) { - result.addAction(AccessibilityNodeInfo.ACTION_SET_TEXT); - } + if (semanticsNode.hasAction(Action.SET_TEXT)) { + result.addAction(AccessibilityNodeInfo.ACTION_SET_TEXT); } if (semanticsNode.hasFlag(Flag.IS_BUTTON) || semanticsNode.hasFlag(Flag.IS_LINK)) { @@ -770,8 +746,7 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { // TODO(jonahwilliams): Figure out a way conform to the expected id from TalkBack's // CustomLabelManager. talkback/src/main/java/labeling/CustomLabelManager.java#L525 } - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 - && semanticsNode.hasAction(Action.DISMISS)) { + if (semanticsNode.hasAction(Action.DISMISS)) { result.setDismissable(true); result.addAction(AccessibilityNodeInfo.ACTION_DISMISS); } @@ -788,8 +763,7 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { result.setParent(rootAccessibilityView); } - if (semanticsNode.previousNodeId != -1 - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + if (semanticsNode.previousNodeId != -1) { result.setTraversalAfter(rootAccessibilityView, semanticsNode.previousNodeId); } @@ -809,7 +783,7 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { !semanticsNode.hasFlag(Flag.HAS_ENABLED_STATE) || semanticsNode.hasFlag(Flag.IS_ENABLED)); if (semanticsNode.hasAction(Action.TAP)) { - if (Build.VERSION.SDK_INT >= 21 && semanticsNode.onTapOverride != null) { + if (semanticsNode.onTapOverride != null) { result.addAction( new AccessibilityNodeInfo.AccessibilityAction( AccessibilityNodeInfo.ACTION_CLICK, semanticsNode.onTapOverride.hint)); @@ -820,7 +794,7 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { } } if (semanticsNode.hasAction(Action.LONG_PRESS)) { - if (Build.VERSION.SDK_INT >= 21 && semanticsNode.onLongPressOverride != null) { + if (semanticsNode.onLongPressOverride != null) { result.addAction( new AccessibilityNodeInfo.AccessibilityAction( AccessibilityNodeInfo.ACTION_LONG_CLICK, semanticsNode.onLongPressOverride.hint)); @@ -853,8 +827,7 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { if (semanticsNode.hasFlag(Flag.HAS_IMPLICIT_SCROLLING)) { if (semanticsNode.hasAction(Action.SCROLL_LEFT) || semanticsNode.hasAction(Action.SCROLL_RIGHT)) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT - && shouldSetCollectionInfo(semanticsNode)) { + if (shouldSetCollectionInfo(semanticsNode)) { result.setCollectionInfo( AccessibilityNodeInfo.CollectionInfo.obtain( 0, // rows @@ -865,8 +838,7 @@ && shouldSetCollectionInfo(semanticsNode)) { result.setClassName("android.widget.HorizontalScrollView"); } } else { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 - && shouldSetCollectionInfo(semanticsNode)) { + if (shouldSetCollectionInfo(semanticsNode)) { result.setCollectionInfo( AccessibilityNodeInfo.CollectionInfo.obtain( semanticsNode.scrollChildren, // rows @@ -901,8 +873,7 @@ && shouldSetCollectionInfo(semanticsNode)) { result.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); } } - if (semanticsNode.hasFlag(Flag.IS_LIVE_REGION) - && Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) { + if (semanticsNode.hasFlag(Flag.IS_LIVE_REGION)) { result.setLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE); } @@ -967,12 +938,10 @@ && shouldSetCollectionInfo(semanticsNode)) { } // Actions on the local context menu - if (Build.VERSION.SDK_INT >= 21) { - if (semanticsNode.customAccessibilityActions != null) { - for (CustomAccessibilityAction action : semanticsNode.customAccessibilityActions) { - result.addAction( - new AccessibilityNodeInfo.AccessibilityAction(action.resourceId, action.label)); - } + if (semanticsNode.customAccessibilityActions != null) { + for (CustomAccessibilityAction action : semanticsNode.customAccessibilityActions) { + result.addAction( + new AccessibilityNodeInfo.AccessibilityAction(action.resourceId, action.label)); } } @@ -1114,26 +1083,10 @@ public boolean performAction( } 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(semanticsNode, 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(semanticsNode, virtualViewId, arguments, true); } case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: @@ -1192,14 +1145,6 @@ public boolean performAction( } 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 @@ -1250,12 +1195,6 @@ public boolean performAction( } case AccessibilityNodeInfo.ACTION_SET_TEXT: { - // Set text APIs aren't available until API 21. 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 < 21. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return false; - } return performSetText(semanticsNode, virtualViewId, arguments); } default: @@ -1275,8 +1214,6 @@ public boolean performAction( * Handles the responsibilities of {@link #performAction(int, int, Bundle)} for the specific * scenario of cursor movement. */ - @TargetApi(18) - @RequiresApi(18) private boolean performCursorMoveAction( @NonNull SemanticsNode semanticsNode, int virtualViewId, @@ -1413,8 +1350,6 @@ private void predictCursorMovement( * Handles the responsibilities of {@link #performAction(int, int, Bundle)} for the specific * scenario of cursor movement. */ - @TargetApi(21) - @RequiresApi(21) private boolean performSetText(SemanticsNode node, int virtualViewId, @NonNull Bundle arguments) { String newText = ""; if (arguments != null @@ -2005,9 +1940,7 @@ private void setAccessibilityPaneTitle(String title) { private void sendWindowContentChangeEvent(int virtualViewId) { AccessibilityEvent event = obtainAccessibilityEvent(virtualViewId, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); - } + event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); sendAccessibilityEvent(event); } @@ -2058,8 +1991,6 @@ private boolean doesLayoutInDisplayCutoutModeRequireLeftInset() { * Hook called just before a {@link SemanticsNode} is removed from the Android cache of Flutter's * semantics tree. */ - @TargetApi(19) - @RequiresApi(19) private void willRemoveSemanticsNode(SemanticsNode semanticsNodeToBeRemoved) { if (BuildConfig.DEBUG) { if (!flutterSemanticsTree.containsKey(semanticsNodeToBeRemoved.id)) { @@ -2875,27 +2806,15 @@ private float max(float a, float b, float c, float d) { } private CharSequence getValue() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return value; - } else { - return createSpannableString(value, valueAttributes); - } + return createSpannableString(value, valueAttributes); } private CharSequence getLabel() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return label; - } else { - return createSpannableString(label, labelAttributes); - } + return createSpannableString(label, labelAttributes); } private CharSequence getHint() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return hint; - } else { - return createSpannableString(hint, hintAttributes); - } + return createSpannableString(hint, hintAttributes); } private CharSequence getValueLabelHint() { @@ -2928,8 +2847,6 @@ private CharSequence getTextFieldHint() { return result; } - @TargetApi(21) - @RequiresApi(21) private SpannableString createSpannableString(String string, List attributes) { if (string == null) { return null; diff --git a/shell/platform/android/io/flutter/view/AccessibilityViewEmbedder.java b/shell/platform/android/io/flutter/view/AccessibilityViewEmbedder.java index 368e14ce5fc29..09fecf5e9dd10 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityViewEmbedder.java +++ b/shell/platform/android/io/flutter/view/AccessibilityViewEmbedder.java @@ -230,24 +230,18 @@ private void copyAccessibilityFields( output.setText(input.getText()); output.setVisibleToUser(input.isVisibleToUser()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - output.setEditable(input.isEditable()); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - output.setCanOpenPopup(input.canOpenPopup()); - output.setCollectionInfo(input.getCollectionInfo()); - output.setCollectionItemInfo(input.getCollectionItemInfo()); - output.setContentInvalid(input.isContentInvalid()); - output.setDismissable(input.isDismissable()); - output.setInputType(input.getInputType()); - output.setLiveRegion(input.getLiveRegion()); - output.setMultiLine(input.isMultiLine()); - output.setRangeInfo(input.getRangeInfo()); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - output.setError(input.getError()); - output.setMaxTextLength(input.getMaxTextLength()); - } + output.setEditable(input.isEditable()); + output.setCanOpenPopup(input.canOpenPopup()); + output.setCollectionInfo(input.getCollectionInfo()); + output.setCollectionItemInfo(input.getCollectionItemInfo()); + output.setContentInvalid(input.isContentInvalid()); + output.setDismissable(input.isDismissable()); + output.setInputType(input.getInputType()); + output.setLiveRegion(input.getLiveRegion()); + output.setMultiLine(input.isMultiLine()); + output.setRangeInfo(input.getRangeInfo()); + output.setError(input.getError()); + output.setMaxTextLength(input.getMaxTextLength()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { output.setContextClickable(input.isContextClickable()); // TODO(amirh): copy traversal before and after. diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index d61d54c78ebbb..dde0422c6a10a 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -12,7 +12,6 @@ import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.PixelFormat; -import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.os.Build; import android.os.Handler; @@ -447,14 +446,7 @@ public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); } - // TODO(abarth): This version check might not be effective in some - // versions of Android that statically compile code and will be upset - // at the lack of |requestUnbufferedDispatch|. Instead, we should factor - // version-dependent code into separate classes for each supported - // version and dispatch dynamically. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - requestUnbufferedDispatch(event); - } + requestUnbufferedDispatch(event); return androidTouchProcessor.onTouchEvent(event); } @@ -544,8 +536,7 @@ 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) - @RequiresApi(20) + private int guessBottomKeyboardInset(WindowInsets insets) { int screenHeight = getRootView().getHeight(); // Magic number due to this being a heuristic. This should be replaced, but we have not @@ -566,8 +557,6 @@ private int guessBottomKeyboardInset(WindowInsets insets) { // caused by usage of Android Q APIs. These calls are safe because they are // guarded. @Override - @TargetApi(20) - @RequiresApi(20) @SuppressLint({"InlinedApi", "NewApi"}) public final WindowInsets onApplyWindowInsets(WindowInsets insets) { // getSystemGestureInsets() was introduced in API 29 and immediately deprecated in 30. @@ -668,28 +657,6 @@ navigationBarVisible && guessBottomKeyboardInset(insets) == 0 return super.onApplyWindowInsets(insets); } - @Override - @SuppressWarnings("deprecation") - protected boolean fitSystemWindows(Rect insets) { - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { - // Status bar, left/right system insets partially obscure content (padding). - mMetrics.physicalViewPaddingTop = insets.top; - mMetrics.physicalViewPaddingRight = insets.right; - mMetrics.physicalViewPaddingBottom = 0; - mMetrics.physicalViewPaddingLeft = insets.left; - - // Bottom system inset (keyboard) should adjust scrollable bottom edge (inset). - mMetrics.physicalViewInsetTop = 0; - mMetrics.physicalViewInsetRight = 0; - mMetrics.physicalViewInsetBottom = insets.bottom; - mMetrics.physicalViewInsetLeft = 0; - updateViewportMetrics(); - return true; - } else { - return super.fitSystemWindows(insets); - } - } - private boolean isAttached() { return mNativeView != null && mNativeView.isAttached(); } @@ -931,19 +898,12 @@ final class SurfaceTextureRegistryEntry implements TextureRegistry.SurfaceTextur this.id = id; this.textureWrapper = new SurfaceTextureWrapper(surfaceTexture); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - // The callback relies on being executed on the UI thread (unsynchronised read of - // mNativeView - // and also the engine code check for platform thread in - // Shell::OnPlatformViewMarkTextureFrameAvailable), - // so we explicitly pass a Handler for the current thread. - this.surfaceTexture().setOnFrameAvailableListener(onFrameListener, new Handler()); - } else { - // Android documentation states that the listener can be called on an arbitrary thread. - // But in practice, versions of Android that predate the newer API will call the listener - // on the thread where the SurfaceTexture was constructed. - this.surfaceTexture().setOnFrameAvailableListener(onFrameListener); - } + // The callback relies on being executed on the UI thread (unsynchronised read of + // mNativeView + // and also the engine code check for platform thread in + // Shell::OnPlatformViewMarkTextureFrameAvailable), + // so we explicitly pass a Handler for the current thread. + this.surfaceTexture().setOnFrameAvailableListener(onFrameListener, new Handler()); } private SurfaceTexture.OnFrameAvailableListener onFrameListener = diff --git a/shell/platform/android/io/flutter/view/VsyncWaiter.java b/shell/platform/android/io/flutter/view/VsyncWaiter.java index 80f5658dea569..b99b089a5c55e 100644 --- a/shell/platform/android/io/flutter/view/VsyncWaiter.java +++ b/shell/platform/android/io/flutter/view/VsyncWaiter.java @@ -4,7 +4,6 @@ package io.flutter.view; -import android.annotation.TargetApi; import android.hardware.display.DisplayManager; import android.view.Choreographer; import android.view.Display; @@ -14,7 +13,6 @@ // TODO(mattcarroll): add javadoc. public class VsyncWaiter { - @TargetApi(17) class DisplayListener implements DisplayManager.DisplayListener { DisplayListener(DisplayManager displayManager) { this.displayManager = displayManager; @@ -59,7 +57,6 @@ public static VsyncWaiter getInstance(float fps, @NonNull FlutterJNI flutterJNI) return instance; } - @TargetApi(17) @NonNull public static VsyncWaiter getInstance( @NonNull DisplayManager displayManager, @NonNull FlutterJNI flutterJNI) { diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java index 30dd648beac6e..f5b0d395341cd 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java @@ -485,7 +485,7 @@ public void itReleaseEngineWhenOnDestroy() { } @Test - @Config(minSdk = Build.VERSION_CODES.KITKAT, maxSdk = Build.VERSION_CODES.P) + @Config(minSdk = 21, maxSdk = Build.VERSION_CODES.P) public void fullyDrawn_beforeAndroidQ() { Intent intent = FlutterActivityWithReportFullyDrawn.createDefaultIntent(ctx); ActivityController activityController = diff --git a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java index e221afbe011d7..735382b21cdb2 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java @@ -14,7 +14,6 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; -import android.annotation.TargetApi; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -33,7 +32,6 @@ @Config(manifest = Config.NONE) @RunWith(AndroidJUnit4.class) -@TargetApi(21) public class PlayStoreDeferredComponentManagerTest { private class TestFlutterJNI extends FlutterJNI { public int loadDartDeferredLibraryCalled = 0; diff --git a/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java b/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java index 9d93a2acd573d..1158f1d33b0cf 100644 --- a/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java +++ b/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.res.AssetManager; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.text.InputType; import android.text.Selection; @@ -1074,9 +1073,6 @@ public void testMethod_getExtractedText() { @Test public void testExtractedText_monitoring() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return; - } ListenableEditingState editable = sampleEditable(5, 5); View testView = new View(ctx); InputConnectionAdaptor adaptor = @@ -1128,10 +1124,6 @@ public void testExtractedText_monitoring() { @Test public void testCursorAnchorInfo() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return; - } - ListenableEditingState editable = sampleEditable(5, 5); View testView = new View(ctx); InputConnectionAdaptor adaptor = diff --git a/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java b/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java index 3bb087916080e..4fce566fc1655 100644 --- a/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java +++ b/shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java @@ -1246,9 +1246,6 @@ public void inputConnection_respondsToKeyEvents_textInputTypeNone() throws JSONE @SuppressWarnings("deprecation") // InputMethodSubtype @Test public void inputConnection_finishComposingTextUpdatesIMM() throws JSONException { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return; - } ShadowBuild.setManufacturer("samsung"); InputMethodSubtype inputMethodSubtype = new InputMethodSubtype(0, 0, /*locale=*/ "en", "", "", false, false); diff --git a/shell/platform/android/test/io/flutter/plugin/localization/LocalizationPluginTest.java b/shell/platform/android/test/io/flutter/plugin/localization/LocalizationPluginTest.java index 9b3d7ee921b7e..3f40c47646e1c 100644 --- a/shell/platform/android/test/io/flutter/plugin/localization/LocalizationPluginTest.java +++ b/shell/platform/android/test/io/flutter/plugin/localization/LocalizationPluginTest.java @@ -238,7 +238,7 @@ public void computePlatformResolvedLocale_fromAndroidN() { // Tests the legacy pre API 24 algorithm. @Test @Config( - minSdk = Build.VERSION_CODES.KITKAT, + minSdk = Build.VERSION_CODES.LOLLIPOP, maxSdk = Build.VERSION_CODES.M, qualifiers = "es-rMX") public void computePlatformResolvedLocale_emptySupportedLocales_beforeAndroidN() { @@ -252,7 +252,7 @@ public void computePlatformResolvedLocale_emptySupportedLocales_beforeAndroidN() } @Test - @Config(minSdk = Build.VERSION_CODES.KITKAT, maxSdk = Build.VERSION_CODES.M, qualifiers = "") + @Config(minSdk = 21, maxSdk = Build.VERSION_CODES.M, qualifiers = "") public void computePlatformResolvedLocale_selectFirstLocaleWhenNoUserSetting_beforeAndroidN() { FlutterJNI flutterJNI = new FlutterJNI(); DartExecutor dartExecutor = mock(DartExecutor.class); @@ -272,10 +272,7 @@ public void computePlatformResolvedLocale_selectFirstLocaleWhenNoUserSetting_bef } @Test - @Config( - minSdk = Build.VERSION_CODES.KITKAT, - maxSdk = Build.VERSION_CODES.M, - qualifiers = "fr-rCH") + @Config(minSdk = 21, maxSdk = Build.VERSION_CODES.M, qualifiers = "fr-rCH") public void computePlatformResolvedLocale_selectFirstLocaleWhenNoExactMatch_beforeAndroidN() { FlutterJNI flutterJNI = new FlutterJNI(); DartExecutor dartExecutor = mock(DartExecutor.class); @@ -298,10 +295,7 @@ public void computePlatformResolvedLocale_selectFirstLocaleWhenNoExactMatch_befo } @Test - @Config( - minSdk = Build.VERSION_CODES.KITKAT, - maxSdk = Build.VERSION_CODES.M, - qualifiers = "it-rIT") + @Config(minSdk = 21, maxSdk = Build.VERSION_CODES.M, qualifiers = "it-rIT") public void computePlatformResolvedLocale_selectExactMatchLocale_beforeAndroidN() { FlutterJNI flutterJNI = new FlutterJNI(); DartExecutor dartExecutor = mock(DartExecutor.class); @@ -324,10 +318,7 @@ public void computePlatformResolvedLocale_selectExactMatchLocale_beforeAndroidN( } @Test - @Config( - minSdk = Build.VERSION_CODES.KITKAT, - maxSdk = Build.VERSION_CODES.M, - qualifiers = "fr-rCH") + @Config(minSdk = 21, maxSdk = Build.VERSION_CODES.M, qualifiers = "fr-rCH") public void computePlatformResolvedLocale_selectOnlyLanguageLocale_beforeAndroidN() { FlutterJNI flutterJNI = new FlutterJNI(); DartExecutor dartExecutor = mock(DartExecutor.class); @@ -350,36 +341,30 @@ public void computePlatformResolvedLocale_selectOnlyLanguageLocale_beforeAndroid assertEquals(result[2], ""); } - // Tests the legacy pre API 21 algorithm. - @Config(sdk = Build.VERSION_CODES.KITKAT) @Test public void localeFromString_languageOnly() { Locale locale = LocalizationPlugin.localeFromString("en"); assertEquals(locale, new Locale("en")); } - @Config(sdk = Build.VERSION_CODES.KITKAT) @Test public void localeFromString_languageAndCountry() { Locale locale = LocalizationPlugin.localeFromString("en-US"); assertEquals(locale, new Locale("en", "US")); } - @Config(sdk = Build.VERSION_CODES.KITKAT) @Test public void localeFromString_languageCountryAndVariant() { Locale locale = LocalizationPlugin.localeFromString("zh-Hans-CN"); assertEquals(locale, new Locale("zh", "CN", "Hans")); } - @Config(sdk = Build.VERSION_CODES.KITKAT) @Test public void localeFromString_underscore() { Locale locale = LocalizationPlugin.localeFromString("zh_Hans_CN"); assertEquals(locale, new Locale("zh", "CN", "Hans")); } - @Config(sdk = Build.VERSION_CODES.KITKAT) @Test public void localeFromString_additionalVariantsAreIgnored() { Locale locale = LocalizationPlugin.localeFromString("de-DE-u-co-phonebk"); diff --git a/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java b/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java index 1d312057d47fc..dfb2f57cbd4b0 100644 --- a/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java +++ b/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java @@ -71,23 +71,6 @@ public void setUpForTextClipboardTests(Activity mockActivity) { clipboardFormat = ClipboardContentFormat.PLAIN_TEXT; } - @Config(sdk = Build.VERSION_CODES.KITKAT) - @Test - public void itIgnoresNewHapticEventsOnOldAndroidPlatforms() { - View fakeDecorView = mock(View.class); - Window fakeWindow = mock(Window.class); - Activity mockActivity = mock(Activity.class); - when(fakeWindow.getDecorView()).thenReturn(fakeDecorView); - when(mockActivity.getWindow()).thenReturn(fakeWindow); - PlatformPlugin platformPlugin = new PlatformPlugin(mockActivity, mockPlatformChannel); - - // HEAVY_IMPACT haptic response is only available on "M" (23) and later. - platformPlugin.vibrateHapticFeedback(PlatformChannel.HapticFeedbackType.HEAVY_IMPACT); - - // SELECTION_CLICK haptic response is only available on "LOLLIPOP" (21) and later. - platformPlugin.vibrateHapticFeedback(PlatformChannel.HapticFeedbackType.SELECTION_CLICK); - } - @Test public void platformPlugin_getClipboardDataIsNonNullWhenPlainTextCopied() throws IOException { View fakeDecorView = mock(View.class); diff --git a/shell/platform/android/test/io/flutter/plugin/platform/SingleViewPresentationTest.java b/shell/platform/android/test/io/flutter/plugin/platform/SingleViewPresentationTest.java index d27e08bbbdc97..fa07fa117136b 100644 --- a/shell/platform/android/test/io/flutter/plugin/platform/SingleViewPresentationTest.java +++ b/shell/platform/android/test/io/flutter/plugin/platform/SingleViewPresentationTest.java @@ -4,7 +4,6 @@ package io.flutter.plugin.platform; -import static android.os.Build.VERSION_CODES.KITKAT; import static android.os.Build.VERSION_CODES.P; import static android.os.Build.VERSION_CODES.R; import static org.junit.Assert.assertEquals; @@ -28,7 +27,7 @@ @TargetApi(P) public class SingleViewPresentationTest { @Test - @Config(minSdk = KITKAT, maxSdk = R) + @Config(minSdk = 21, maxSdk = R) public void returnsOuterContextInputMethodManager() { // There's a bug in Android Q caused by the IMM being instanced per display. // https://github.com/flutter/flutter/issues/38375. We need the context returned by @@ -59,7 +58,7 @@ public void returnsOuterContextInputMethodManager() { } @Test - @Config(minSdk = KITKAT, maxSdk = R) + @Config(minSdk = 21, maxSdk = R) public void returnsOuterContextInputMethodManager_createDisplayContext() { // The IMM should also persist across display contexts created from the base context. diff --git a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java index de209e29b448e..42be60d6d104e 100644 --- a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java +++ b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java @@ -64,7 +64,6 @@ @Config(manifest = Config.NONE) @RunWith(AndroidJUnit4.class) -@TargetApi(19) public class AccessibilityBridgeTest { @Test @@ -859,7 +858,6 @@ public void itAnnouncesRouteNameWhenRemoveARoute() { } @Config(sdk = 21) - @TargetApi(21) @Test public void itCanPerformSetText() { AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); @@ -899,7 +897,6 @@ public void itCanPerformSetText() { } @Config(sdk = 21) - @TargetApi(21) @Test public void itCanPredictSetText() { AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); @@ -939,7 +936,6 @@ public void itCanPredictSetText() { } @Config(sdk = 21) - @TargetApi(21) @Test public void itBuildsAttributedString() { AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); @@ -1006,7 +1002,6 @@ public void itBuildsAttributedString() { } @Config(sdk = 21) - @TargetApi(21) @Test public void itSetsTextCorrectly() { AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); @@ -1142,7 +1137,6 @@ public void itSetsIdentifierCorrectly() { } @Config(sdk = 21) - @TargetApi(21) @Test public void itCanCreateAccessibilityNodeInfoWithSetText() { AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); diff --git a/shell/platform/android/test/io/flutter/view/VsyncWaiterTest.java b/shell/platform/android/test/io/flutter/view/VsyncWaiterTest.java index 9afeb9c5deebb..ef56b9936b87b 100644 --- a/shell/platform/android/test/io/flutter/view/VsyncWaiterTest.java +++ b/shell/platform/android/test/io/flutter/view/VsyncWaiterTest.java @@ -14,7 +14,6 @@ import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; -import android.annotation.TargetApi; import android.hardware.display.DisplayManager; import android.os.Looper; import android.view.Display; @@ -50,7 +49,6 @@ public void itSetsFpsBelowApi17() { verify(mockFlutterJNI, times(1)).onVsync(anyLong(), eq(1000000000l / 10l), eq(1l)); } - @TargetApi(17) @Test public void itSetsFpsWhenDisplayManagerUpdates() { FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); @@ -86,7 +84,6 @@ public void itSetsFpsWhenDisplayManagerUpdates() { verify(mockFlutterJNI, times(1)).onVsync(anyLong(), eq(1000000000l / 60l), eq(1l)); } - @TargetApi(17) @Test public void itSetsFpsWhenDisplayManagerDoesNotUpdate() { FlutterJNI mockFlutterJNI = mock(FlutterJNI.class); diff --git a/shell/platform/android/test_runner/build.gradle b/shell/platform/android/test_runner/build.gradle index 9bd982a2fd119..da3b508bca435 100644 --- a/shell/platform/android/test_runner/build.gradle +++ b/shell/platform/android/test_runner/build.gradle @@ -35,7 +35,7 @@ android { compileSdkVersion 34 defaultConfig { - minSdkVersion 19 + minSdkVersion 21 } compileOptions { diff --git a/testing/android_background_image/android/app/build.gradle b/testing/android_background_image/android/app/build.gradle index 7a72a25fe99e6..d866acf038def 100644 --- a/testing/android_background_image/android/app/build.gradle +++ b/testing/android_background_image/android/app/build.gradle @@ -24,7 +24,7 @@ android { } defaultConfig { applicationId 'dev.flutter.android_background_image' - minSdkVersion 19 + minSdkVersion 21 targetSdkVersion 34 versionCode 1 versionName '1.0' diff --git a/testing/scenario_app/android/app/build.gradle b/testing/scenario_app/android/app/build.gradle index 2465157ed5ff4..c65cc89148e8f 100644 --- a/testing/scenario_app/android/app/build.gradle +++ b/testing/scenario_app/android/app/build.gradle @@ -26,7 +26,7 @@ android { } defaultConfig { applicationId 'dev.flutter.scenarios' - minSdkVersion 19 + minSdkVersion 21 targetSdkVersion 34 versionCode 1 versionName '1.0' diff --git a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/ExternalTextureTests.java b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/ExternalTextureTests.java index 37d96fa3e261f..605a07a3b6606 100644 --- a/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/ExternalTextureTests.java +++ b/testing/scenario_app/android/app/src/androidTest/java/dev/flutter/scenariosui/ExternalTextureTests.java @@ -47,7 +47,6 @@ public void testCanvasSurface() throws Exception { } @Test - @SdkSuppress(minSdkVersion = VERSION_CODES.LOLLIPOP) public void testMediaSurface() throws Exception { intent.putExtra("scenario_name", "display_texture"); intent.putExtra("surface_renderer", "media"); @@ -56,7 +55,6 @@ public void testMediaSurface() throws Exception { } @Test - @SdkSuppress(minSdkVersion = VERSION_CODES.LOLLIPOP) public void testRotatedMediaSurface_90() throws Exception { intent.putExtra("scenario_name", "display_texture"); intent.putExtra("surface_renderer", "media"); @@ -66,7 +64,6 @@ public void testRotatedMediaSurface_90() throws Exception { } @Test - @SdkSuppress(minSdkVersion = VERSION_CODES.LOLLIPOP) public void testRotatedMediaSurface_180() throws Exception { intent.putExtra("scenario_name", "display_texture"); intent.putExtra("surface_renderer", "media"); @@ -76,7 +73,6 @@ public void testRotatedMediaSurface_180() throws Exception { } @Test - @SdkSuppress(minSdkVersion = VERSION_CODES.LOLLIPOP) public void testRotatedMediaSurface_270() throws Exception { intent.putExtra("scenario_name", "display_texture"); intent.putExtra("surface_renderer", "media"); diff --git a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java index 8479673a6ca60..fcced923eb563 100644 --- a/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java +++ b/testing/scenario_app/android/app/src/main/java/dev/flutter/scenarios/ExternalTextureFlutterActivity.java @@ -111,11 +111,7 @@ private SurfaceRenderer selectSurfaceRenderer(String surfaceRenderer, Bundle ext throw new RuntimeException("ImageSurfaceRenderer not supported"); } case "media": - if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - return new MediaSurfaceRenderer(this::createMediaExtractor, extras.getInt("rotation", 0)); - } else { - throw new RuntimeException("MediaSurfaceRenderer not supported"); - } + return new MediaSurfaceRenderer(this::createMediaExtractor, extras.getInt("rotation", 0)); case "canvas": default: return new CanvasSurfaceRenderer(); @@ -224,7 +220,6 @@ public void destroy() {} } /** Decodes a sample video into the attached Surface. */ - @RequiresApi(VERSION_CODES.LOLLIPOP) private static class MediaSurfaceRenderer implements SurfaceRenderer { private final Supplier extractorSupplier; private final int rotation; diff --git a/tools/android_lint/baseline.xml b/tools/android_lint/baseline.xml index 2fccb83d76cf3..a73601b794503 100644 --- a/tools/android_lint/baseline.xml +++ b/tools/android_lint/baseline.xml @@ -1,61 +1,6 @@ - - - - - - - - - - - - - - - - - - - - + @@ -108,6 +109,7 @@ + @@ -159,5 +161,6 @@ +