|
|
|
There are a number of issues worth considering when writing an application that is intended to work on phones with different UI configurations. In order to minimize the need for testing on many phones and with various UI configurations on the emulator, there are a number of guidelines, outlined in this section, to follow. Most of the problems that might occur are related to commands: they are shown in the wrong way, appear when they should not or are missing when they should be present. If you follow the guidelines in this guide most of those problems should never occur. However, some testing on different phones and UI configurations will probably be needed to make sure everything works as expected.
The most important parameter to set correctly is the command type. Study the table in section 3.4.1, Placement, in the Programmer's Guide to New Features in UIQ 3 to see how commands are distributed on softkeys as opposed to distribution in the application menu and the Button bar.
An application can either have different command lists for each UI configuration the
application is written for, that is, different QIK_COMMAND_LISTs for each
QIK_VIEW_CONFIGURATION, or it could in some cases use just one QIK_COMMAND_LIST for all UI
configurations. Which path to choose is basically a matter of taste, but if it is possible
to have just one command list, then it is probably the solution that is less error prone
and easier to maintain. It is generally easier with one command list, but using multiple
command lists provides more control; you can have different sets of commands, different
strings, different groups and so forth.
Here is an example of commands for a view as they would appear on the screen in different UI configurations:
|
It is quite common that the commands for different UI configurations are very similar, as in this example. Instead of creating two separate command lists, however, you can have just one list but flag "Open" like this:
QIK_COMMAND
{
id = EMyCommandOpen;
type = EQikCommandTypeScreen;
text = STRING_r_my_cmd_open;
cpfFlags = EQikCpfFlagInteractionSoftkeysOnly;
}
There are a number of different flags that can be used to define which UI configuration parameter the command must match in order to be displayed.
When the structure of the command lists is different, for example, when some commands are part of a named group in one list but not in the other, it is probably better to make two different lists.
Here is another example showing the difference between one and multiple command lists:
RESOURCE QIK_VIEW_CONFIGURATIONS r_my_configurations
{
configurations =
{
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikPenStyleTouchPortrait;
command_list=r_my_commands_menu;
},
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikSoftkeyStylePortrait;
command_list=r_my_commands_softkey;
}
};
}
RESOURCE QIK_COMMAND_LIST r_my_commands_menu
{
items=
{
QIK_COMMAND
{
id=EMyCmdDone;
type=EQikCommandTypeDone;
text=STRING_r_my_cmd_done;
}
};
}
RESOURCE QIK_COMMAND_LIST r_my_commands_softkey
{
items=
{
QIK_COMMAND
{
id=EMyCmdDone;
type=EQikCommandTypeDone;
text=STRING_r_my_cmd_done;
},
QIK_COMMAND
{
id=EMyCmdCancel;
type=EQikCommandTypeCancel;
text=STRING_r_my_cmd_cancel;
},
QIK_COMMAND
{
id=EMyCmdDelete;
type=EQikCommandTypeDelete;
text=STRING_r_my_cmd_delete;
}
};
}
This is arguably more conveniently written as:
RESOURCE QIK_VIEW_CONFIGURATIONS r_my_configurations
{
configurations =
{
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikPenStyleTouchPortrait;
command_list=r_my_commands;
},
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikSoftkeyStylePortrait;
command_list=r_my_commands;
}
};
}
RESOURCE QIK_COMMAND_LIST r_my_commands
{
items=
{
QIK_COMMAND
{
id=EMyCmdDone;
type=EQikCommandTypeDone;
text=STRING_r_my_cmd_done;
},
QIK_COMMAND
{
id=EMyCmdCancel;
type=EQikCommandTypeCancel;
text=STRING_r_my_cmd_cancel;
cpfFlags=EQikCpfFlagInteractionSoftkeysOnly;
},
QIK_COMMAND
{
id=EMyCmdDelete;
type=EQikCommandTypeDelete;
text=STRING_r_my_cmd_delete;
cpfFlags=EQikCpfFlagInteractionSoftkeysOnly;
}
};
}
The rules and guidelines regarding one or multiple command lists for applications apply in general to controls as well. However, there are two major differences.
The first difference is that applications have framework support for selecting and switching command lists when the UI configuration changes. If a control wants to have multiple command lists it needs to select the command list, either by using the downgrade path or by checking UI configuration parameters, and then react to changes in the UI configuration.
The other difference is that command model owners know the command lists which are available and whether one or multiple command lists have been created. Command adders do not have this information.
It is generally easier and less error prone to use just one command list for controls, but by using multiple lists you have more control.
If a model owner has not specified a command list that exactly matches the UI configuration
of the phone it gets a call to FindCompatibleUiConfig() where it chooses the closest fit. Views,
View-dialogs, and simple dialogs all have the same downgrade path, that is, they use the same
algorithm to make this choice: QikUiConfigUtils::FindCompatibleUiConfigMode().
The system default downgrade path values matching screen modes highest, followed by interaction styles, touchscreens and orientations. However, you cannot rely on any specific prioritization of the different parameters since it might differ between different UI configurations and phones.
An example: you have specified different command lists and layouts for a view in Pen style and Softkey style. When you run that view on another UI configuration, such as Softkey style Touch, the downgrade path will be used to select the closest match, which happens to be Pen style. If you do not agree with the choice of the downgrade path you can easily add Softkey style Touch to the list of supported UI configurations of the view and manually choose which commands and layout to use.
There are several situations where you want to make choices depending on the UI
configuration of the phone, such as implementing FindCompatibleUiConfig(), choosing which set
of commands to use, launching different dialogs, or choosing between different strings. You
could either check UI parameters manually or use the system downgrade path, which is preferable,
like this:
RArray<TInt> array;
CleanupClosePushL(array);
array.AppendL(KQikSoftkeyStylePortrait);
array.AppendL(KQikSoftkeyStyleSmallPortrait);
array.AppendL(KQikPenStyleTouchLandscape);
array.AppendL(KQikSoftkeyStyleTouchPortrait);
const TInt index = QikUiConfigUtils::FindCompatibleUiConfigMode(array);
CleanupStack::PopAndDestroy(); //array
Or alternatively:
const TInt resource = QikUiConfigUtils::FindCompatibleResource(R_DIALOG_CONFIGS);
CEikDialog* dialog = new(ELeave) CEikDialog;
dialog->ExecuteLD(resource);
RESOURCE ARRAY r_dialog_configs
{
items =
{
QIK_UI_CONFIG_RESOURCE
{
ui_config_mode = KQikSoftkeyStylePortrait;
resource = r_softkey_dialog;
},
QIK_UI_CONFIG_RESOURCE
{
ui_config_mode = KQikSoftkeyStyleSmallPortrait;
resource = r_softkey_small_dialog;
},
QIK_UI_CONFIG_RESOURCE
{
ui_config_mode = KQikPenStyleTouchLandscape;
resource = r_pen_landscape_dialog;
},
QIK_UI_CONFIG_RESOURCE
{
ui_config_mode = KQikSoftkeyStyleTouchPortrait;
resource = r_softkey_touch_dialog;
}
};
}
You should not make assumptions about which command list is currently loaded. The downgrade path might have selected another command list than the one you assume.
For example, if you have an application with two command lists:
R_MY_MENUBAR_COMMANDS and R_MY_SOFTKEY_COMMANDS, this is wrong to assume that the appearance of an attribute in itself can tell you which command list is being used.
THIS ASSUMPTION IS WRONG:
if(uiConfigClient.CurrentConfig().InteractionStyle() == EQikInteractionStyleMenubar)
{
//do something that assumes that R_MY_MENUBAR_COMMANDS is the active command list
}
Instead you should check to see if the command list is active.
THIS IS CORRECT, NO ASSUMPTION IS MADE:
if(/*CQikViewBase::*/IsCommandListActive(R_MY_MENUBAR_COMMANDS))
{
//do something that assumes that R_MY_MENUBAR_COMMANDS is the active command list
}
Command adders can just as well check if any one of their
QIK_COMMAND_LISTs is loaded by using
CQikCommandManager::IsCommandListActive() directly.
A mistake when you want to have different behavior for different UI configurations of the phone is to check for the whole style.
THIS IS A MISTAKE:
if(CQUiConfigClient::Static().CurrentConfig() == KQikSoftkeyStyleLandscape)
//do something
By doing so, the code is too dependent on the UI configuration of the phone. The code
should, for example, probably not distinguish between the screen modes
KQikSoftkeyStyleLandscape and KQikSoftkeyStyleLandscape180. Instead,
using the significant UI configuration parameters is a better approach, if you do not want to
use the downgrade path.
THIS IS CORRECT:
if(CQUiConfigClient::Static().CurrentConfig().ScreenMode() == EQikScreenModeLandscape)
//do something
The four available parameters are:
ScreenMode()
Orientation()
InteractionStyle()
TouchScreen()
Besides checking the parameters programmatically you can also flag a command to only be present for some value of a parameter:
EQikCpfFlagTouchscreenOnly
EQikCpfFlagNoTouchscreenOnly
EQikCpfFlagInteractionMenubarOnly
EQikCpfFlagInteractionSoftkeysOnly
EQikCpfFlagPortraitOnly
EQikCpfFlagLandscapeOnly
The parameters that are tricky to get right are the touchscreen parameters and the UI-Interaction-style parameters. Probably the main reason that these are tricky is because they are not truly independent parameters; Softkey style is designed for non-touchscreen use and Pen style is designed for touchscreen use. Therefore, softkey-style design decisions correlate with non-touchscreen design decisions and pen-style design decisions correlate with touchscreen design decisions.
Some examples for when the touchscreen parameter should be used are:
for text input since selecting text is easier using the pen than using the softkeys; when there is no touchscreen, there are commands such as Copy word and Cut word,
Mark/Unmark should not be available in the menu since it is easier to use the pen,
whenever a touchscreen is required, for example for hotspots.
Here is an example where UI-Interaction style is checked for text input commands.
THIS IS THE WRONG WAY:
if(CQUiConfigClient::Static().CurrentConfig().InteractionStyle() == EQikInteractionStyleSoftkey)
CQikCommandManager::Static().InsertIntoCommandListL(*this, *this, R_MY_TEXT_INPUT_COMMANDS_SOFTKEY_STYLE);
else
CQikCommandManager::Static().InsertIntoCommandListL(*this, *this, R_MY_TEXT_INPUT_COMMANDS_PEN_STYLE);
But where a touchscreen should be used, for example if we want to use the pen to select text instead of using the Cut word and Copy word commands, we can check for the parameter directly.
THIS IS THE RIGHT WAY:
if(CQUiConfigClient::Static().CurrentConfig().TouchScreen() == EQikTouchScreenYes)
CQikCommandManager::Static().InsertIntoCommandListL(*this, *this, R_MY_TEXT_INPUT_COMMANDS_TOUCHSCREEN_YES);
else
CQikCommandManager::Static().InsertIntoCommandListL(*this, *this, R_MY_TEXT_INPUT_COMMANDS_TOUCHSCREEN_NO);
When you have multiple command lists there are two different ways to add commands. The commands could either be added to all command lists, which is the recommended way,
const TBool touchscreen = (CQUiConfigClient::Static().CurrentConfig().TouchScreen() == EQikUiConfigTouchScreenYes);
cmdManager.InsertIntoCommandListL(*this, *this, (touchscreen ? R_MY_TOUCHSCREEN_COMMANDS : R_MY_NON_TOUCHSCREEN_COMMANDS));
or they could be added to those command lists which match a certain UI-configuration parameter.
cmdManager.InsertIntoCommandListL(*this, *this, R_MY_TOUCHSCREEN_COMMANDS, EQikUiConfigTouchScreenYes);
cmdManager.InsertIntoCommandListL(*this, *this, R_MY_NON_TOUCHSCREEN_COMMANDS, EQikUiConfigTouchScreenNo);
When you have only one command list, you do not have to choose; you use the first option, that is, to add to all the command lists, which in this case is just one list.
The same guidelines apply for setting the state of commands as for adding commands.
SetAvailable(), or the state flag EQikCmdFlagUnavailable,
should be used in preference to SetDimmed()/SetInvisible() in most
cases where you want to indicate that a command is not available to the user. If a command is
unavailable, it will be invisible when the interaction style is softkey, and dimmed when the
interaction style is menu bar.
There are a number of cases when you want a command to be duplicated, such as on the button bar and in the application menu, on the left softkey and in the More menu, on a hardware key and in the More menu or in the application menu. One way to handle these cases is to duplicate the command in the command list, but that is not recommended since when you run that application on an unknown phone you might, for example, end up with duplicated commands in the More menu.
Most of these cases can be addressed by flagging the command to be duplicated in menu panes (application menu, dialog menu, more menu/right softkey, container pop-out menu, full screen floating menu):
QIK_COMMAND
{
id = EMyCommandNew;
type = EQikCommandTypeScreen;
text = "New";
cpfFlags = EQikCpfFlagPreferToBePlacedInButtonbar | EQikCpfFlagDuplicateInMenuPane;
}
There are some recommendations and requirements as to which hardware keys a UIQ phone should have. But basically, you have to consider what would happen to your application if a phone did not have all of the hardware keys you expected it to have.
One example is a Select command in a list box. You want the command to be attached to the Action key on a Pen-style phone, and on the center softkey on a Softkey-style phone. But if there is a phone that does not have an Action key, the command would appear in the menu on a Pen-style phone; this you do not want because it is more convenient to use the touchscreen for selecting items.
If you want a command to only be present on a hardware key, that is, not even on a softkey, you can do this:
QIK_COMMAND
{
id = EMyCommandHardwareCommand;
type = EQikCommandTypeItem;
cpfFlags = EQikCpfFlagHardwarekeyOnly;
}
Another aspect is how to treat commands you want to appear in the UI even if the hardware key they were expecting to be placed on should be omitted from a phone. Commands that are intended exclusively for hardware keys do not need any form of visual representation. But the expected hardware key may not be available, so it is a good idea to set a text label, a short text label or an icon for the command just in case.
Not setting at least one form of visual representation for a command has the same effect as flagging
it EQikCpfFlagHardwarekeyOnly. If there is no hardware key, the command will not appear in the UI at all.
For example, if you run an application written for a Pen-style phone on a Softkey-style phone, commands intended for the Action key and other hardware keys might end up on softkeys and in the More menu; running a Softkey-style application on a Pen-style phone might move commands from hardware keys to the Button bar and the application menu.
When you want a menu popout in the Button bar you just need to create a named group and make it end up on the Button bar. The problem with trying to make your own menu popout, for example having a command which ends up in the button bar and manually create a popout when the command is executed, is that it is difficult to find a solution that works if that application is run on a phone that does not use the Button bar.
QIK_COMMAND
{
id = EMyCommandNewGroup;
type = EQikCommandTypeScreen;
text = "New...";
namedGroupLinkId = EMyCommandGroupLinkIdNew;
cpfFlags = EQikCpfFlagPreferToBePlacedInButtonbar;
},
QIK_COMMAND
{
id = EMyCommandNewHouse;
type = EQikCommandTypeScreen;
text = "New house";
namedGroupId = EMyCommandGroupLinkIdNew;
},
QIK_COMMAND
{
id = EMyCommandNewBoat;
type = EQikCommandTypeScreen;
text = "New boat";
namedGroupId = EMyCommandGroupLinkIdNew;
}