Skip to content
Open
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 99 additions & 19 deletions Sources/CarPlay/OACarPlayDashboardInterfaceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ @implementation OACarPlayDashboardInterfaceController
int _calculationProgress;

CPMapButton *_3DModeMapButton;
BOOL _lastIs3DMode;
BOOL _wasIn3DBeforePreview;

OAAutoObserverProxy *_locationUpdateObserver;
Expand Down Expand Up @@ -155,7 +156,9 @@ - (void) enterBrowsingState
_mapTemplate.trailingNavigationBarButtons = @[panningButton];
_mapTemplate.leadingNavigationBarButtons = @[[self createBarButton:EOACarPlayButtonTypeSettings], [self createBarButton:EOACarPlayButtonTypeDirections]];

_3DModeMapButton = [self createMapButton:EOACarPlayButtonType3D];
BOOL is3DMode = [OAMapViewTrackingUtilities.instance is3DMode];
_lastIs3DMode = is3DMode;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to store is3DMode in _lastIs3DMode here? How will it behave if the 2D/3D mode is changed from the phone while CarPlay is connected?

_3DModeMapButton = [self createMapButton:EOACarPlayButtonType3D is3DMode:is3DMode];
_mapTemplate.mapButtons = @[_3DModeMapButton, [self createMapButton:EOACarPlayButtonTypeCenterMap], [self createMapButton:EOACarPlayButtonTypeZoomIn], [self createMapButton:EOACarPlayButtonTypeZoomOut]];
[self onMap3dModeUpdated];
}
Expand Down Expand Up @@ -351,6 +354,7 @@ - (void) enterRoutePreviewMode:(BOOL)shouldCheckConnectedMainScene
destinationSubtitle = nil;
}

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 260400

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Xcode 26.2 Fix

