From 02f9e7040c7767526ff85376035737df30b788dc Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 28 Feb 2024 12:17:26 -0800 Subject: [PATCH] Reapply "Bump everything to Android 21" (#51056) This reverts commit c9381fb8ef4ca7542cb99b5f668aa9d6415fc7f6. --- 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 8052f59b6d1c6..82455af96b75d 100644 --- a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java +++ b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java @@ -302,18 +302,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 @@ -895,7 +888,6 @@ public long id() { } @Override - @TargetApi(19) public void release() { if (released) { return; @@ -909,7 +901,6 @@ public void release() { } @Override - @TargetApi(19) public void pushImage(Image image) { if (released) { return; @@ -970,7 +961,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 cbf111cbaef34..4b63c5d54661e 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 f06f75fcd801b..cb088ba8f0867 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 @@ -112,11 +112,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(); @@ -226,7 +222,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 @@ +