Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClampingScrollSimulation decays sooner and goes less far than native Android scrolling #119875

Closed
gnprice opened this issue Feb 3, 2023 · 9 comments · Fixed by #120420
Closed
Labels
a: fidelity Matching the OEM platforms better f: scrolling Viewports, list views, slivers, etc. found in release: 3.7 Found to occur in 3.7 found in release: 3.8 Found to occur in 3.8 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list platform-android Android applications specifically r: fixed Issue is closed as already fixed in a newer version

Comments

@gnprice
Copy link
Member

gnprice commented Feb 3, 2023

On Android, when the user attempts to scroll quickly using a "fling" gesture, the scroll doesn't go as far or as fast as it would have in a native Android scrolling view. In a long list this can make scrolling feel sluggish, or not easy, or not responsive.

One reason for this behavior is that Flutter's ClampingScrollSimulation, which is meant to match Android's scroll physics (and is used by default on Android and other non-Apple platforms), in fact uses a curve that decays faster than the Android curve, and goes less far in total. When the simulation is complete, the distance traveled is about 7.2% less than the Android scroll physics would travel.

(This isn't the only factor contributing to the overall slowness of the scroll; I'll file other issues separately.)

Related issue:

Steps to Reproduce

  1. Run the platform_tests/scroll_overlay app on an Android device.
  2. Scroll with a fling gesture: swipe rapidly upward and release. Wait a couple of seconds for the scroll to come to a stop.
  3. Observe how far the scroll went, as shown by the numbered items in the Android- and Flutter-driven scrolling lists.

Expected results:

The Flutter list should scroll the same distance as the Android list, so that corresponding list items are aligned with each other.

Actual results:

The Flutter list goes substantially less far than the Android list.

Specifically, when I try this on the current version of scroll_overlay (at flutter/platform_tests@1d797b8 ), I see "Android 94" next to "Flutter 81".

That version has item heights that vary through the list and don't quite agree between Android and Flutter, making the numbers a bit hard to interpret. In a revised scroll_overlay with fixed heights (which I'll send a platform_tests PR for), I see "Android 202" next to "Flutter 189".

Logs
[   +6 ms] executing: uname -m
[   +3 ms] Exit code 0 from: uname -m
[        ] x86_64
[        ] executing: [/home/greg/n/flutter/flutter/] git -c log.showSignature=false log -n 1 --pretty=format:%H
[   +4 ms] Exit code 0 from: git -c log.showSignature=false log -n 1 --pretty=format:%H
[        ] 33e896b47581fe2737f641a181f86839df72719f
[        ] executing: [/home/greg/n/flutter/flutter/] git tag --points-at 33e896b47581fe2737f641a181f86839df72719f
[  +13 ms] Exit code 0 from: git tag --points-at 33e896b47581fe2737f641a181f86839df72719f
[        ] executing: [/home/greg/n/flutter/flutter/] git describe --match *.*.* --long --tags 33e896b47581fe2737f641a181f86839df72719f
[  +14 ms] Exit code 0 from: git describe --match *.*.* --long --tags 33e896b47581fe2737f641a181f86839df72719f
[        ] 3.7.0-12.0.pre-4-g33e896b47
[   +6 ms] executing: [/home/greg/n/flutter/flutter/] git rev-parse --abbrev-ref --symbolic @{upstream}
[   +2 ms] Exit code 0 from: git rev-parse --abbrev-ref --symbolic @{upstream}
[        ] origin/main
[        ] executing: [/home/greg/n/flutter/flutter/] git ls-remote --get-url origin
[   +1 ms] Exit code 0 from: git ls-remote --get-url origin
[        ] https://github.com/flutter/flutter.git
[   +9 ms] executing: [/home/greg/n/flutter/flutter/] git rev-parse --abbrev-ref HEAD
[   +2 ms] Exit code 0 from: git rev-parse --abbrev-ref HEAD
[        ] main
[  +23 ms] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
[   +1 ms] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
[  +31 ms] executing: /home/greg/Android/Sdk/platform-tools/adb devices -l
[   +7 ms] List of devices attached
           08171FDD40025F         device usb:1-5 product:redfin model:Pixel_5 device:redfin transport_id:7
[   +3 ms] /home/greg/Android/Sdk/platform-tools/adb -s 08171FDD40025F shell getprop
[  +33 ms] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
[        ] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
[  +88 ms] Skipping pub get: version match.
[  +28 ms] Generating /home/greg/n/flutter/platform_tests/scroll_overlay/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
[  +32 ms] ro.hardware = redfin
[        ] ro.build.characteristics = nosdcard
[  +20 ms] Initializing file store
[   +5 ms] Skipping target: gen_localizations
[   +3 ms] gen_dart_plugin_registrant: Starting due to {InvalidatedReasonKind.inputChanged: The following inputs have updated contents:
/home/greg/n/flutter/platform_tests/scroll_overlay/.dart_tool/package_config_subset}
[  +10 ms] gen_dart_plugin_registrant: Complete
[        ] Skipping target: _composite
[   +1 ms] complete
[   +4 ms] Launching lib/main.dart on Pixel 5 in debug mode...
[   +2 ms] /home/greg/n/flutter/flutter/bin/cache/dart-sdk/bin/dart --disable-dart-dev /home/greg/n/flutter/flutter/bin/cache/dart-sdk/bin/snapshots/frontend_server.dart.snapshot
--sdk-root /home/greg/n/flutter/flutter/bin/cache/artifacts/engine/common/flutter_patched_sdk/ --incremental --target=flutter --experimental-emit-debug-metadata
-DFLUTTER_WEB_AUTO_DETECT=true --output-dill /tmp/flutter_tools.CIELAI/flutter_tool.WAQCVS/app.dill --packages
/home/greg/n/flutter/platform_tests/scroll_overlay/.dart_tool/package_config.json -Ddart.vm.profile=false -Ddart.vm.product=false --enable-asserts --track-widget-creation
--filesystem-scheme org-dartlang-root --initialize-from-dill build/c075001b96339384a97db4862b8ab8db.cache.dill.track.dill --verbosity=error --flutter-widget-cache
--enable-experiment=alternative-invalidation-strategy
[   +4 ms] executing: /home/greg/Android/Sdk/build-tools/33.0.1/aapt dump xmltree /home/greg/n/flutter/platform_tests/scroll_overlay/build/app/outputs/flutter-apk/app-debug.apk
AndroidManifest.xml
[   +3 ms] Exit code 0 from: /home/greg/Android/Sdk/build-tools/33.0.1/aapt dump xmltree /home/greg/n/flutter/platform_tests/scroll_overlay/build/app/outputs/flutter-apk/app-debug.apk
AndroidManifest.xml
[        ] N: android=http://schemas.android.com/apk/res/android
             E: manifest (line=2)
               A: android:versionCode(0x0101021b)=(type 0x10)0x1
               A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")
               A: android:compileSdkVersion(0x01010572)=(type 0x10)0x21
               A: android:compileSdkVersionCodename(0x01010573)="13" (Raw: "13")
               A: package="io.flutter.scroll_overlay" (Raw: "io.flutter.scroll_overlay")
               A: platformBuildVersionCode=(type 0x10)0x21
               A: platformBuildVersionName=(type 0x10)0xd
               E: uses-sdk (line=7)
                 A: android:minSdkVersion(0x0101020c)=(type 0x10)0x10
                 A: android:targetSdkVersion(0x01010270)=(type 0x10)0x1c
               E: uses-permission (line=14)
                 A: android:name(0x01010003)="android.permission.INTERNET" (Raw: "android.permission.INTERNET")
               E: application (line=16)
                 A: android:label(0x01010001)="scroll_overlay" (Raw: "scroll_overlay")
                 A: android:icon(0x01010002)=@0x7f080000
                 A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
                 A: android:appComponentFactory(0x0101057a)="androidx.core.app.CoreComponentFactory" (Raw: "androidx.core.app.CoreComponentFactory")
                 E: activity (line=21)
                   A: android:theme(0x01010000)=@0x7f0a0000
                   A: android:name(0x01010003)="io.flutter.scroll_overlay.ScrollOverlayActivity" (Raw: "io.flutter.scroll_overlay.ScrollOverlayActivity")
                   A: android:exported(0x01010010)=(type 0x12)0xffffffff
                   A: android:launchMode(0x0101001d)=(type 0x10)0x1
                   A: android:configChanges(0x0101001f)=(type 0x11)0x40003fb4
                   A: android:windowSoftInputMode(0x0101022b)=(type 0x11)0x10
                   A: android:hardwareAccelerated(0x010102d3)=(type 0x12)0xffffffff
                   E: meta-data (line=36)
                     A: android:name(0x01010003)="io.flutter.embedding.android.NormalTheme" (Raw: "io.flutter.embedding.android.NormalTheme")
                     A: android:resource(0x01010025)=@0x7f0a0001
                   E: intent-filter (line=40)
                     E: action (line=41)
                       A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
                     E: category (line=43)
                       A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")
                 E: meta-data (line=50)
                   A: android:name(0x01010003)="flutterEmbedding" (Raw: "flutterEmbedding")
                   A: android:value(0x01010024)=(type 0x10)0x2
                 E: uses-library (line=54)
                   A: android:name(0x01010003)="androidx.window.extensions" (Raw: "androidx.window.extensions")
                   A: android:required(0x0101028e)=(type 0x12)0x0
                 E: uses-library (line=57)
                   A: android:name(0x01010003)="androidx.window.sidecar" (Raw: "androidx.window.sidecar")
                   A: android:required(0x0101028e)=(type 0x12)0x0
[   +3 ms] executing: /home/greg/Android/Sdk/platform-tools/adb -s 08171FDD40025F shell -x logcat -v time -t 1
[   +8 ms] <- compile package:scroll_overlay/main.dart
[  +62 ms] --------- beginning of main
           02-02 16:16:20.106 D/CHRE    ( 1280): @ 411930.827: [ActivityPlatform] type 6, confidence 41
[   +6 ms] executing: /home/greg/Android/Sdk/platform-tools/adb version
[   +3 ms] Android Debug Bridge version 1.0.41
           Version 33.0.3-8952118
           Installed as /home/greg/Android/Sdk/platform-tools/adb
[   +1 ms] executing: /home/greg/Android/Sdk/platform-tools/adb start-server
[   +4 ms] Building APK
[   +6 ms] Running Gradle task 'assembleDebug'...
[   +1 ms] Using gradle from /home/greg/n/flutter/platform_tests/scroll_overlay/android/gradlew.
[  +14 ms] executing: /home/greg/lib/android-studio-2020.3.1.24/jre/bin/java -version
[  +83 ms] Exit code 0 from: /home/greg/lib/android-studio-2020.3.1.24/jre/bin/java -version
[        ] openjdk version "11.0.15" 2022-04-19
           OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
           OpenJDK 64-Bit Server VM (build 11.0.15+0-b2043.56-8887301, mixed mode)
[   +1 ms] executing: /opt/android-studio/jre/bin/java -version
[  +67 ms] Exit code 0 from: /opt/android-studio/jre/bin/java -version
[        ] openjdk version "11.0.15" 2022-04-19
           OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
           OpenJDK 64-Bit Server VM (build 11.0.15+0-b2043.56-8887301, mixed mode)
[   +1 ms] executing: [/home/greg/n/flutter/platform_tests/scroll_overlay/android/] /home/greg/n/flutter/platform_tests/scroll_overlay/android/gradlew --full-stacktrace --info
-Pverbose=true -Ptarget-platform=android-arm64 -Ptarget=/home/greg/n/flutter/platform_tests/scroll_overlay/lib/main.dart -Pbase-application-name=android.app.Application
-Pdart-defines=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ== -Pdart-obfuscation=false -Ptrack-widget-creation=true -Ptree-shake-icons=false -Pfilesystem-scheme=org-dartlang-root assembleDebug
[ +320 ms] Initialized native services in: /home/greg/.gradle/native
[ +204 ms] The client will now receive all logging from the daemon (pid: 8283). The daemon log file: /home/greg/.gradle/daemon/5.6.2/daemon-8283.out.log
[        ] Starting 15th build in daemon [uptime: 24 mins 23.946 secs, performance: 100%]
[        ] Using 12 worker leases.
[        ] Starting Build
[        ] Settings evaluated using settings file '/home/greg/n/flutter/platform_tests/scroll_overlay/android/settings.gradle'.
[        ] Projects loaded. Root project using build file '/home/greg/n/flutter/platform_tests/scroll_overlay/android/build.gradle'.
[        ] Included projects: [root project 'android', project ':app']
[ +100 ms] > Configure project :app
[        ] Evaluating project ':app' using build file '/home/greg/n/flutter/platform_tests/scroll_overlay/android/app/build.gradle'.
[        ] Creating configuration androidTestUtil
[        ] Creating configuration compile
[        ] Creating configuration apk
[        ] Creating configuration provided
[        ] Creating configuration api
[        ] Creating configuration implementation
[        ] Creating configuration runtimeOnly
[        ] Creating configuration compileOnly
[        ] Creating configuration wearApp
[        ] Creating configuration annotationProcessor
[        ] Creating configuration androidTestCompile
[        ] Creating configuration androidTestApk
[        ] Creating configuration androidTestProvided
[        ] Creating configuration androidTestApi
[        ] Creating configuration androidTestImplementation
[        ] Creating configuration androidTestRuntimeOnly
[        ] Creating configuration androidTestCompileOnly
[        ] Creating configuration androidTestWearApp
[        ] Creating configuration androidTestAnnotationProcessor
[        ] Creating configuration testCompile
[        ] Creating configuration testApk
[        ] Creating configuration testProvided
[        ] Creating configuration testApi
[        ] Creating configuration testImplementation
[        ] Creating configuration testRuntimeOnly
[        ] Creating configuration testCompileOnly
[        ] Creating configuration testWearApp
[        ] Creating configuration testAnnotationProcessor
[        ] Creating configuration debugCompile
[        ] Creating configuration debugApk
[        ] Creating configuration debugProvided
[        ] Creating configuration debugApi
[        ] Creating configuration debugImplementation
[        ] Creating configuration debugRuntimeOnly
[        ] Creating configuration debugCompileOnly
[        ] Creating configuration debugWearApp
[        ] Creating configuration debugAnnotationProcessor
[        ] Creating configuration androidTestDebugCompile
[        ] Creating configuration androidTestDebugApk
[        ] Creating configuration androidTestDebugProvided
[        ] Creating configuration androidTestDebugApi
[        ] Creating configuration androidTestDebugImplementation
[        ] Creating configuration androidTestDebugRuntimeOnly
[        ] Creating configuration androidTestDebugCompileOnly
[        ] Creating configuration androidTestDebugWearApp
[        ] Creating configuration androidTestDebugAnnotationProcessor
[        ] Creating configuration testDebugCompile
[        ] Creating configuration testDebugApk
[        ] Creating configuration testDebugProvided
[        ] Creating configuration testDebugApi
[        ] Creating configuration testDebugImplementation
[        ] Creating configuration testDebugRuntimeOnly
[        ] Creating configuration testDebugCompileOnly
[        ] Creating configuration testDebugWearApp
[        ] Creating configuration testDebugAnnotationProcessor
[        ] Creating configuration releaseCompile
[        ] Creating configuration releaseApk
[        ] Creating configuration releaseProvided
[        ] Creating configuration releaseApi
[        ] Creating configuration releaseImplementation
[        ] Creating configuration releaseRuntimeOnly
[        ] Creating configuration releaseCompileOnly
[        ] Creating configuration releaseWearApp
[        ] Creating configuration releaseAnnotationProcessor
[        ] Creating configuration testReleaseCompile
[        ] Creating configuration testReleaseApk
[        ] Creating configuration testReleaseProvided
[        ] Creating configuration testReleaseApi
[        ] Creating configuration testReleaseImplementation
[        ] Creating configuration testReleaseRuntimeOnly
[        ] Creating configuration testReleaseCompileOnly
[        ] Creating configuration testReleaseWearApp
[        ] Creating configuration testReleaseAnnotationProcessor
[        ] Creating configuration profileCompile
[        ] Creating configuration profileApk
[        ] Creating configuration profileProvided
[        ] Creating configuration profileApi
[        ] Creating configuration profileImplementation
[        ] Creating configuration profileRuntimeOnly
[        ] Creating configuration profileCompileOnly
[        ] Creating configuration profileWearApp
[        ] Creating configuration profileAnnotationProcessor
[        ] Creating configuration testProfileCompile
[        ] Creating configuration testProfileApk
[        ] Creating configuration testProfileProvided
[        ] Creating configuration testProfileApi
[        ] Creating configuration testProfileImplementation
[        ] Creating configuration testProfileRuntimeOnly
[        ] Creating configuration testProfileCompileOnly
[        ] Creating configuration testProfileWearApp
[        ] Creating configuration testProfileAnnotationProcessor
[        ] > Configure project :
[        ] Evaluating root project 'android' using build file '/home/greg/n/flutter/platform_tests/scroll_overlay/android/build.gradle'.
[        ] All projects evaluated.
[        ] Analytics other plugin to proto: Unknown plugin type org.gradle.kotlin.dsl.provider.plugins.KotlinScriptRootPlugin expected enum
ORG_GRADLE_KOTLIN_DSL_PROVIDER_PLUGINS_KOTLINSCRIPTROOTPLUGIN
[        ] Analytics other plugin to proto: Unknown plugin type org.gradle.kotlin.dsl.provider.plugins.KotlinScriptBasePlugin expected enum
ORG_GRADLE_KOTLIN_DSL_PROVIDER_PLUGINS_KOTLINSCRIPTBASEPLUGIN
[        ] Analytics other plugin to proto: Unknown plugin type Flutter_gradle$FlutterPluginKts expected enum FLUTTER_GRADLE$FLUTTERPLUGINKTS
[        ] Analytics other plugin to proto: Unknown plugin type FlutterPlugin expected enum FLUTTERPLUGIN
[        ] Selected primary task 'assembleDebug' from project :
[        ] Tasks to be executed: [task ':app:compileFlutterBuildDebug', task ':app:packLibsflutterBuildDebug', task ':app:preBuild', task ':app:preDebugBuild', task
':app:compileDebugAidl', task ':app:compileDebugRenderscript', task ':app:checkDebugManifest', task ':app:generateDebugBuildConfig', task ':app:cleanMergeDebugAssets', task
':app:mergeDebugShaders', task ':app:compileDebugShaders', task ':app:generateDebugAssets', task ':app:mergeDebugAssets', task ':app:copyFlutterAssetsDebug', task
':app:mainApkListPersistenceDebug', task ':app:generateDebugResValues', task ':app:generateDebugResources', task ':app:mergeDebugResources', task
':app:createDebugCompatibleScreenManifests', task ':app:processDebugManifest', task ':app:processDebugResources', task ':app:compileDebugKotlin', task ':app:javaPreCompileDebug', task
':app:compileDebugJavaWithJavac', task ':app:compileDebugSources', task ':app:processDebugJavaRes', task ':app:mergeDebugJavaResource', task ':app:checkDebugDuplicateClasses', task
':app:desugarDebugFileDependencies', task ':app:mergeExtDexDebug', task ':app:transformClassesWithDexBuilderForDebug', task ':app:mergeDexDebug', task ':app:validateSigningDebug', task
':app:signingConfigWriterDebug', task ':app:mergeDebugJniLibFolders', task ':app:mergeDebugNativeLibs', task ':app:stripDebugDebugSymbols', task ':app:packageDebug', task
':app:assembleDebug']
[   +2 ms] JetifyTransform (Thread[Execution worker for ':',5,main]) started.
[        ] JetifyTransform (Thread[Execution worker for ':' Thread 2,5,main]) started.
[        ] JetifyTransform (Thread[Execution worker for ':' Thread 3,5,main]) started.
[        ] JetifyTransform (Thread[Execution worker for ':' Thread 4,5,main]) started.
[        ] JetifyTransform (Thread[Execution worker for ':' Thread 5,5,main]) started.
[        ] JetifyTransform (Thread[Execution worker for ':' Thread 6,5,main]) started.
[        ] JetifyTransform (Thread[Execution worker for ':' Thread 7,5,main]) started.
[        ] JetifyTransform (Thread[Execution worker for ':' Thread 8,5,main]) started.
[   +1 ms] JetifyTransform (Thread[Execution worker for ':' Thread 10,5,main]) started.
[        ] JetifyTransform (Thread[Execution worker for ':' Thread 11,5,main]) started.
[        ] JetifyTransform (Thread[Daemon worker Thread 7,5,main]) started.
[        ] > Transform artifact kotlin-stdlib-common.jar (org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31) with JetifyTransform
[        ] Transforming artifact kotlin-stdlib-common.jar (org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31) with JetifyTransform
[        ] Caching disabled for JetifyTransform:
/home/greg/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.31/43331609c7de811fed085e0dfd150874b157c32/kotlin-stdlib-common-1.5.31.jar because:
[        ]   Build cache is disabled
[        ] Skipping JetifyTransform:
/home/greg/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.31/43331609c7de811fed085e0dfd150874b157c32/kotlin-stdlib-common-1.5.31.jar as it is up-to-date.
[        ] > Transform artifact kotlin-stdlib-jdk7.jar (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30) with JetifyTransform
[        ] Transforming artifact kotlin-stdlib-jdk7.jar (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30) with JetifyTransform
[   +3 ms] Caching disabled for JetifyTransform:
/home/greg/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.5.30/525f5a7fa6d7790a571c07dd24214ed2dda352fe/kotlin-stdlib-jdk7-1.5.30.jar because:
[        ]   Build cache is disabled
[        ] Skipping JetifyTransform:
/home/greg/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.5.30/525f5a7fa6d7790a571c07dd24214ed2dda352fe/kotlin-stdlib-jdk7-1.5.30.jar as it is up-to-date.