if (@available(iOS 26.4, *)) {
CPLocationCoordinate3D startPoint = {
.latitude = startCoord.latitude,
Expand Down Expand Up @@ -385,7 +389,10 @@ - (void) enterRoutePreviewMode:(BOOL)shouldCheckConnectedMainScene
_currentTrip = [[CPTrip alloc] initWithOriginWaypoint:origin
destinationWaypoint:destination
routeChoices:@[routeChoice]];
} else {
}
else
#endif
{

NSMutableDictionary<NSString *, NSString *> *addressDict = [NSMutableDictionary dictionary];

Expand Down Expand Up @@ -469,27 +476,102 @@ - (void)openNavigation
[directionsGrid present];
}

- (void)updateMapButton:(CPMapButton *)mapButton

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move this into a common image helper and pass whether the image should use template rendering? This would avoid having separate [UIImage templateImageNamed:] and [UIImage imageNamed:] branches here.

+ (UIImage *)imageNamed:(NSString *)imageName template:(BOOL)template
{
    return template
        ? [UIImage templateImageNamed:imageName]
        : [UIImage imageNamed:imageName];
}

forType:(EOACarPlayButtonType)type
is3DMode:(BOOL)is3DMode
{
UIImage *image = nil;
if (@available(iOS 26.0, *))
{
switch (type)
{
case EOACarPlayButtonTypeZoomIn:
image = [UIImage templateImageNamed:ACImageNameIcCustomMapZoomIn];
break;
case EOACarPlayButtonTypeZoomOut:
image = [UIImage templateImageNamed:ACImageNameIcCustomMapZoomOut];
break;
case EOACarPlayButtonTypeCenterMap:
image = [UIImage templateImageNamed:ACImageNameIcCustomMapLocationPosition];
break;
case EOACarPlayButtonType3D:
image = [UIImage templateImageNamed:is3DMode ? ACImageNameIcCustom2D : ACImageNameIcCustom3D];
break;
default:
break;
}
}
else
{
switch (type)
{
case EOACarPlayButtonTypeZoomIn:
image = [UIImage imageNamed:ACImageNameBtnMapZoomIn];
break;
case EOACarPlayButtonTypeZoomOut:
image = [UIImage imageNamed:ACImageNameBtnMapZoomOut];
break;
case EOACarPlayButtonTypeCenterMap:
image = [UIImage imageNamed:ACImageNameBtnMapCurrentLocation];
break;
case EOACarPlayButtonType3D:
image = [UIImage imageNamed:is3DMode ? ACImageNameBtnMap2DMode : ACImageNameBtnMap3DMode];
break;
default:
break;
}
}
mapButton.image = image;
}

- (void)replace3DModeMapButton:(CPMapButton *)mapButton
{
NSUInteger buttonIndex = [_mapTemplate.mapButtons indexOfObjectIdenticalTo:_3DModeMapButton];
if (buttonIndex == NSNotFound)
return;

NSMutableArray<CPMapButton *> *mapButtons = _mapTemplate.mapButtons.mutableCopy;
mapButtons[buttonIndex] = mapButton;
_3DModeMapButton = mapButton;
_mapTemplate.mapButtons = mapButtons;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to recreate CPMapButton on iOS 26 when switching between 2D and 3D? If this is required because CarPlay caches the automatically generated focused image, could we document that workaround here? Otherwise, updating the existing button’s image would avoid replacing the entire mapButtons array

}

- (void)onMap3dModeUpdated
{
if (_3DModeMapButton)
{
dispatch_async(dispatch_get_main_queue(), ^{
OAMapViewTrackingUtilities *mapViewTrackingUtilities = [OAMapViewTrackingUtilities instance];
BOOL is3DMode = [mapViewTrackingUtilities is3DMode];
Map3DModeVisibility map3DMode = [[[OAMapButtonsHelper sharedInstance] getMap3DButtonState] getVisibility];
BOOL hideButton = map3DMode == Map3DModeVisibilityHidden
|| (map3DMode == Map3DModeVisibilityVisibleIn3DMode && ![mapViewTrackingUtilities is3DMode]);
_3DModeMapButton.hidden = hideButton ? YES : NO;
if ([mapViewTrackingUtilities is3DMode])
|| (map3DMode == Map3DModeVisibilityVisibleIn3DMode && !is3DMode);
BOOL shouldRecreateButton = NO;
if (@available(iOS 26.0, *))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The button creation logic is also unclear

{
BOOL isButtonPresented = [_mapTemplate.mapButtons indexOfObjectIdenticalTo:_3DModeMapButton] != NSNotFound;
shouldRecreateButton = _lastIs3DMode != is3DMode && isButtonPresented;
}
_lastIs3DMode = is3DMode;

CPMapButton *mapButton = shouldRecreateButton
? [self createMapButton:EOACarPlayButtonType3D is3DMode:is3DMode]
: _3DModeMapButton;
if (!shouldRecreateButton)
[self updateMapButton:mapButton forType:EOACarPlayButtonType3D is3DMode:is3DMode];
mapButton.hidden = hideButton;
if (is3DMode)
{
_3DModeMapButton.image = [UIImage imageNamed:@"btn_map_2d_mode"];
_3DModeMapButton.accessibilityLabel = OALocalizedString(@"map_3d_mode_action");
mapButton.accessibilityLabel = OALocalizedString(@"map_3d_mode_action");
}
else
{
_3DModeMapButton.image = [UIImage imageNamed:@"btn_map_3d_mode"];
_3DModeMapButton.accessibilityLabel = OALocalizedString(@"map_2d_mode_action");
mapButton.accessibilityLabel = OALocalizedString(@"map_2d_mode_action");
}
_3DModeMapButton.accessibilityValue = [Map3DModeVisibilityWrapper getTitleForType:map3DMode];
mapButton.accessibilityValue = [Map3DModeVisibilityWrapper getTitleForType:map3DMode];

if (shouldRecreateButton)
[self replace3DModeMapButton:mapButton];
});
}
}
Expand Down Expand Up @@ -607,7 +689,12 @@ - (void)openFindParkingWithCompletion:(dispatch_block_t)completion
completion();
}

- (CPMapButton *) createMapButton:(EOACarPlayButtonType)type
- (CPMapButton *)createMapButton:(EOACarPlayButtonType)type
{
return [self createMapButton:type is3DMode:[OAMapViewTrackingUtilities.instance is3DMode]];
}

- (CPMapButton *)createMapButton:(EOACarPlayButtonType)type is3DMode:(BOOL)is3DMode
{
CPMapButton *mapButton = [[CPMapButton alloc] initWithHandler:^(CPMapButton * _Nonnull mapButton) {
switch (type) {
Expand Down Expand Up @@ -636,14 +723,7 @@ - (CPMapButton *) createMapButton:(EOACarPlayButtonType)type
}
}];

if (type == EOACarPlayButtonTypeZoomIn)
mapButton.image = [UIImage imageNamed:@"btn_map_zoom_in"];
else if (type == EOACarPlayButtonTypeZoomOut)
mapButton.image = [UIImage imageNamed:@"btn_map_zoom_out"];
else if (type == EOACarPlayButtonTypeCenterMap)
mapButton.image = [UIImage imageNamed:@"btn_map_current_location"];
else if (type == EOACarPlayButtonType3D)
mapButton.image = [UIImage imageNamed:[OAMapViewTrackingUtilities.instance is3DMode] ? @"btn_map_2d_mode" : @"btn_map_3d_mode"];
[self updateMapButton:mapButton forType:type is3DMode:is3DMode];

return mapButton;
}
Expand Down