Skip to content

Commit

Permalink
Merge pull request #1106 from smartdevicelink/feature/issue_1062_stat…
Browse files Browse the repository at this point in the history
…ic_icon_sdlartwork_support

[SDL-0196] Support Static Icon in Screen Manager
  • Loading branch information
joeljfischer authored Nov 29, 2018
2 parents aea9cab + 1c34752 commit 2bf35ff
Show file tree
Hide file tree
Showing 22 changed files with 287 additions and 140 deletions.
2 changes: 1 addition & 1 deletion Example Apps/Example ObjC/ButtonManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ - (void)setToggleEnabled:(BOOL)toggleEnabled {
}

- (SDLSoftButtonObject *)sdlex_softButtonAlertWithManager:(SDLManager *)manager {
SDLSoftButtonState *alertImageAndTextState = [[SDLSoftButtonState alloc] initWithStateName:AlertSoftButtonImageState text:AlertSoftButtonText image:[[UIImage imageNamed:AlertBWIconName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
SDLSoftButtonState *alertImageAndTextState = [[SDLSoftButtonState alloc] initWithStateName:AlertSoftButtonImageState text:AlertSoftButtonText artwork:[SDLArtwork artworkWithImage:[[UIImage imageNamed:CarBWIconImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] asImageFormat:SDLArtworkImageFormatPNG]];
SDLSoftButtonState *alertTextState = [[SDLSoftButtonState alloc] initWithStateName:AlertSoftButtonTextState text:AlertSoftButtonText image:nil];

__weak typeof(self) weakself = self;
Expand Down
2 changes: 1 addition & 1 deletion Example Apps/Example ObjC/PerformInteractionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ - (SDLChoiceSet *)choiceSet {
}

- (NSArray<SDLChoiceCell *> *)cells {
SDLChoiceCell *firstChoice = [[SDLChoiceCell alloc] initWithText:PICSFirstChoice];
SDLChoiceCell *firstChoice = [[SDLChoiceCell alloc] initWithText:PICSFirstChoice artwork:[SDLArtwork artworkWithStaticIcon:SDLStaticIconNameKey] voiceCommands:nil];
SDLChoiceCell *secondChoice = [[SDLChoiceCell alloc] initWithText:PICSSecondChoice];
SDLChoiceCell *thirdChoice = [[SDLChoiceCell alloc] initWithText:PICSThirdChoice];

Expand Down
6 changes: 3 additions & 3 deletions Example Apps/Example Swift/PerformInteractionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ class PerformInteractionManager: NSObject {
private extension PerformInteractionManager {
/// The PICS menu items
var choiceCells: [SDLChoiceCell] {
let firstChoice = SDLChoiceCell(text: PICSFirstChoice, artwork: nil, voiceCommands: nil)
let secondChoice = SDLChoiceCell(text: PICSSecondChoice, artwork: nil, voiceCommands: nil)
let thirdChoice = SDLChoiceCell(text: PICSThirdChoice, artwork: nil, voiceCommands: nil)
let firstChoice = SDLChoiceCell(text: PICSFirstChoice, artwork: SDLArtwork(staticIcon: .key), voiceCommands: nil)
let secondChoice = SDLChoiceCell(text: PICSSecondChoice)
let thirdChoice = SDLChoiceCell(text: PICSThirdChoice)
return [firstChoice, secondChoice, thirdChoice]
}

Expand Down
26 changes: 26 additions & 0 deletions SmartDeviceLink/SDLArtwork.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#import <UIKit/UIKit.h>

#import "SDLFile.h"
#import "SDLStaticIconName.h"

@class SDLImage;

typedef NS_ENUM(NSUInteger, SDLArtworkImageFormat) {
SDLArtworkImageFormatPNG,
Expand All @@ -26,6 +29,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (assign, nonatomic, readonly) BOOL isTemplate;

/**
The Image RPC representing this artwork. Generally for use internally, you should instead pass an artwork to a Screen Manager method.
*/
@property (strong, nonatomic, readonly) SDLImage *imageRPC;

/**
* Convenience helper to create an ephemeral artwork from an image.
*
Expand Down Expand Up @@ -59,6 +67,15 @@ NS_ASSUME_NONNULL_BEGIN
*/
+ (instancetype)artworkWithImage:(UIImage *)image asImageFormat:(SDLArtworkImageFormat)imageFormat NS_SWIFT_UNAVAILABLE("Use the standard initializer and set persistant to false");

/**
Create an SDLArtwork that represents a static icon. This can only be passed to the screen manager; passing this directly to the file manager will fail.
@param staticIcon The static icon to be shown on the remote system.
@return An instance of this class to be passed to a screen manager.
*/
+ (instancetype)artworkWithStaticIcon:(SDLStaticIconName)staticIcon NS_SWIFT_UNAVAILABLE("Use the standard initializer");

/**
* Convenience helper to create a persistent artwork from an image.
*
Expand Down Expand Up @@ -115,6 +132,15 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (instancetype)initWithImage:(UIImage *)image persistent:(BOOL)persistent asImageFormat:(SDLArtworkImageFormat)imageFormat;

/**
Create an SDLArtwork that represents a static icon. This can only be passed to the screen manager; passing this directly to the file manager will fail.
@param staticIcon The static icon to be shown on the remote system.
@return An instance of this class to be passed to a screen manager.
*/
- (instancetype)initWithStaticIcon:(SDLStaticIconName)staticIcon;

@end

NS_ASSUME_NONNULL_END
47 changes: 41 additions & 6 deletions SmartDeviceLink/SDLArtwork.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@
// Copyright © 2015 smartdevicelink. All rights reserved.
//

#import <CommonCrypto/CommonDigest.h>

#import "SDLArtwork.h"
#import "SDLFileType.h"
#import <CommonCrypto/CommonDigest.h>
#import "SDLImage.h"

NS_ASSUME_NONNULL_BEGIN

@interface SDLFile ()

@property (assign, nonatomic, readwrite) BOOL isStaticIcon;

@end

@interface SDLArtwork ()

@property (strong, nonatomic) UIImage *image;
Expand All @@ -22,11 +30,6 @@ @interface SDLArtwork ()

@implementation SDLArtwork

- (void)setImage:(UIImage *)image {
_image = image;
_isTemplate = (image.renderingMode == UIImageRenderingModeAlwaysTemplate);
}

#pragma mark - Lifecycle

+ (instancetype)artworkWithImage:(UIImage *)image name:(NSString *)name asImageFormat:(SDLArtworkImageFormat)imageFormat {
Expand All @@ -37,6 +40,10 @@ + (instancetype)artworkWithImage:(UIImage *)image asImageFormat:(SDLArtworkImage
return [[self alloc] initWithImage:image persistent:NO asImageFormat:imageFormat];
}

+ (instancetype)artworkWithStaticIcon:(SDLStaticIconName)staticIcon {
return [[self alloc] initWithStaticIcon:staticIcon];
}

+ (instancetype)persistentArtworkWithImage:(UIImage *)image name:(NSString *)name asImageFormat:(SDLArtworkImageFormat)imageFormat {
return [[self alloc] initWithImage:image name:name persistent:YES asImageFormat:imageFormat];
}
Expand All @@ -60,6 +67,30 @@ - (instancetype)initWithImage:(UIImage *)image persistent:(BOOL)persistent asIma
return [super initWithData:[self.class sdl_dataForUIImage:image imageFormat:imageFormat] name:(imageName != nil ? imageName : @"") fileExtension:[self.class sdl_fileExtensionForImageFormat:imageFormat] persistent:persistent];
}

- (instancetype)initWithStaticIcon:(SDLStaticIconName)staticIcon {
self = [super initWithData:[staticIcon dataUsingEncoding:NSASCIIStringEncoding] name:staticIcon fileExtension:@"" persistent:NO];
self.isStaticIcon = true;

return self;
}

#pragma mark - Setters and Getters

- (void)setImage:(UIImage *)image {
_image = image;
_isTemplate = (image.renderingMode == UIImageRenderingModeAlwaysTemplate);
}

- (SDLImage *)imageRPC {
if (self.isStaticIcon) {
return [[SDLImage alloc] initWithStaticIconName:self.name];
} else {
return [[SDLImage alloc] initWithName:self.name isTemplate:self.isTemplate];
}
}

#pragma mark - Helper Methods

/**
* Returns the JPG or PNG image data for a UIImage.
*
Expand Down Expand Up @@ -146,6 +177,10 @@ - (BOOL)isEqualToArtwork:(SDLArtwork *)artwork {
return haveEqualNames && haveEqualData && haveEqualFormats;
}

- (NSString *)description {
return [NSString stringWithFormat:@"SDLArtwork name: %@, image: %@, isTemplate: %@, isStaticIcon: %@", self.name, self.image, (self.isTemplate ? @"YES" : @"NO"), (self.isStaticIcon ? @"YES" : @"NO")];
}

@end

NS_ASSUME_NONNULL_END
4 changes: 4 additions & 0 deletions SmartDeviceLink/SDLChoiceSet.m
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ - (NSString *)description {
return [NSString stringWithFormat:@"SDLChoiceSet: \"%@\", layout: %@", _title, (_layout == SDLChoiceSetLayoutList ? @"List" : @"Tiles")];
}

- (NSString *)debugDescription {
return [NSString stringWithFormat:@"SDLChoiceSet: Title: \"%@\", layout: %@, timeout: %@, initial prompt: \"%@\", timeout prompt: \"%@\", help prompt: \"%@\", help list: %@, choices: %@", _title, (_layout == SDLChoiceSetLayoutList ? @"List" : @"Tiles"), @(_timeout), _initialPrompt, _timeoutPrompt, _helpPrompt, _helpList, _choices];
}

@end

NS_ASSUME_NONNULL_END
8 changes: 6 additions & 2 deletions SmartDeviceLink/SDLChoiceSetManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#import "SDLError.h"
#import "SDLFileManager.h"
#import "SDLHMILevel.h"
#import "SDLImage.h"
#import "SDLKeyboardProperties.h"
#import "SDLLogMacros.h"
#import "SDLOnHMIStatus.h"
Expand Down Expand Up @@ -280,7 +279,12 @@ - (void)presentChoiceSet:(SDLChoiceSet *)choiceSet mode:(SDLInteractionMode)mode
}

self.pendingPresentationSet = choiceSet;
[self preloadChoices:self.pendingPresentationSet.choices withCompletionHandler:nil];
[self preloadChoices:self.pendingPresentationSet.choices withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
[choiceSet.delegate choiceSet:choiceSet didReceiveError:error];
return;
}
}];

[self sdl_findIdsOnChoiceSet:self.pendingPresentationSet];

Expand Down
1 change: 1 addition & 0 deletions SmartDeviceLink/SDLError.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ extern SDLErrorDomain *const SDLErrorDomainTransport;
+ (NSError *)sdl_fileManager_fileDoesNotExistError;
+ (NSError *)sdl_fileManager_fileUploadCanceled;
+ (NSError *)sdl_fileManager_dataMissingError;
+ (NSError *)sdl_fileManager_staticIconError;

#pragma mark Show Managers

Expand Down
9 changes: 9 additions & 0 deletions SmartDeviceLink/SDLError.m
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,15 @@ + (NSError *)sdl_fileManager_dataMissingError {
return [NSError errorWithDomain:SDLErrorDomainFileManager code:SDLFileManagerErrorFileDataMissing userInfo:userInfo];
}

+ (NSError *)sdl_fileManager_staticIconError {
NSDictionary<NSString *, NSString *> *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(@"The file upload was canceled", nil),
NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"The file is a static icon, which cannot be uploaded", nil),
NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Stop trying to upload a static icon, set it via the screen manager or create an SDLImage instead", nil)
};
return [NSError errorWithDomain:SDLErrorDomainFileManager code:SDLFileManagerErrorStaticIcon userInfo:userInfo];
}

#pragma mark SDLUploadFileOperation

+ (NSError *)sdl_fileManager_fileDoesNotExistError {
Expand Down
4 changes: 4 additions & 0 deletions SmartDeviceLink/SDLErrorConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ typedef NS_ENUM(NSInteger, SDLFileManagerError) {
* The file data is nil or empty.
*/
SDLFileManagerErrorFileDataMissing = -9,
/*
* The file is a static icon, which cannot be uploaded
*/
SDLFileManagerErrorStaticIcon = -10,
};

/**
Expand Down
9 changes: 9 additions & 0 deletions SmartDeviceLink/SDLFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, readonly) NSInputStream *inputStream;

/**
Describes whether or not this file is represented by static icon data. The head unit will present its representation of the static icon concept when sent this data.
A file that represents a static icon may not be uploaded via the File Manager. It must be set using the Screen Manager.
Support for this feature may vary by system, but it will generally be more supported in soft buttons and menus.
*/
@property (assign, nonatomic, readonly) BOOL isStaticIcon;

- (instancetype)init NS_UNAVAILABLE;

/**
Expand Down
3 changes: 3 additions & 0 deletions SmartDeviceLink/SDLFile.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ @interface SDLFile ()
@property (copy, nonatomic, readwrite) NSString *name;

@property (nonatomic, readwrite) NSInputStream *inputStream;

@property (assign, nonatomic, readwrite) BOOL isStaticIcon;

@end


Expand Down
7 changes: 7 additions & 0 deletions SmartDeviceLink/SDLFileManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,13 @@ - (void)uploadFile:(SDLFile *)file completionHandler:(nullable SDLFileManagerUpl
return;
}

if (file.isStaticIcon) {
if (handler != nil) {
handler(NO, self.bytesAvailable, [NSError sdl_fileManager_staticIconError]);
}
return;
}

// Make sure we are able to send files
if (![self.currentState isEqualToString:SDLFileManagerStateReady]) {
if (handler != nil) {
Expand Down
10 changes: 7 additions & 3 deletions SmartDeviceLink/SDLMenuManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ - (void)sdl_sendCurrentMenu:(SDLMenuUpdateCompletionHandler)completionHandler {

NSMutableSet<SDLArtwork *> *mutableArtworks = [NSMutableSet set];
for (SDLMenuCell *cell in cells) {
if (cell.icon != nil && ![self.fileManager hasUploadedFile:cell.icon]) {
if ([self sdl_artworkNeedsUpload:cell.icon]) {
[mutableArtworks addObject:cell.icon];
}

Expand All @@ -295,6 +295,10 @@ - (void)sdl_sendCurrentMenu:(SDLMenuUpdateCompletionHandler)completionHandler {
return [mutableArtworks allObjects];
}

- (BOOL)sdl_artworkNeedsUpload:(SDLArtwork *)artwork {
return (artwork != nil && ![self.fileManager hasUploadedFile:artwork] && !artwork.isStaticIcon);
}

#pragma mark IDs

- (void)sdl_updateIdsOnMenuCells:(NSArray<SDLMenuCell *> *)menuCells parentId:(UInt32)parentId {
Expand Down Expand Up @@ -374,14 +378,14 @@ - (SDLAddCommand *)sdl_commandForMenuCell:(SDLMenuCell *)cell withArtwork:(BOOL)

command.menuParams = params;
command.vrCommands = cell.voiceCommands;
command.cmdIcon = (cell.icon && shouldHaveArtwork) ? [[SDLImage alloc] initWithName:cell.icon.name isTemplate:cell.icon.isTemplate] : nil;
command.cmdIcon = (cell.icon && shouldHaveArtwork) ? cell.icon.imageRPC : nil;
command.cmdID = @(cell.cellId);

return command;
}

- (SDLAddSubMenu *)sdl_subMenuCommandForMenuCell:(SDLMenuCell *)cell withArtwork:(BOOL)shouldHaveArtwork position:(UInt16)position {
SDLImage *icon = (shouldHaveArtwork && (cell.icon.name != nil)) ? [[SDLImage alloc] initWithName:cell.icon.name isTemplate:cell.icon.isTemplate] : nil;
SDLImage *icon = (shouldHaveArtwork && (cell.icon.name != nil)) ? cell.icon.imageRPC : nil;
return [[SDLAddSubMenu alloc] initWithId:cell.cellId menuName:cell.title menuIcon:icon position:(UInt8)position];
}

Expand Down
20 changes: 13 additions & 7 deletions SmartDeviceLink/SDLPreloadChoicesOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,13 @@ - (void)sdl_preloadCellArtworksWithCompletionHandler:(void(^)(NSError *_Nullable

NSMutableArray<SDLArtwork *> *artworksToUpload = [NSMutableArray arrayWithCapacity:self.cellsToUpload.count];
for (SDLChoiceCell *cell in self.cellsToUpload) {
if ([self.displayCapabilities hasImageFieldOfName:SDLImageFieldNameChoiceImage]) {
cell.artwork != nil ? [artworksToUpload addObject:cell.artwork] : nil;
if ([self.displayCapabilities hasImageFieldOfName:SDLImageFieldNameChoiceImage]
&& [self sdl_artworkNeedsUpload:cell.artwork]) {
[artworksToUpload addObject:cell.artwork];
}
if ([self.displayCapabilities hasImageFieldOfName:SDLImageFieldNameChoiceSecondaryImage]) {
cell.secondaryArtwork != nil ? [artworksToUpload addObject:cell.secondaryArtwork] : nil;
if ([self.displayCapabilities hasImageFieldOfName:SDLImageFieldNameChoiceSecondaryImage]
&& [self sdl_artworkNeedsUpload:cell.secondaryArtwork]) {
[artworksToUpload addObject:cell.secondaryArtwork];
}
}

Expand All @@ -107,6 +109,10 @@ - (void)sdl_preloadCellArtworksWithCompletionHandler:(void(^)(NSError *_Nullable
}];
}

- (BOOL)sdl_artworkNeedsUpload:(SDLArtwork *)artwork {
return (artwork != nil && ![self.fileManager hasUploadedFile:artwork] && !artwork.isStaticIcon);
}

- (void)sdl_preloadCells {
_currentState = SDLPreloadChoicesOperationStatePreloadingChoices;

Expand All @@ -123,7 +129,7 @@ - (void)sdl_preloadCells {
}
} completionHandler:^(BOOL success) {
if (!success) {
SDLLogW(@"Error preloading choice cells: %@", errors);
SDLLogE(@"Error preloading choice cells: %@", errors);
weakSelf.internalError = [NSError sdl_choiceSetManager_choiceUploadFailed:errors];
}

Expand All @@ -147,8 +153,8 @@ - (SDLCreateInteractionChoiceSet *)sdl_choiceFromCell:(SDLChoiceCell *)cell {
NSString *secondaryText = [self.displayCapabilities hasTextFieldOfName:SDLTextFieldNameSecondaryText] ? cell.secondaryText : nil;
NSString *tertiaryText = [self.displayCapabilities hasTextFieldOfName:SDLTextFieldNameTertiaryText] ? cell.tertiaryText : nil;

SDLImage *image = ([self.displayCapabilities hasImageFieldOfName:SDLImageFieldNameChoiceImage] && cell.artwork != nil) ? [[SDLImage alloc] initWithName:cell.artwork.name isTemplate:cell.artwork.isTemplate] : nil;
SDLImage *secondaryImage = ([self.displayCapabilities hasImageFieldOfName:SDLImageFieldNameChoiceSecondaryImage] && cell.secondaryArtwork != nil) ? [[SDLImage alloc] initWithName:cell.secondaryArtwork.name isTemplate:cell.secondaryArtwork.isTemplate] : nil;
SDLImage *image = ([self.displayCapabilities hasImageFieldOfName:SDLImageFieldNameChoiceImage] && cell.artwork != nil) ? cell.artwork.imageRPC : nil;
SDLImage *secondaryImage = ([self.displayCapabilities hasImageFieldOfName:SDLImageFieldNameChoiceSecondaryImage] && cell.secondaryArtwork != nil) ? cell.secondaryArtwork.imageRPC : nil;

SDLChoice *choice = [[SDLChoice alloc] initWithId:cell.choiceId menuName:(NSString *_Nonnull)menuName vrCommands:(NSArray<NSString *> * _Nonnull)vrCommands image:image secondaryText:secondaryText secondaryImage:secondaryImage tertiaryText:tertiaryText];

Expand Down
Loading

0 comments on commit 2bf35ff

Please sign in to comment.