[… copious build logs elided to meet GitHub's length limit …]

[        ] > Transform artifact tracing.aar (androidx.tracing:tracing:1.0.0) with AarTransform
[        ] Transforming artifact tracing.aar (androidx.tracing:tracing:1.0.0) with AarTransform
[        ] Caching disabled for AarTransform: /home/greg/.gradle/caches/transforms-2/files-2.1/d606eb34fbe4f818c2c6052896a24d12/tracing-1.0.0 because:
[        ]   Build cache is disabled
[        ] Skipping AarTransform: /home/greg/.gradle/caches/transforms-2/files-2.1/d606eb34fbe4f818c2c6052896a24d12/tracing-1.0.0 as it is up-to-date.
[        ] AarTransform (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 0.003 secs.
[        ] :app:mergeDebugNativeLibs (Thread[Execution worker for ':' Thread 2,5,main]) started.
[        ] > Task :app:mergeDebugNativeLibs UP-TO-DATE
[        ] Task :app:mergeDebugNativeLibs in app Starting
[        ] Transforming file /home/greg/n/flutter/platform_tests/scroll_overlay/build/app/intermediates/flutter/debug/libs.jar with JetifyTransform
[        ] Transforming file /home/greg/n/flutter/platform_tests/scroll_overlay/build/app/intermediates/flutter/debug/libs.jar with IdentityTransform
[        ] Caching disabled for task ':app:mergeDebugNativeLibs' because:
[        ]   Build cache is disabled
[        ] Skipping task ':app:mergeDebugNativeLibs' as it is up-to-date.
[        ] Task :app:mergeDebugNativeLibs in app Finished
[        ] :app:mergeDebugNativeLibs (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 0.001 secs.
[        ] :app:stripDebugDebugSymbols (Thread[Execution worker for ':' Thread 2,5,main]) started.
[        ] > Task :app:stripDebugDebugSymbols UP-TO-DATE
[        ] Task :app:stripDebugDebugSymbols in app Starting
[        ] android.ndkVersion from module build.gradle is not set
[        ] ndk.dir in local.properties is not set
[        ] ANDROID_NDK_HOME environment variable is not set
[        ] sdkFolder is /home/greg/Android/Sdk
[        ] Considering /home/greg/Android/Sdk/ndk-bundle in SDK ndk-bundle folder
[        ] Considering /home/greg/Android/Sdk/ndk/21.4.7075529 in SDK ndk folder
[        ] Rejected /home/greg/Android/Sdk/ndk-bundle in SDK ndk-bundle folder because that location has no source.properties
[        ] No user requested version, choosing /home/greg/Android/Sdk/ndk/21.4.7075529 which is version 21.4.7075529
[        ] Caching disabled for task ':app:stripDebugDebugSymbols' because:
[        ]   Build cache is disabled
[        ] Skipping task ':app:stripDebugDebugSymbols' as it is up-to-date.
[        ] Task :app:stripDebugDebugSymbols in app Finished
[        ] :app:stripDebugDebugSymbols (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 0.002 secs.
[        ] :app:packageDebug (Thread[Execution worker for ':' Thread 2,5,main]) started.
[        ] > Task :app:packageDebug UP-TO-DATE
[        ] Task :app:packageDebug in app Starting
[        ] Caching disabled for task ':app:packageDebug' because:
[        ]   Build cache is disabled
[        ] Skipping task ':app:packageDebug' as it is up-to-date.
[        ] Task :app:packageDebug in app Finished
[        ] :app:packageDebug (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 0.002 secs.
[        ] :app:assembleDebug (Thread[Execution worker for ':' Thread 2,5,main]) started.
[        ] > Task :app:assembleDebug
[        ] Task :app:assembleDebug in app Starting
[        ] Caching disabled for task ':app:assembleDebug' because:
[        ]   Build cache is disabled
[        ] Task ':app:assembleDebug' is not up-to-date because:
[        ]   Task has not declared any outputs despite executing actions.
[        ] Task :app:assembleDebug in app Finished
[        ] :app:assembleDebug (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 0.098 secs.
[        ] BUILD SUCCESSFUL in 873ms
[        ] 31 actionable tasks: 4 executed, 27 up-to-date
[ +338 ms] Running Gradle task 'assembleDebug'... (completed in 1,438ms)
[   +2 ms] Calculate SHA1: LocalDirectory: '/home/greg/n/flutter/platform_tests/scroll_overlay/build/app/outputs/flutter-apk'/app-debug.apk
[ +579 ms] ✓  Built build/app/outputs/flutter-apk/app-debug.apk.
[   +1 ms] executing: /home/greg/Android/Sdk/build-tools/33.0.1/aapt dump xmltree /home/greg/n/flutter/platform_tests/scroll_overlay/build/app/outputs/flutter-apk/app-debug.apk
AndroidManifest.xml
[   +3 ms] Exit code 0 from: /home/greg/Android/Sdk/build-tools/33.0.1/aapt dump xmltree /home/greg/n/flutter/platform_tests/scroll_overlay/build/app/outputs/flutter-apk/app-debug.apk
AndroidManifest.xml
[        ] N: android=http://schemas.android.com/apk/res/android
             E: manifest (line=2)
               A: android:versionCode(0x0101021b)=(type 0x10)0x1
               A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")
               A: android:compileSdkVersion(0x01010572)=(type 0x10)0x21
               A: android:compileSdkVersionCodename(0x01010573)="13" (Raw: "13")
               A: package="io.flutter.scroll_overlay" (Raw: "io.flutter.scroll_overlay")
               A: platformBuildVersionCode=(type 0x10)0x21
               A: platformBuildVersionName=(type 0x10)0xd
               E: uses-sdk (line=7)
                 A: android:minSdkVersion(0x0101020c)=(type 0x10)0x10
                 A: android:targetSdkVersion(0x01010270)=(type 0x10)0x1c
               E: uses-permission (line=14)
                 A: android:name(0x01010003)="android.permission.INTERNET" (Raw: "android.permission.INTERNET")
               E: application (line=16)
                 A: android:label(0x01010001)="scroll_overlay" (Raw: "scroll_overlay")
                 A: android:icon(0x01010002)=@0x7f080000
                 A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
                 A: android:appComponentFactory(0x0101057a)="androidx.core.app.CoreComponentFactory" (Raw: "androidx.core.app.CoreComponentFactory")
                 E: activity (line=21)
                   A: android:theme(0x01010000)=@0x7f0a0000
                   A: android:name(0x01010003)="io.flutter.scroll_overlay.ScrollOverlayActivity" (Raw: "io.flutter.scroll_overlay.ScrollOverlayActivity")
                   A: android:exported(0x01010010)=(type 0x12)0xffffffff
                   A: android:launchMode(0x0101001d)=(type 0x10)0x1
                   A: android:configChanges(0x0101001f)=(type 0x11)0x40003fb4
                   A: android:windowSoftInputMode(0x0101022b)=(type 0x11)0x10
                   A: android:hardwareAccelerated(0x010102d3)=(type 0x12)0xffffffff
                   E: meta-data (line=36)
                     A: android:name(0x01010003)="io.flutter.embedding.android.NormalTheme" (Raw: "io.flutter.embedding.android.NormalTheme")
                     A: android:resource(0x01010025)=@0x7f0a0001
                   E: intent-filter (line=40)
                     E: action (line=41)
                       A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
                     E: category (line=43)
                       A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")
                 E: meta-data (line=50)
                   A: android:name(0x01010003)="flutterEmbedding" (Raw: "flutterEmbedding")
                   A: android:value(0x01010024)=(type 0x10)0x2
                 E: uses-library (line=54)
                   A: android:name(0x01010003)="androidx.window.extensions" (Raw: "androidx.window.extensions")
                   A: android:required(0x0101028e)=(type 0x12)0x0
                 E: uses-library (line=57)
                   A: android:name(0x01010003)="androidx.window.sidecar" (Raw: "androidx.window.sidecar")
                   A: android:required(0x0101028e)=(type 0x12)0x0
[        ] Stopping app 'app-debug.apk' on Pixel 5.
[        ] executing: /home/greg/Android/Sdk/platform-tools/adb -s 08171FDD40025F shell am force-stop io.flutter.scroll_overlay
[  +79 ms] executing: /home/greg/Android/Sdk/platform-tools/adb -s 08171FDD40025F shell pm list packages io.flutter.scroll_overlay
[  +74 ms] package:io.flutter.scroll_overlay
[   +1 ms] executing: /home/greg/Android/Sdk/platform-tools/adb -s 08171FDD40025F shell cat /data/local/tmp/sky.io.flutter.scroll_overlay.sha1
[  +21 ms] 18a556dff430ae97d52ae3a1f0ce4362c002fc3f
[        ] Latest build already installed.
[        ] executing: /home/greg/Android/Sdk/platform-tools/adb -s 08171FDD40025F shell -x logcat -v time -t 1
[ +133 ms] --------- beginning of main
                    02-02 16:16:25.194 D/InsetsController( 4868): show(ime(), fromIme=true)
[   +6 ms] executing: /home/greg/Android/Sdk/platform-tools/adb -s 08171FDD40025F shell am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x20000000 --ez
enable-dart-profiling true --ez enable-checked-mode true --ez verify-entry-points true io.flutter.scroll_overlay/io.flutter.scroll_overlay.ScrollOverlayActivity
[  +65 ms] Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x20000000 cmp=io.flutter.scroll_overlay/.ScrollOverlayActivity (has extras) }
[        ] Waiting for observatory port to be available...
[ +381 ms] Observatory URL on device: http://127.0.0.1:43231/BeKDRJHAPZs=/
[        ] executing: /home/greg/Android/Sdk/platform-tools/adb -s 08171FDD40025F forward tcp:0 tcp:43231
[   +4 ms] 38865
[        ] Forwarded host port 38865 to device port 43231 for Observatory
[   +4 ms] Caching compiled dill
[  +37 ms] Connecting to service protocol: http://127.0.0.1:38865/BeKDRJHAPZs=/
[ +212 ms] Launching a Dart Developer Service (DDS) instance at http://127.0.0.1:0, connecting to VM service at http://127.0.0.1:38865/BeKDRJHAPZs=/.
[ +229 ms] DDS is listening at http://127.0.0.1:45645/mUYg-ZDncHM=/.
[  +93 ms] Successfully connected to service protocol: http://127.0.0.1:38865/BeKDRJHAPZs=/
[  +65 ms] DevFS: Creating new filesystem on the device (null)
[  +25 ms] DevFS: Created new filesystem on the device (file:///data/user/0/io.flutter.scroll_overlay/code_cache/scroll_overlayYHASOW/scroll_overlay/)
[   +1 ms] Updating assets
[  +61 ms] Syncing files to device Pixel 5...
[   +1 ms] Compiling dart to kernel with 0 updated files
[        ] Processing bundle.
[        ] <- recompile package:scroll_overlay/main.dart 5c5b1ae6-5cb1-49a2-b251-46283a17da67
[        ] <- 5c5b1ae6-5cb1-49a2-b251-46283a17da67
[   +1 ms] Bundle processing done.
[  +53 ms] Updating files.
[        ] DevFS: Sync finished
[        ] Syncing files to device Pixel 5... (completed in 57ms)
[        ] Synced 0.0MB.
[        ] <- accept
[   +5 ms] Connected to _flutterView/0x74f404e040.
[   +1 ms] Flutter run key commands.
[        ] r Hot reload. 🔥🔥🔥
[        ] R Hot restart.
[        ] h List all available interactive commands.
[        ] d Detach (terminate "flutter run" but leave application running).
[        ] c Clear the screen
[        ] q Quit (terminate the application on the device).
[        ] 💪 Running with sound null safety 💪
[        ] An Observatory debugger and profiler on Pixel 5 is available at: http://127.0.0.1:45645/mUYg-ZDncHM=/
[ +493 ms] The Flutter DevTools debugger and profiler on Pixel 5 is available at: http://127.0.0.1:9100?uri=http://127.0.0.1:45645/mUYg-ZDncHM=/
[+5070 ms] Application finished.
Analyzing scroll_overlay...                                             
No issues found! (ran in 5.4s)
[✓] Flutter (Channel main, 3.7.0-13.0.pre.4, on Debian GNU/Linux 10 (buster) 4.19.0-23-amd64, locale en_US.UTF-8)
    • Flutter version 3.7.0-13.0.pre.4 on channel main at /home/greg/n/flutter/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 33e896b475 (6 weeks ago), 2022-12-25 23:14:13 -0800
    • Engine revision 339791f190
    • Dart version 3.0.0 (build 3.0.0-35.0.dev)
    • DevTools version 2.20.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
    • Android SDK at /home/greg/Android/Sdk
    • Platform android-33, build-tools 33.0.1
    • Java binary at: /home/greg/lib/android-studio-2020.3.1.24/jre/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Linux toolchain - develop for Linux desktop
    • clang version 7.0.1-8+deb10u2 (tags/RELEASE_701/final)
    • cmake version 3.13.4
    • ninja version 1.8.2
    • pkg-config version 0.29

[✓] Android Studio (version 2022.1)
    • Android Studio at /home/greg/lib/android-studio-2020.3.1.24
    • Flutter plugin version 71.2.4
    • Dart plugin version 221.6096
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] Android Studio (version 2021.2)
    • Android Studio at /opt/android-studio
    • Flutter plugin version 71.1.2
    • Dart plugin version 212.5744
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] VS Code (version 1.74.3)
    • VS Code at /usr/share/code
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (3 available)
    • Pixel 5 (mobile) • 08171FDD40025F • android-arm64  • Android 13 (API 33)
    • Linux (desktop)  • linux          • linux-x64      • Debian GNU/Linux 10 (buster) 4.19.0-23-amd64
    • Chrome (web)     • chrome         • web-javascript • Google Chrome 109.0.5414.119

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
@gnprice
Copy link
Member Author

gnprice commented Feb 3, 2023

I've done some investigation of this issue already, and have a diagnosis.

Android uses (in OverScroller.java, which is used by RecyclerView) a certain spline curve: time and position are scaled as $t, x \in [0,1]$, and both $t$ and $x$ are cubic functions of an additional parameter $p \in [0,1]$: namely $t = 0.425 p^3 + 0.525 p$ while $x = -1/2 p^3 + 3/2 p$. This curve has $x = 0$ at $t = 0$, and $x = 1$ at $t = 1$.

With the spline curve, to find the scroll position $x$ for a frame at time $t$, one needs to solve the first cubic for $p$ and then put that into the second cubic to find $x$. To avoid having to solve a cubic on each frame, Android's OverScroller precomputes a static table of $x$ for times $t = 0, 0.01, 0.02, \ldots, 0.99, 1$, and does linear interpolation from that.

In ClampingScrollSimulation, we simplify that to a single cubic: $x = (1/.35/3.065) * (1.2 t^3 - 3.27 t^2 + 3.065 t)$. At $t = 0$ this has the correct value $x = 0$. At $t = 1$, however, it has $x \approx 0.92752$. This causes the scroll to end up $1 - x(1) \approx 7.248\%$ short of where the Android scroll physics would take it.

Here's a set of graphs comparing the Android scroll physics and what's in ClampingScrollSimulation, showing both position and velocity over time:

image

So what's needed is to use a curve that better approximates the Android curve. In particular, at $t = 1$ it should have $x = 1$.


There's a bonus issue with the ClampingScrollSimulation curve, which one can see in the above graphs: the scroll does not come to a smooth stop.

Instead the velocity actually increases over the last 200ms or so, before abruptly stopping when the simulation ends. In the Android scroll physics, the velocity decreases continuously to reach zero at the end.

I originally noticed this bonus issue thanks to these graphs; when interacting as a user I'd never put my finger on it. But now that I know about it, it's very conspicuous to me when using scroll_overlay; and I find it noticeable even in a normal app with a long list to scroll through. I suspect that for lots of users the lack of a smooth stop contributes to a feeling that the scrolling isn't quite right, even without them ever identifying specifically why.

To fix this bonus issue and get a smooth stop, we want the curve to have velocity 0 at $t = 1$, i.e. $\frac{\mathrm d x}{\mathrm d t}(1) = 0$, like the Android curve does.

@danagbemava-nc danagbemava-nc added the in triage Presently being triaged by the triage team label Feb 3, 2023
@danagbemava-nc
Copy link
Member

Reproducible using the code sample and steps outlined above.

Labeling based on the information provided above.

recording
telegram-cloud-document-4-5974508209786850387.mp4
flutter doctor -v
[✓] Flutter (Channel stable, 3.7.1, on macOS 13.1 22C65 darwin-arm64, locale en-GB)
    • Flutter version 3.7.1 on channel stable at /Users/nexus/dev/sdks/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 7048ed95a5 (2 days ago), 2023-02-01 09:07:31 -0800
    • Engine revision 800594f1f4
    • Dart version 2.19.1
    • DevTools version 2.20.1

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14C18
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[!] Android Studio (version 2022.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to find bundled Java version.
    • Try updating or re-installing Android Studio.

[!] Android Studio (version 2022.1)
    • Android Studio at /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to find bundled Java version.
    • Try updating or re-installing Android Studio.

[✓] IntelliJ IDEA Community Edition (version 2022.3.2)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.75.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.58.0

[✓] Connected device (4 available)
    • Pixel 7 (mobile)    • adb-28291FDH2001SA-5Lv71w._adb-tls-connect._tcp. • android-arm64  • Android 13 (API 33)
    • M2007J20CG (mobile) • adb-5dd3be00-17AYzd._adb-tls-connect._tcp.       • android-arm64  • Android 12 (API 31)
    • macOS (desktop)     • macos                                            • darwin-arm64   • macOS 13.1 22C65 darwin-arm64
    • Chrome (web)        • chrome                                           • web-javascript • Google Chrome 109.0.5414.119

[✓] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 2 categories.
[!] Flutter (Channel master, 3.8.0-3.0.pre.21, on macOS 13.1 22C65 darwin-arm64, locale en-GB)
    • Flutter version 3.8.0-3.0.pre.21 on channel master at /Users/nexus/dev/sdks/flutters
    ! Warning: `flutter` on your path resolves to /Users/nexus/dev/sdks/flutter/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutters. Consider adding /Users/nexus/dev/sdks/flutters/bin to the front of your path.
    ! Warning: `dart` on your path resolves to /Users/nexus/dev/sdks/flutter/bin/dart, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutters. Consider adding /Users/nexus/dev/sdks/flutters/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision f3effce630 (5 hours ago), 2023-02-03 00:07:10 -0500
    • Engine revision e3fe6dade9
    • Dart version 3.0.0 (build 3.0.0-198.0.dev)
    • DevTools version 2.21.1
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14C18
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[!] Android Studio (version 2022.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to find bundled Java version.
    • Try updating or re-installing Android Studio.

[!] Android Studio (version 2022.1)
    • Android Studio at /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/221.6008.13.2211.9477386/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to find bundled Java version.
    • Try updating or re-installing Android Studio.

[✓] IntelliJ IDEA Community Edition (version 2022.3.2)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.75.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.58.0

[✓] Connected device (4 available)
    • Pixel 7 (mobile)    • adb-28291FDH2001SA-5Lv71w._adb-tls-connect._tcp. • android-arm64  • Android 13 (API 33)
    • M2007J20CG (mobile) • adb-5dd3be00-17AYzd._adb-tls-connect._tcp.       • android-arm64  • Android 12 (API 31)
    • macOS (desktop)     • macos                                            • darwin-arm64   • macOS 13.1 22C65 darwin-arm64
    • Chrome (web)        • chrome                                           • web-javascript • Google Chrome 109.0.5414.119

[✓] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 3 categories.

@danagbemava-nc danagbemava-nc added platform-android Android applications specifically framework flutter/packages/flutter repository. See also f: labels. a: fidelity Matching the OEM platforms better f: scrolling Viewports, list views, slivers, etc. has reproducible steps The issue has been confirmed reproducible and is ready to work on found in release: 3.7 Found to occur in 3.7 found in release: 3.8 Found to occur in 3.8 and removed in triage Presently being triaged by the triage team labels Feb 3, 2023
@gnprice
Copy link
Member Author

gnprice commented Feb 3, 2023

Thanks @danagbemava-nc for that recording! Yes, that exactly.

I plan to send a PR to fix this issue. Before that, I'll send a platform_tests PR or two to update the scroll_overlay test app and to make some changes I've found helpful in investigating.

Before I send a PR, it would be helpful to get some feedback on the possible solutions. I see several options:

  1. We could continue using a cubic, and just choose a higher-fidelity cubic.

    Specifically, we can make it go the same total distance as Android, and also come to a smooth stop. Together with the basic requirements of starting at zero and at the user's initial velocity, that exhausts the flexibility there is in a cubic.

    I haven't yet experimented enough to have a strong view on whether this would be good enough to feel right as a user. I suspect it would not. For example, like the current ClampingScrollSimulation cubic, this curve would have a negative second derivative right from the start — meaning that the scroll would be decelerating at a rapid rate from the beginning. In the Android spline, the deceleration starts at zero. I suspect that difference affects how the scrolling feels as a user.

  2. We could use a higher-degree polynomial that more closely approximates the Android scrolling curve.

    For example, a quartic (a degree-4 polynomial) would let us set the initial deceleration to zero, in addition to the other constraints. At higher and higher degree we can approximate the Android curve more and more closely.

  3. We could use linear interpolation from a table, like Android does, in order to match its curve exactly.

    Android's OverScroller.java computes the table in a static initializer. Dart doesn't have those, and we wouldn't want to compute it at runtime anyway. The way to do this would be to have a const list of numbers, computed once (and with the script to compute them checked in under dev/ so that they aren't completely magic numbers.)

Here's a set of graphs showing Android's curve; the current cubic from main; the cubic from option 1; and a degree-10 polynomial as an example of option 2:
image

You can see that the degree-10 polynomial (in red) hugs the Android spline (in blue) much more closely than either cubic, but still imperfectly.

@gnprice
Copy link
Member Author

gnprice commented Feb 3, 2023

Aha, and just now I've done the code archaeology that I probably should have done sooner, and found the previous work on this issue:

Cc'ing @grouma and @Piinks as the authors of those previous PRs.

(I did try searching the tracker, and missed those; the closest I found was #103762 which is about iOS. But git log widgets/scroll_simulation.dart pulled the relevant history right up.)


I see that both the above PRs went for option 3 from my previous comment: using linear interpolation from a table, in order to go for perfect fidelity. That's the option I was thinking was probably best. I guess those PRs confirm that others agree.

I'll spend some time studying those previous PRs (especially the later version) and the issues that caused the reverts.

@Piinks
Copy link
Contributor

Piinks commented Feb 3, 2023

I'll spend some time studying those previous PRs (especially the later version) and the issues that caused the reverts.

@gnprice thank you very much for your detailed analysis! This has been a challenging issue to resolve. I look forward to hearing what your thoughts are after some research.

@goderbauer goderbauer added the P2 Important issues not at the top of the work list label Feb 7, 2023
@gnprice
Copy link
Member Author

gnprice commented Feb 8, 2023

I'll spend some time studying those previous PRs (especially the later version) and the issues that caused the reverts.

OK, I've now done this. I'm going to file a few more issues reflecting what I've found, then a PR or two with a possible way forward.

gnprice added a commit to gnprice/flutter that referenced this issue Feb 10, 2023
Fixes flutter#120338.
Fixes flutter#119875.
Fixes flutter#113424.

Fixes most of flutter#16371, as the combined symptom of those three.
(There's still flutter#120345, and possibly other contributing factors,
remaining.)

This replaces the implementation of ClampingScrollSimulation with
a new version that better matches the Android scroll physics it's
intended to match.

The new implementation is a version of the Android curve which has
been adjusted so that it behaves in a physically reasonable way,
in order to satisfy an invariant which the Flutter scroll protocol
relies on.

Because the old ClampingScrollSimulation didn't satisfy that
invariant either, it suffered from a bug (flutter#120338) where
restarting the simulation with new metrics would have the side
effect of adding friction, making a fling go about 15% less far.
So this fixes flutter#120338.

The new implementation also goes the same total distance as the
Android scroll physics, whereas the existing version would go about
7% less far (stacking with the 15% reduction when the other issue
was triggered.)  That fixes flutter#119875.

Finally, the new implementation comes to a smooth stop, like Android
does, whereas the existing version would speed slightly up before
abruptly stopping.  That fixes flutter#113424.

The new implementation's curve is the unique curve that both goes the
same total distance as Android's for every possible starting velocity,
and meets the Flutter scroll protocol's ballistic invariant.  So in
that sense this is the canonical way of fixing up the Android behavior
to something physically reasonable, or something that works correctly
in Flutter.
@grouma
Copy link
Member

grouma commented Feb 10, 2023

Incredible write up! Thank you.

Before I landed #77497, I did attempt another approach. I simply updated the cubic approximation to match the boundary conditions and thus have the velocity eventually decelerate to zero. As you noted above, this updated approximation is not truly accurate which I noticed. I then decided to copy the logic which has issues as you also noted.

@gnprice
Copy link
Member Author

gnprice commented Feb 11, 2023

Incredible write up! Thank you.

Thanks!

Before I landed #77497, I did attempt another approach. I simply updated the cubic approximation to match the boundary conditions and thus have the velocity eventually decelerate to zero. As you noted above, this updated approximation is not truly accurate which I noticed. I then decided to copy the logic which has issues as you also noted.

Makes sense. That would have been the same cubic shown in green in my graphs above (#119875 (comment)). It would have fixed this issue and #113424, but #120338 would have still been present, with I think a slightly smaller effect because the initial deceleration would be slightly less.

@danagbemava-nc danagbemava-nc added the r: fixed Issue is closed as already fixed in a newer version label Mar 1, 2023
@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: fidelity Matching the OEM platforms better f: scrolling Viewports, list views, slivers, etc. found in release: 3.7 Found to occur in 3.7 found in release: 3.8 Found to occur in 3.8 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list platform-android Android applications specifically r: fixed Issue is closed as already fixed in a newer version
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants