Rework MyActivity to support Invite and improve UX
Summary
This PR enhances deep link handling in MyActivity by:
- Introducing support for
https://my.home-assistant.io/invite#url=...universal links, directing users to the server onboarding flow with the specified URL. - Improving the user experience for
https://my.home-assistant.io/redirect/...universal links by navigating directly to the relevant content within the app, instead of opening a WebView with a button.
Motivation & Background:
-
Invite Links: To streamline server setup by allowing users to directly onboard via a shared link containing the server URL. The server URL is passed in the URL fragment for security (to prevent it from being sent to
my.home-assistant.io) so we have to manipulate the fragment and transform it into a query. -
Redirect Links UX: Previously,
redirectlinks opened a WebView as a security measure. After discussion with the frontend team, it was determined that since the frontend already validates these links and user interaction is expected, a more seamless in-app navigation is preferable. This change also ensures these links work even ifmy.home-assistant.iois temporarily unavailable or the user doesn't have internet (on their local network). -
Task Affinity Bug: Resolved an issue where
MyActivity, due to itsstandardlaunchMode, would incorrectly appear as part of the calling app's task (e.g., Home Assistant appearing within Google Keep's task in the recents screen).MyActivitynow correctly launches in its own task. - URL Parameter Encoding: Dedicated effort was made to ensure URLs with percent-encoded parameters are handled correctly throughout the linking process, preventing the generation of invalid URLs from valid incoming links.
Impact:
- Users can now be invited to a Home Assistant instance via a simple link, automatically pre-filling the server URL for onboarding.
- Navigating via
redirectlinks frommy.home-assistant.iowill feel more integrated, taking users directly to the content within the app. - Fixes a bug where the app could be incorrectly grouped with the launching app in the Android task switcher.
Checklist
- [x] New or updated tests have been added to cover the changes following the testing guidelines.
- [x] The code follows the project's code style and best_practices.
- [x] The changes have been thoroughly tested, and edge cases have been considered.
- [x] Changes are backward compatible whenever feasible. Any breaking changes are documented in the changelog for users and/or in the code for developers depending on the relevance.
Screenshots
Before: Home Assistant shown as part of the calling app's task (e.g., Google Keep) and opening a WebView. https://github.com/user-attachments/assets/0982b09d-032b-4e89-bed7-015c4086ee51
Now: Home Assistant correctly opens in its own task and supports invite without opening an intermediate WebView. https://github.com/user-attachments/assets/6e42f506-0e58-4a1c-ac41-dba62ed5bd65
Any other notes
It was added on iOS in https://github.com/home-assistant/iOS/pull/3591 using deep link but I prefered the universal link way since it feels more native.
FailFast has been extended to add a simpler method to handle more cases.
This functionality mirrors a similar feature added on iOS (see https://github.com/home-assistant/iOS/pull/3591), though this PR implements it using Android Universal Links for a more native feel compared to custom URL schemes.
The FailFast utility has been extended with a simpler method fail to cover more use cases.
I made a mistake in the implementation it should support deep link rather than universal link, that is different from the iOS impl. It means that it doesn't open the my website.
Also another mistake is that I should treat the fragment as an URI not using simple string manipulation.
I decided to make it better and introduce another class that will be agnostic from the activity so that I can write Unit Test about it. I don't think it needs to be a ViewModel but it could.
Test Results
43 files 43 suites 4m 27s ⏱️ 142 tests 142 ✅ 0 💤 0 ❌ 152 runs 152 ✅ 0 💤 0 ❌
Results for commit 9179ef9c.
:recycle: This comment has been updated with latest results.
is there an easy way to test this? For some reason the debug build does not register teh deep links nor allows me to select them, so the browser keeps opening telling me to install the app.
Testing this by saving links in gmail and clicking on them to trigger the process
It's because your production app already captures the links. We should have universal links for debug but that's a bigger task.
This seems incomplete to me for the flow where a user is completely new and doesn't have the app. My page opens in browser (because there is no app) > user taps Google Play badge to install the app > user returns to browser > tapping 'Accept invite' doesn't do anything because you haven't added support for homeassistant://invite#url=http%3A%2F%2Fhomeassistant.local%3A8123. So this either needs a change on the my page, or in the app. I'm guessing changing the app is easier and backwards compatible ;)