[iOS] Dynamically populate target devices in Share Sheet
This CL implements the dynamic population of individual device-specific send targets directly into the iOS native Share Sheet.
It updates ActivityServiceCoordinator to retrieve the user's first name from their Google Account via the IdentityManager and pass it to the mediator. The ActivityServiceMediator is updated to fetch the active target devices from the SendTabToSelfSyncService. When the kSendTabToSelfIOSShareSheetDeviceList feature flag is enabled and devices are available, it generates one SendTabToSelfActivity per device.
Each activity is dynamically formatted as "[First name] • [Device model]" (e.g. "Michael • MacBook Pro") with a custom monochrome icon matching its form factor. When clicked, it routes directly to the direct-send coordinator pipeline, bypassing the bottom sheet picker.
[iOS] Support device-specific mode in SendTabToSelfActivity
This CL introduces a new device-specific initialization mode to SendTabToSelfActivity, allowing it to represent a single, specific target device in the Share Sheet.
It implements a convenience initializer to pass the target device name, cache GUID, and form factor. It updates the activity to dynamically set its title to "Send to [Device Name]" and resolve its monochrome icon to a phone, tablet, or laptop symbol matching the device's form factor.
In addition, the activity's execution is updated to trigger the direct-send coordinator command when targeting a specific device. Unit tests are added to verify the dynamic titles, icons, and direct-send routing.
[iOS] Add Send Tab to Self Share Sheet flag, dependency injection, and direct-send pipeline
This CL introduces the kSendTabToSelfIOSShareSheetDeviceList feature flag to control the rollout of dynamic device targets in the native iOS Share Sheet.
It updates ActivityServiceMediator to accept SendTabToSelfSyncService as a dependency (cleaning up and utilizing a pre-existing unused import).
It also adds a direct-send command to BrowserCoordinatorCommands, allowing a tab to be sent directly to a specific target device cache GUID without presenting the device picker UI. The SendTabToSelfCoordinator is updated to execute the send transaction asynchronously, extracting scroll position and form fields, and displaying the post-send snackbar upon completion.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
if (self.userGivenName.length > 0) {
activityTitle = [NSString
stringWithFormat:@"%@ • %@", self.userGivenName, rawDeviceName];
}This needs to be adjusted. It doesn't work well i18n
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
if (self.userGivenName.length > 0) {
activityTitle = [NSString
stringWithFormat:@"%@ • %@", self.userGivenName, rawDeviceName];
}This needs to be adjusted. It doesn't work well i18n
Done
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +1 |
formatted as [First Name] • [Device Model], enabling direct one-tap tabDo you know if the desired format has been decided? I ask because the Android implementation currently only uses "device model", but I still have a TODO to follow up on this.
da39a3ee5e6b4b0d3255bfef95601890afd80709This image doesn't seem to exist on the server?
// the picker UI even when dynamic target activities are available.I think we should also clarify whether there should be a limit to the number of devices. On Android, we limited it to 2, so as to not overcrowd this row. (I'm not sure what other competing entries there are in the iOS share sheet - on Android there are typically lots!)
]);
SendTabToSelfShareActivity* phone_activity = activities[2];
SendTabToSelfShareActivity* tablet_activity = activities[3];
SendTabToSelfShareActivity* desktop_activity = activities[4];
EXPECT_NSEQ(@"Michael • Phone", [phone_activity activityTitle]);
EXPECT_NSEQ(@"Michael • Tablet", [tablet_activity activityTitle]);
EXPECT_NSEQ(@"Michael • Desktop", [desktop_activity activityTitle]);I was wondering whether the ordering actually works out like this here, since "desktop" might actually have a slightly larger timestamp than "tablet" or "phone". It does, because the fake model returns the devices in the order they were added...
Maybe using `SetTargetDeviceInfoSortedList` instead of adding the devices one by one would make the ordering clearer?
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
initWithHandler:self.handlerThe pattern of collecting multiple protocols into a single handler is long-deprectated (and I thought all of them had been cleaned up).
Even if fixing this coordinator's 'handler' property is out of scope for this CL, since you're changing the mediator, it should have separate BrowserCooordinator and FindInPage handlers (assuming it needs both -- if not, it should just have the one it needs, clearly named as such).
namespace {I'd like to manage scope creep in both the mediator and coordinator for the activity service; this is an OS-supplied gateway to a bunch of internal Chrome features, so ideally as much feature-specific code as possible should be moved out of these classes and into classes or utility files that are local to those features. This keeps all of the logic related to each feature collected together, and it keeps this mediator and its associated coordinator more readable.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
formatted as [First Name] • [Device Model], enabling direct one-tap tabDo you know if the desired format has been decided? I ask because the Android implementation currently only uses "device model", but I still have a TODO to follow up on this.
I've checked with UXW and this format is indeed the one we want!
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |