Contents |
Notes are small dialogs that can be used to display short messages to the user.
Notes are a subset of AVKON dialogs. For detailed information on dialogs in general, as well as other dialog types, see S60 3.1 Dialogs API Specification.
API category | public |
API type | c++ |
Existed since | Legacy S60 0.9 |
API libraries | avkon.lib, eikcdlg.lib, eikctl.lib |
Location | /sf/mw/classicui/classicui_pub/notes_api
|
Buildfiles | /sf/mw/classicui/classicui_pub/notes_api/group/bld.inf
|
It is important to inform the user about different states or result of operations. AVKON UI Notes provide method for displaying these short messages on the screen for a couple of seconds. User may dismiss them before the note's time expire. It is also possible to give a choice to the user: cancel a long process (e.g. a file upload), or answering a two-way question (e.g. Yes/No).
To use the basic AVKON UI Notes only an instance should be created from the appropriate note class (defined in avkonwrapper.h). These notes are the followings:
A note can be a modal control: when executed it prevents the application from doing any further processing until the note is dismissed. By default basic notes are non-waitings.
There are also predefined notes that cannot be used just by instantiating a simple note class. These notes' lifetime is based on a background process and client code has to provide an interface to retrieve this information. These notes are:
Global Notes are special notes, they are displayed even if the application launching the note is not in the foreground.
Notes API is an SDK API and was first published in S60 release 0.9.
This API is valid for all platforms running on Symbian OS 9.1 or later.
The main use cases of AVKON UI Notes API are:
Classes | Files |
---|---|
|
/epoc32/include/mw/aknnotewrappers.h
CAknErrorNote
/epoc32/include/mw/aknnotewrappers.h
CAknInformationNote
/epoc32/include/mw/aknnotewrappers.h
CAknNoteControl
/epoc32/include/mw/aknnotecontrol.h
CAknNoteControl::TIndex
/epoc32/include/mw/aknnotecontrol.h
CAknNoteDialog
/epoc32/include/mw/aknnotedialog.h
CAknNoteWrapper
/epoc32/include/mw/aknnotewrappers.h
CAknProgressDialog
/epoc32/include/mw/AknProgressDialog.h
CAknProgressTimer
/epoc32/include/mw/aknprogresstimer.h
CAknResourceNoteDialog
/epoc32/include/mw/aknnotewrappers.h
CAknStaticNoteDialog
/epoc32/include/mw/aknstaticnotedialog.h
CAknStaticNoteStackIndicator
/epoc32/include/mw/aknstaticnotedialog.h
CAknWaitDialog
/epoc32/include/mw/AknWaitDialog.h
CAknWaitNoteWrapper
/epoc32/include/mw/AknWaitNoteWrapper.h
CAknWarningNote
/epoc32/include/mw/aknnotewrappers.h
CEikInfoDialog
/epoc32/include/mw/eikinfo.h
CEikProgressInfo
/epoc32/include/mw/eikprogi.h
MAknBackgroundProcess
/epoc32/include/mw/AknWaitNoteWrapper.h
MProgressDialogCallback
/epoc32/include/mw/AknProgressDialog.h
TAknNoteResData
/epoc32/include/mw/aknnotewrappers.h
The base class for AVKON UI Notes is CAknNoteDialog
. The
following diagram shows the basic notes.
Wait Note and Progress Note's design
A confirmation note informs the user about a successfully completed operation. By default it has a short duration and a subtle tone and should be used when the effect of the operation cannot be seen directly.
Information note is used when an unexpected situation is encountered during usage of the device. This note has a longer duration and a more noticeable tone than the confirmation note. Information note should be used when an error that can be rectified occurs, for example "Name already exists" when user tries to add a duplicate name to Phonebook.
Warning note is used when the user must be notified about something that may require action. The note is displayed for a fairly long time and the sound can be heard even when the user is not concentrating on the phone - this note is used for example a "Battery low" warning.
Error notes should be used when user does something that may cause considerable harm immediately or later, for example entering a wrong PIN-code would block using the SIM card.
Wait note is used to inform the user about an operation is taking place. However, it does not indicate the length of the operation.
Progress note is used for operations when the process length can be calculated; so the user might be informed about the time status of the operation.
Global note is used to display an information which is not application specific, e.g. Alarm, Calendar notes or battery notes.
The following code creates a waiting confirmation note, displays it, and
after a short delay dismisses it. Delay timer is predefined for all basic
notes in avkon.hrh. Since the note is created as a waiting note, the ExecuteLD()
function
blocks the application execution. ExecuteLD()
also deletes
the note automatically.
// creating basic note #include <aknnotewrappers.h>
_LIT( mConfText, "Picture deleted."); CAknConfirmationNote *mConfNote; mConfNote = new (ELeave) CAknConfirmationNote( ETrue ); // waiting mConfNote->ExecuteLD( mConfText ); // display the note and delete it
When a non-waiting note is used, ExecuteLD()
returns immediately
not blocking the application to do further processes. When a pointer reference
is used, the note is not only deleted after execution but the pointer is also
set to NULL
.
class CNoteExampleAppUi : public CAknAppUi { private: CAknInformationNote *iInfNote; };
void CNoteExampleAppUi::HandleCommandL( TInt aCommand ) { switch( aCommand ) { case ECommandCreateInformationNote : { iInfNote = new (ELeave) CAknInformationNote( &iInfNote ); iInfNote->ExecuteLD( _L("Not an integer. Try again.") ); // note will be deleted automatically // and pointer will be set to NULL after execution break; } default: break; } }
Do not create and execute another note until this one has completed, ActiveScheduler
cannot
handle this situation:
void CNoteExampleAppUi::ShowErrorNoteL() { if( iInfNote ) // note is on the screen { return; } // no note is shown CAknErrorNote* mErrorNote; mErrorNote = new (ELeave) CAknErrorNote( ETrue ); mErrorNote->ExecuteLD( _L("General error.") ); }
To use WaitNoteWrapper
you have to define a note resource.
Its structure is defined in eikon.rh and avkon.rh.
STRUCT DIALOG { LONG flags = 0; LLINK buttons = 0; STRUCT items(); // STRUCT DLG_LINE }
STRUCT DLG_LINE { WORD type; WORD id = 0; STRUCT control; // STRUCT AVKON_NOTE }
STRUCT AVKON_NOTE { WORD layout; LTEXT singular_label; // e.g. You have missed a call. LTEXT plural_label = ""; // e.g. You have %d missed calls. LTEXT imagefile = ""; WORD imageid = 0xffff; WORD imagemask = 0xffff; LTEXT iconfile = ""; WORD iconid = 0xffff; WORD iconmask = 0xffff; LLINK animation = 0; } RESOURCE DIALOG r_myapp_waitnote { flags = EAknWaitNoteFlags; buttons = R_AVKON_SOFTKEYS_CANCEL; items = { DLG_LINE { type = EAknCtNote; id = EMyAppWaitNote; control = AVKON_NOTE { layout = EWaitLayout; singular_label = "Connecting, please wait."; imagefile = "z:\\system\data\avkon.mbm"; imageid = EMbmAvkonQgn_note_progress; imagemask = EMbmAvkonQgn_note_progress_mask; animation = R_QGN_GRAF_WAIT_BAR_ANIM; }; } }; }
Wait note's background process is controlled by a MAknBackgroundProcess
class.
Its callback functions are called by the WaitNoteWrapper
:
IsProcessDone()
: check whether the background process
has been finished or not.
StepL()
: do 1 step in the background process.
CycleError()
: called when StepL()
leaves,
has to return with KErrNone
if error was processed.
DialogDismissedL()
: called when user dismissed the note.
ProcessFinishedL()
: do anything before destroying the
note.
If the user does not interrupt the Wait note by pressing a key, ProcessFinishedL()
is
called before DialogDismissedL()
.
#include <aknwaitnotewrapper.h>
class CMyProcess : public CBase, public MAknBackgroundProcess { public: TBool IsProcessDone() const; void StepL(); // TInt CycleError( TInt aError ); // void DialogDismissedL( TInt aButtonId ); // void ProcessFinishedL();
private: TInt iCount; };
Here we implement a simple strategy to maintain the wait note. It will be shown for 5 seconds, so 5 rounds of stepping is done:
TBool CMyProcess::IsProcessDone() const { return ( iCount == 5 ); }
void CMyProcess::StepL() { sleep( 1 ); // do nothing for 1 second iCount++; // next cycle }
Using the note:
// create background process CMyProcess *myProcess = new (ELeave) CMyProcess(); CleanupStack::PushL( myProcess );
// create WaitNoteWrapper CAknWaitNoteWrapper *waitNote = CAknWaitNoteWrapper::NewL(); // CAknWaitNoteWrapper is privately derived from CActive/CBase // therefore a reinterpret_cast must be performed here CleanupStack::PushL( reinterpret_cast<CBase*> ( waitNote ) );
// shows the note immediately TBool success = waitNote->ExecuteL( R_MYAPP_WAITNOTE, *myProcess, ETrue ) )
CleanupStack::PopAndDestroy( waitNote ); CleanupStack::PopAndDestroy( myProcess );
// further processes based on the note's exit code if( success ) { InitializeConnection(); } else // note was cancelled { CancelConnection(); }
A similar resource can be used to create a Progress note:
RESOURCE DIALOG r_myapp_progressnote { flags = EAknProgressNoteFlags; buttons = R_AVKON_SOFTKEYS_CANCEL; items = { DLG_LINE { type = EAknCtNote; id = EMyAppProgressNote; control = AVKON_NOTE { layout = EProgressLayout; singular_label = "Resizing image"; imagefile = "\\system\data\avkon.mbm"; imageid = EMbmAvkonQgn_note_progress; imagemask = EMbmAvkonQgn_note_progress_mask; }; } }; }
Progress note does not have a wrapper class around the note object as Wait note does. Therefore the note has to be controlled directly by the client. This means two things: when and how the progress bar is updated. In most cases it means a data-based operation calculation, e.g. uploading a file is a connection dependent process, converting an image to another format might be a hardware chipset-variant operation, etc.
Here we use a simple timer-based active object for the progress bar calculation.
It is a safe design decision to encapsulate the active object, the dialog
and the callback provide mechanism ( MProgressDialogCallback
)
into one class. Another design issue is the usage of the class. Here we used
the "fire and forget" method:
#include <myapp.rsg> // create a waiting note CProgressProcessor* iProcessor = CProgressProcessor::NewL( &iProcessor, R_MYAPP_PROGRESSNOTE, ETrue ); // run iProcessor->ExecuteLD(); // do nothing, ExecuteLD() deletes the objects automatically
Based on this the class definition looks like this:
#include <aknprogressdialog.h>
class CProgressProcessor: public CActive, public MProgressDialogCallback { public: // constructors, destructor
// aResource: the progress note's resource id // aWaiting: waiting note or non-waiting // aVisible: ETrue if note has to be shown immediately static CProgressProcessor* NewL( CProgressProcessor** aSelfPtr, TInt aResource, TBool aWaiting, TBool aVisible = EFalse );
virtual ~CProgressProcessor();
public: // new functions void ExecuteLD();
private: // from CActive void RunL(); void DoCancel(); TInt RunError( TInt aError );
public: // from MProgressDialogCallback void DialogDismissedL( TInt aButtonId );
protected: // construction CProgressProcessor(); void ConstructL( TInt aResource, TBool aWaiting, TBool aVisible );
private: // new functions TBool IsProcessDone(); // finished? void DoProcess(); // perform next step void DoDelete(); // delete the object
private: // data CAknProgressDialog* iDialog; TInt iCounter; CProgressProcessor** iSelfPtr; RTimer iTimer; TBool iDestroy; CActiveSchedulerWait* iWait; // for waiting note };
There is nothing special in the constructors and destructor. The second phase constructor creates the dialog and initializes the progress bar.
CProgressProcessor::ConstructL( TInt aResource, TBool aWaiting, TBool aVisible ) { User::LeaveIfError( iTimer.CreateLocal() );
// length of the process is unknown (in time) but it can be calculated iDialog = new (ELeave) CAknProgressDialog( reinterpret_cast<CEikDialog**>(&iDialog), aVisible ); iDialog->PrepareLC( aResource ); CleanupStack::Pop(); iDialog->SetCallback( this );
// how "long" is the process in steps // here we use a percentage value CEikProgressInfo* progressInfo = iDialog->GetProgressInfoL(); progressInfo->SetFinalValue( 100 );
if( aWaiting ) iWait = new (ELeave) CActiveSchedulerWait(); CActiveScheduler::Add( this ); }
CProgressProcessor::~CProgressProcessor() { iTimer.Close(); // if note is not deleted yet if( iDialog ) { iDialog->SetCallback( NULL ); TRAP_IGNORE( iDialog->ProcessFinishedL() ); } *iSelfPtr = NULL; // set self pointer in parent object to NULL }
The process status functions are very simple:
TBool CProgressProcessor::IsProcessDone() { // 100 percent reached? return iCounter>=100; }
void CProgressProcessor::DoProcess() { iCounter++; iTimer.After( iStatus, 300000 ); // wait 0.3 seconds SetActive(); // and call RunL() }
The public function to activate the note:
void CProgressProcessor::ExecuteLD() { CleanupStack::PushL( this ); iDialog->RunLD(); // shows the dialog, returns immediately DoProcess(); // start background process if( iWait ) { // start waiting process, it blocks further execution here iWait->Start(); // after it finishes, cleanup everything CleanupStack::PopAndDestroy(); } else { // non-waiting dialog, so return immediately // delete will be performed by RunL() or DoCancel() CleanupStack::Pop(); } }
Safe object delete:
void CProgressProcessor::DoDelete() { if( iWait ) // waiting note? CAknEnv::StopSchedulerWaitWithBusyMessage( *iWait ); else delete this; }
Active object deletes itself if it was requested (via an error) or process has been finished; or perform next step.
// one step was done void CProgressProcessor::RunL() { // any delete operation requested meanwhile? if( iDestroy ) { DoDelete(); }
if( IsProcessDone() ) { iDialog->SetCallback( NULL ); iDialog->ProcessFinishedL(); DoDelete(); } else // do next step, update progress bar { DoProcess(); iDialog->GetProgressInfoL()->IncrementAndDarw( 1 ); } }
// RunL() did leave TInt CProgressProcessor::RunError( TInt /* aError */ ) { iDialog->SetCallback( NULL ); TRAP_IGNORE( iDialog->ProcessFinishedL() );
iDestroy = ETrue; iTimer.Cancel(); iTimer.Start( iStatus, 10 ); // call RunL() immediately SetActive();
// all errors are swallowed return KErrNone; }
// someone uses the object in a not proper way? void CProgressProcessor::DoCancel() { if( iDialog ) { // no function callback needed for ProcessFinishedL() iDialog->SetCallback( NULL ); TRAP_IGNORE( iDialog->ProcessFinishedL() ); } iDestroy = ETrue; // just in case iTimer.Cancel(); // object is NOT deleted here }
If the dialog was dismissed, delete this object too:
void CProgressProcessor::DialogDismissedL( TInt /* aButton */ ) { iDialog = NULL; DoDelete(); }
Following code shows the simplest way of using the Global note:
// resource definition RESOURCE TBUF r_myapp_globalnote_searching { buf = "Searching..."; } #include <aknnotifystd.h> // note type #include <myapp.rsg> // application resource
const TInt KGlobalNoteMaxLength = 32;
// allocate TBuf with constant length, and fill it with a resource text TBuf<KGlobalNoteMaxLength> text( NULL ); CEikonEnv::Static()->ReadResourceL( text, R_MYAPP_GLOBALNOTE_SEARCHING ); TPtrC noteText( text );
// create GlobalNote instance and show it. CAknGlobalNote* globalNote = CAknGlobalNote::NewLC(); TInt noteId = globalNote->ShowNoteL( EAknGlobalInformationNote, noteText );
// do anything here sleep( 5 ); // waiting for 5 seconds
// discard note globalNote->CancelNoteL( noteId ); CleanupStack::PopAndDestroy();
It is also possible to wait for user action when softkeys are attached to the Global note. This note is an asynchronous UI element, so an active object has to be implemented to receive the notification about user's choice.
Here we define an interface class as well to handle user interactions and errors.
// callback interface for global note handler class MGlobalNoteClient { public: virtual void HandleCommandL( TInt aCommand ) = 0; virtual TInt NoteError( TInt aError ) = 0; };
// define the global note handler as an active object class CGlobalNoteHandler: public CActive { public: // constructors, destructor, etc.
public: // new function // aResource: resource identifier to shown void ShowNoteL( TInt aResource, const TDesC& aText, MGlobalNoteClient*& aClient );
protected: // from CActive void RunL(); void DoCancel(); TInt RunError( TInt aError );
private: // data CAknGlobalNote *iGlobalNote; TInt iNoteId; MGlobalNoteClient* iNoteClient; }; // active object initialization CGlobalNoteHandler::CGlobalNoteHandler() : CActive( EPriorityNormal ) { CActiveScheduler::Add( this ); }
// showing the note void CGlobalNoteHandler::ShowNoteL( TInt aResource, const TDesC& aText, MGlobalNoteClient*& aClient ) { if( iGlobalNote ) return; // do not do anything if a note is already shown iGlobalNote = CAknGlobalNote::NewL(); iGlobalNote->SetSoftkeys( aResource ); iNoteId = iGlobalNote->ShowNoteL( iStatus, EAknGlobalConfirmationNote, aText ); SetActive(); iNoteClient = aNoteClient; } // handling user interaction void CGlobalNoteHandler::RunL() { // cancel note operation iGlobalNote->CancelNoteL( iNoteId ); delete iGlobalNote; iGlobalNote = NULL; iNoteId = 0;
TInt value( iStatus.Int() ); // user response User::LeaveIfError( value );
// handle user response iNoteClient->HandleCommandL( value ); }
// error occurs in RunL() TInt CGlobalNoteHandler::RunError( TInt aError ) { // cancel note operation TRAP_IGNORE( iGlobalNote->CancelNoteL( iNoteId ) ); delete iGlobalNote; iGlobalNote = NULL; iNoteId = 0;
return iNoteClient->NoteError( aError ); // all errors are passed to client }
// system cancelled the note void CGlobalNoteHandler::DoCancel() { // cancel note operation TRAP_IGNORE( iGlobalNote->CancelNoteL( iNoteId ) ); delete iGlobalNote; iGlobalNote = NULL; iNoteId = 0; }
There are cases when the predefined notes just are not enough. You might,
for example, want to change the icon displayed in the note, use a different
kind of sound, or change the note duration. All of the properties can be changed
via CAknNoteDialog
's setter functions: SetTimeout
, SetTone
, SetTextWrapping
, SetTextProcessing
, SetImageL
, SetIconL
.
AVKON UI Notes API uses standard Symbian OS error reporting mechanism. Leaves and system wide error codes as function return values are used if the error is recoverable. A client application can handle these errors similarly as a normal Symbian platform application.
S60 3.1 Dialogs API Specification |