On some Samsung devices Flutter with spell-check enabled will crash when typing/moving near the ">" character.
Stack trace is
```
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.textservice.SentenceSuggestionsInfo.getSuggestionsCount()' on a null object reference
at io.flutter.plugin.editing.SpellCheckPlugin.onGetSentenceSuggestions(SpellCheckPlugin.java:26)
at android.view.textservice.SpellCheckerSession.lambda$handleOnGetSentenceSuggestionsMultiple$1$android-view-textservice-SpellCheckerSession(SpellCheckerSession.java:224)
at android.view.textservice.SpellCheckerSession$$ExternalSyntheticLambda0.run(:4)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8747)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
```
## Description
This reverts commit 879917b to re-land #40542 to fix the lint warning which caused the original PR to be reverted (the lint warnings were turned on after the original was landed, which is why it wasn't caught earlier).
## Description
This PR updates `BasicMessageChannel.resizeChannelBuffer` implementation. Previous implementation builds a wrong `ByteBuffer` and was not tested so it is difficult to know when it stopped working.
## Related Issue
Fixes https://github.com/flutter/flutter/issues/126632
## Tests
Adds 1 test.
Fixes https://github.com/flutter/flutter/issues/101569
This block of code was originally introduced in https://github.com/flutter/engine/pull/15560 , but removing it does not have any affect on the software text editing controls in GBoard.
Before this change
* shift + arrow right/left selection would collapse after releasing the shift key.
* shift + mouse click to expand selection would collapse after releasing the shift key.
After this change
* shift key up no longer collapses the selection.
Fixes b/282290672
Google Testing currently does not support vulkan, and constructors like
this need to be behind a flag.
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I added new tests to check the change I am making or feature I am
adding, or Hixie said the PR is test-exempt. See [testing the engine]
for instructions on writing and running engine tests.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I signed the [CLA].
- [x] All existing and new tests are passing.
Noticed this while working on https://github.com/flutter/flutter/issues/124181
In Impeller right now, Android creates a context for each surface - but in Skia, Android creates one context and shares it across surfaces. For the multiple-engine scenario this matters. This also makes it possible for Android to provide the impeller::Context independently of surface creation.
## Description
In https://github.com/flutter/engine/pull/41702, the default state of the focus bit is "false", assuming that Android will send an `onWindowFocusChanged(true)` when the window is first focused, but there appear to be some cases where that doesn't happen.
This change puts the initial state back to what it used to be: in the absence of focus change events, entering the "onResume" Android state will report the `resumed` state in Flutter. Before this PR, and after https://github.com/flutter/engine/pull/41702, if no focus events were received, it would default to `inactive`.
## Tests
- Updated tests to match.
Fixes https://github.com/flutter/flutter/issues/123307 - for Android, iOS, and Web, for the main display only (https://github.com/flutter/flutter/issues/125938 tracks supporting multiple displays, https://github.com/flutter/flutter/issues/125939 for desktop).
Desktop will need to be implemented for this, but given priority for a couple of our customers targetting foldable devices on Android I'm inclined to get this in before desktop can be finished.
The main concern for this right now is that on some Android foldable devices, setting a preferred orientation will cause letterboxing and the `MediaQuery` will _never_ get the full screen size when unfolded. This causes apps to think the screen is smaller than it is, as they've mainly been using `MediaQueryData.size` to figure this out. Android's recommendation is to not set a preferred orientation, and if you must to use the new method introduced in `ViewUtil.java` to calculate the maximal window size.
## Description
This reverts commit e49577708d9d5315fa6c001d7dc20ee80d04cd35 to re-land #41094 because the Google test failures have been fixed. There are no changes to the original PR, since the fixes were in the Google code.
Typically the AndroidShellHolder's apk_asset_provider_ is set by AndroidShellHolder::Launch when the DartExecutor runs the engine's entrypoint.
But if the engine was started by Spawn, then the apk_asset_provider_ was not being set. This would cause a crash if the resulting engine was later used to spawn another engine.
Fixes https://github.com/flutter/flutter/issues/122364
## Description
This incorporates additional signal from `Activity.onWindowFocusChanged` to help decide if the application is `resumed` or `inactive`.
When the user pulls down the notification shade or opens the app switcher in iOS, then iOS sends a notification to the application that it no longer has input focus (is no longer "active" in Apple terminology).
However, Android (at least on a Pixel) doesn't send `onPause` and `onResume` events for these things, as one might expect. Instead, this PR changes things so that we listen to `Activity.onWindowFocusChanged` and see if any of the windows still have focus.
If it doesn't have focus, then the lifecycle switches to `inactive` (even if `onPause` hasn't been called), and if it does have focus (and `onResume` hasn't been called) then we should go to `resumed`.
State changes are determined and deduped in the `LifecycleChannel` class.
Here's the old state table:
| Android State | Flutter state |
| ------------- | ------------- |
| Resumed | resumed |
| Paused | inactive |
| Stopped | paused |
| Detached | detached |
Here's the new state table:
| Android State | Window focused | Flutter state |
| ------------- | ------------- | ------------- |
| Resumed | true | resumed |
| Resumed | false | _inactive_ * |
| Paused | true | inactive |
| Paused | false | inactive |
| Stopped | true | paused |
| Stopped | false | paused |
| Detached | true | detached |
| Detached | false | detached |
* = This is the relevant change in this PR.
("Window focused" means one or more windows managed by Flutter are focused)
The `inactive` state is for when the application is running and visible, but doesn't have the input focus. An example where this currently happens are when a phone call is in progress on top of the app, or on some OEMs when going into the app switcher (I've tested on Realme and it does that, at least). With the PR, it will also go into `inactive` when the app has lost input focus, but is still in the Android `onResume` state. This means that on phones that don't pause the app when they go into the app switcher or the notification window shade (Pixel, others), the app will go into `inactive` when it didn't before. If developers weren't doing anything special in the `inactive` state before, then this PR will have no change for them. If they were, they will go into that state more often (but more consistently across OEMs).
## Related Issues
- Fixes https://github.com/flutter/flutter/issues/124591
## Tests
- Added unit tests for handling `onWindowFocusChanged`.
Issue fixed by this PR: https://github.com/flutter/flutter/issues/110138
This PR fixes an issue which is causing app crash when User tries to navigate to a new instance **FlutterFragment** (whose old instance is already present in the fragment backstack) in an Activity (which was restored to saved state after being killed in background due to memory pressure).
Detailed case to reproduce the crash and identify its' root cause:
Setup: Let's say we've an Activity1 which has a bottom nav bar with 3 tabs. Each of this 3 tabs are **FlutterFragment** i.e. Fragment1, Fragment2 & Fragment3 and all of them are using separate **FlutterEngine** but all of them will be cached. e.g. Multiple instances of **Fragment1** will be going to use same cached **FlutterEngine1**.
1. When User opens the app, Fragment1 gets added to fragment backstack
2. Then User navigates to Fragment2 (gets added to backstack as well)
3. Then User navigates to Fragment3 (gets added to backstack as well)
4. Then User puts the app in background. Due to memory pressure OS/platform kills the Activity1 and all 3 FlutterFragments while the app is in background.
5. Then after sometime User tries to bring the app to foreground from the app stack. Since Activity1 was killed by the OS/platform the app process will try to restore the Activity1 in the same state it was before it got killed. This leads to all 3 fragments present in backstack to get instantiated and then the **onAttach()** gets called for all 3, but only Fragment3 gets **onCreateView()** lifecycle event as it was the top most visible Fragment before the FragmentManager saved the state and app went into background. All 3 FlutterFragment goes through following function calls.
FlutterFragment.onAttach() -> FlutterActivityAndFragmentDelegate.onAttach(). There is a one-to-one mapping between **FlutterFragment <-> FlutterActivityAndFragmentDelegate**
<img width="977" alt="1" src="https://user-images.githubusercontent.com/8373036/231222642-1596c77c-d127-476b-9bce-8ad2e9cd3639.png">
FlutterActivityAndFragmentDelegate.onAttach() -> FlutterEngineConnectionRegistry.attachToActivity(). There is a one-to-one mapping between **FlutterEngine <-> FlutterEngineConnectionRegistry**. _**NOTE**: THIS IS VERY IMPORTANT POINT TO KEEP IN MIND TO UNDERSTAND THE ROOT CAAUSE OF THIS CRASH._
<img width="962" alt="2" src="https://user-images.githubusercontent.com/8373036/231222672-016ee708-c310-49c8-8016-070b6057af7b.png">
Since all the 3 **FlutterFragment** were just instantiated on activity restore **exclusiveActivity** will be null and exclusiveActivity will be assigned the host **FlutterActivityAndFragmentDelegate**.
<img width="880" alt="3" src="https://user-images.githubusercontent.com/8373036/231241491-c47f5aa6-96e9-4c1f-b92e-7cfed67381e2.png">
6. Then FlutterFragment.onCreateView() will be called only for Fragment3 and it will be visible without an issue as its' state gets restored properly.
7. Then if User tries to navigate to Fragment2 via instantiating new instance of it (this means that now there will be two instances of Fragment2 in the backstack), then there will be crash as it'll go through following function calls.
FlutterFragment.onAttach() -> FlutterActivityAndFragmentDelegate.onAttach().
<img width="977" alt="1" src="https://user-images.githubusercontent.com/8373036/231222642-1596c77c-d127-476b-9bce-8ad2e9cd3639.png">
FlutterActivityAndFragmentDelegate.onAttach() -> FlutterEngineConnectionRegistry.attachToActivity().
<img width="962" alt="2" src="https://user-images.githubusercontent.com/8373036/231222672-016ee708-c310-49c8-8016-070b6057af7b.png">
THIS IS WHERE THE CRASH STARTS. Since this is the second instance of Fragment2 and both instances are going to use the same cached **FlutterEngine** and hence same **FlutterEngineConnectionRegistry**, this time around **exclusiveActivity** will be non-null as it was assigned during step 5. And since exclusiveActivity will be be non null it'll try to detach from the old **ExclusiveAppComponent** via calling **exclusiveActivity.detachFromFlutterEngine()**.
<img width="878" alt="7" src="https://user-images.githubusercontent.com/8373036/231241550-09908108-1747-4ec3-bc70-145446b86eae.png">
FlutterActivityAndFragmentDelegate.detachFromFlutterEngine() -> FlutterFragment.detachFromFlutterEngine()
<img width="905" alt="4" src="https://user-images.githubusercontent.com/8373036/231222702-5ee739f2-fd71-4e20-807d-e3786e6f27fc.png">
FlutterFragment.detachFromFlutterEngine() -> FlutterActivityAndFragmentDelegate.onDestroyView(). This ideally should not be called if the hosts' **FlutterFragments.onCreateView()** was not called in the first place. Also since the previous author has added **// Redundant calls are ok.** comment, I'm guessing that this is just a fallback cleanup.
<img width="902" alt="5" src="https://user-images.githubusercontent.com/8373036/231222719-2ea28157-bd62-45fe-89ef-dd41ee7b3cca.png">
THIS IS WHERE THE CRASH HAPPENS. FlutterActivityAndFragmentDelegate.onDestroyView() -> FlutterView.detachFromFlutterEngine(). Since the lifecycle of older instance of this FlutterFragment2 was capped at onAttach(), it's **FlutterView** property will be null and calling FlutterView.detachFromFlutterEngine() will throw NPE.
<img width="902" alt="6" src="https://user-images.githubusercontent.com/8373036/231222735-55b63911-6a2d-4967-8043-298f4d413f2a.png">
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Reverts flutter/engine#40746
Googler bug: b/278174021
Failing on
```
shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java:239: Error: This method should only be accessed from tests or within private scope [VisibleForTests]
imeSyncCallback.remove();
```
This PR makes view ID signed from unsigned int64.
Initially, I made view IDs unsigned because they were opaque anyway. As
I'm working deeper into multiview, I found some issues that made me
think signed is better:
* Unsigned integers are worse
* Sometimes you want negative values to represent special values.
* Unsigned integers are dangerous (if compared with signed ones by
mistake.)
* Unsigned integers are not needed
* We're very unlikely to reach that big anyway.
* Almost all other languages support only signed integers.
* Also JavaScript only supports up to 51 bits of integer.
Therefore I think it's better to change them to signed int64, especially
before these APIs are widely used by developers.
## Pre-launch Checklist
- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I added new tests to check the change I am making or feature I am
adding, or Hixie said the PR is test-exempt. See [testing the engine]
for instructions on writing and running engine tests.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I signed the [CLA].
- [ ] All existing and new tests are passing.
If you need help, consider asking for advice on the #hackers-new channel
on [Discord].
<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[C++, Objective-C, Java style guides]:
https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
[testing the engine]:
https://github.com/flutter/flutter/wiki/Testing-the-engine
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat