Så gör du egna program för UIQ

I den här Mobilskolan får du lära dig hur du kommer i gång med att utveckla program för Symbian-smartphones med det senaste uiq-gränssnittet, närmare bestämt Sony Ericsson m600/p990/w950. Du får också lära dig att skriva ett program som gör det enkelt att göra minnesanteckningar efter avslutade telefonsamtal.

Publicerad Senast uppdaterad

När man ska skriva program för Symbiantelefoner har man flera olika programmeringsspråk att välja på. De vanligaste är c++ och Java. I den här artikelserien har vi valt att använda c++. Det är det språk som används av i stort sett alla professionella utvecklare. Java kanske är något enklare att programmera i men det finns också flera nackdelar med att använda Java i en Symbianmobil. Java-program är långsammare och förbrukar mera minne. Förr eller senare kommer man dessutom att vilja komma åt funktioner i telefonen som bara är tillgängliga från c++.

Naturligtvis kräver det att man har vissa förkunskaper i c/c++. Har man kunskaper i något annat objektorienterat språk underlättar det också. I programmeringsskolan ska vi försty titta på de viktigaste delarna av koden till ett

enkelt exempelprogram. Sedan får du lära dig lite mer om c++. I slutänden är tanken att du ska ha lärt tillräckligt mycket för att kunna gå vidare på egen hand. Vill du skriva roliga och användbara program måste du dock lägga ner en hel del tid på att själv studera c++.

Vad behöver man?

För att kunna skriva Symbianprogram är det några grundkrav som måste vara uppfyllda. Du måste ha en pc med Windows xp (sp2) eller Windows 2000 (sp4). Det krävs minst 512 megabyte ram och en processor på 1 800 megahertz cpu. Man har mer nytta av mer internminne än av en snabbare cpu, så 1 gigabyte ram rekommenderas.

1 gigabyte ledigt på hårddisken behöver du också. Sedan behöver du ladda ner en integrerad utvecklingsmiljö för c++ till din dator. Det finns flera att välja på, men för en hobbyprogrammerare känns gratisversionen av Carbide. c++ rätt. Carbide.c++ Express v1.1 laddar man ner från Forum Nokia: www.forum.nokia.com/main/resources/

tools_and_sdks/listings/symbian_cpp_tools.html.

Du behöver också ett så kallat sdk (Software Development Kit) som matchar din telefon. För de senaste Sony

Ericsson-telefonerna m600/p990 är det uiq3 sdk som gäller. Ladda ner det från developer.uiq.com/de... Här kan man även ladda ner Sony Ericsson-specifika så kallade extensions för m600 och p990. Dessa kan grovt beskrivas som skins som matchar de riktiga telefonerna. Motsvarande sdk för Nokiatelefoner kan laddas ner från

www.forum.nokia.com.

Installation

Börja med att installera Carbide.c++ Express. Man behöver inte ändra några standardalternativ i denna process. Efter installation visas en webbsida där man uppmanas att installera Perl, cTags och ett Symbian sdk. Perl är »bundlat« i det uiq3 sdk vi kommer att använda och cTags klarar man sig utan. Fortsätt med att installera uiq3 sdk:

- Först installeras Perl som bundlats i SDK.

- Därefter börjar den riktiga SDKinstallationen med att man får välja komponenter. Här är det viktigt att man installerar GCCE Compiler, men inte alternativet x86 vs2003 som är förvalt. Vi rekommenderar också att man väljer att installera Winpcap.

- Installationen av GCCE-kompilatorn (CSL ARM Toolchain) och Winpcap görs i slutet av installationsprocessen.

- Svara ja på frågan om man vill att detta SDK ska vara default.

Nu är vi nästan klara. Man måste manuellt gå in och ändra miljövariabeln path så att pathen c:\Program Files\csl ArmToolchain\bin läggs till. Det är lämpligt att öppna ett kommandofönster i sin pc för att verifiera några saker efter installationen:

- Skriv path. Din PATH bör innehålla C:\Program Files\Common Files\Symbian\tools, C:\Program Files\CSLArm Toolchain\bin och C:\Perl\bin\. Exakta pather kan variera beroende på Windows språkversion. Detta kan tyvärr ställa till med en del problem när man kör svensk version av operativsystemet.

- Skriv kommandot devices. Resultatet bör vara: UIQ3:com.symbian.UIQ - default

- Skriv kommandot epoc, och kontrollera att den så kallade emulatorn startas. Emulatorn simulerar en telefon och det är med hjälp av denna man testar sina program på pc:n först.

Har man installerat någon Sony Ericsson-extension kan man välja »style« i Windows-applikationen sdkConfig

som installerades tillsammans med uiq3 sdk. Nu är vi redo att börja programmera!

Skapa ett första exempel

En fördel med Carbide är att det finns »wizards« som enkelt skapar ett minimalt projekt med alla nödvändiga filer för ett enkelt program. Starta Carbide.c++ och välj File | New | c++ Application for uiq Project i menyn.

- Ge ditt projekt ett namn, till exempel »MobilDel1«.

- Välj template »UIQ 3.x GUI Application«.

- Gå sedan igenom resten av guiden. Man behöver inte mata in något mer eller ändra något av de förvalda alternativen.

Nu har du fått ett c++-projekt med.cpp- och .h-fi ler. En enkel uiq-applikation har fyra klasser: Application, Document, AppUi, och View. Innan vi studerar koden närmare så är det dags att bygga (kompilera/länka) applikationen för att sedan kunna provköra den i emulatorn på pc.

Koden byggs genom att göra Project | Build Project. Förhoppningsvis får man 0 errors; eventuella varningar kan man bortse från i detta skede. För att du ska få en bild av hela processen innan vi ger oss in djupare på hur

c++ fungerar har vi skapat ett färdigt exempel. Alla filer som behövs kan du ladda ner från www.mobil.se/uiqskola.

Kör programmet i emulatorn

När man kommit i gång med själva programmerandet bör man provköra applikationen på pc i ett tidigt skede.

Symbian-emulatorn ger programmeraren möjlighet att testa sin applikation på ett snabbt sätt. I denna emulerade miljö har man också mycket goda möjligheter att felsöka och debugga sin applikation.

Fördelen med emulatorn jämfört med att köra på en riktig telefon är just det att det går snabbt att testa sina ändringar och att debug-möjligheterna är bättre. Däremot är det inte säkert att ett program som fungerar på emulatorn fungerar på en riktig telefon. Emulatorn är bra, men den är inte 100 procent lik en telefon. Därför ska man inte vänta för länge innan man testar programmet på telefonen. Du kan starta emulatorn från Carbide genom att välja Run | Run, eller Run | Debug. Nu finns vår applikation MobilDel1 tillgänglig som en ikon. Markera den och starta programmet. Det är ett mycket enkelt program med en vy som visar texten »MobilDel1« centrerat på skärmen. Dessutom finns det fyra stycken menyval: InfoPrint1 - InfoPrint3 och Close (debug). InfoPrint-menyerna har funktionen att en liten informationsruta med text visas. Close (debug) avslutar programmet.

Installera program på telefon

Innan vi gör lite egna ändringar i vår applikation är det lika bra att förvissa sig om att programmet går att bygga för och köra på en riktig telefon.

Först behöver vi tala om att vi ska bygga programmet för telefonen genom att välja Project | Active Build Configuration | uiq 3.0 Phone (gcce) Release. Kör Project | Build Project igen. Om allt gått bra har nu en installationsfil (.sis) skapats automatiskt. sis-filens innehåll styrs av filen MobilDel1_gcce.pkg. pkg-filen och den färdiga installationsfien hittar man typiskt under c:\Symbian\Carbide\workspace\MobilDel1\sis.

Installera nu programmet på din telefon. Har man installerat Sony Ericsson pc Suite for Smartphones så kan man bara dubbelklicka på sis-filen och installation startas på pc:n. Alternativt överför man sis-fi len till telefonen med hjälp av Bluetooth och startar installationen på telefonen. Sedan är det bara att provköra programmet på din telefon.

Vad innehåller koden?

Först lite förklaringar till vårt exempel som har en vy där vi visar en textsträng. Utseende på vyn definieras här helt och hållet med hjälp av en så kallad resursfil, MobilDel1.rss. Först kan man definiera hur vyn ska se

ut för olika skärmkonfigurationer. Man kan till exempel definiera att en vy och dess menyval anpassar sig beroende på om man har öppen eller stängd lucka på en p990. I det här exemplet definierar vi för enkelhetens skull att vyn och menyer är identiska för samtliga skärmkonfigurationer.

RESOURCE QIK_VIEW_CONFIGURATIONS

r_ui_configurations

{

configurations =

{

QIK_VIEW_CONFIGURATION

{

ui_config_mode = KQikPenStyleTouchPortrait;

command_list = r_MobilDel1_commands;

view = r_MobilDel1_layout;

},

:

:

Vyn r_MobilDel1_layout definieras sedan i en sorts hierarkisk struktur: Vyn kan ha flera flikar som definieras i en qik_view_page-struktur. Vårt program har bara en sida. I vår sida ligger en container som definieras av:

RESOURCE QIK_CONTAINER_SETTINGSr_MobilDel1control

Inuti containern finns ett antal (i detta fall en) container-items.

QIK_CONTAINER_ITEM_CI_LI

{

unique_handle = EMobilDel1LabelCtrl;

type = EEikCtLabel;

control = r_MobilDel1_label;

}

Till sist hittar vi då vår statiska textsträng som har ett id EMobilDel1LabelCtrl och definieras i strukturen:

RESOURCE LABEL r_MobilDel1_label

{

standard_font = EEikLabelFontLegend;

txt = STRING_r_MobilDel1_text;

}

string_r_MobilDel1_text definieras i filen MobilDel1.rls:

rls_string STRING_r_MobilDel1_text "MobilDel1"

I resursfilen hittar vi också en kommandolista som definierar vilka menyval som finns tillgängliga.

RESOURCE QIK_COMMAND_LIST r_MobilDel1_commands

Här definieras vilka menyer som ska vara tillgängliga inklusive namn på menyvalet. Med olika flaggor kan man styra var menyvalet hamnar, till exempel olika soft-keys. Varje menyval och kommando har ett unikt id, till exempel:

id = EMobilDel1InfoPrint1Cmd;

c++-koden är sedan relativt minimal; viktiga delar att notera är: I AppUi-klassens konstruktor, Constructl, skapar man sin vy och registrerar den i applikationsramverket.

CMobilDel1View* appView = CMobilDel1View::NewLC(*this);

AddViewL(*appView);

I View-klassen finns det en metod som heter ViewConstructl som laddar in vyns utseende som vi definierade i resursfilen.

ViewConstructFromResourceL(R_UI_CONFIGURATIONS);

I View-klassen finns också en metod, HandleCommandl som anropas av ramverket när användaren gör ett menyval. Här lägger man alltså in den programkod som ska utföras för olika val.

void CMobilDel1View::HandleCommandL(CQikCommand& aCommand)

{

switch(aCommand.Id())

{

// Just issue simple info messages to show that

// the commands have been selected case EMobilDel1InfoPrint1Cmd:

{

// Shows an infoprint iEikonEnv->InfoMsg (R_INFOPRINT1_TEXT);

break;

}

:

:

Ändra i exemplet

Nu ska vi göra en mindre ändring i vårt exempel. Ändringen består av att lägga till ett textfält där vi kan mata in vårt namn, koppla ett menyval till detta inmatningsfält och skriva ut »Hej ›inmatat namn‹« i den label som redan finns i vyn. För att åstadkomma detta behöver vi göra följande: Lägga till en texteditor-komponent i resursfilen. Denna resurs heter edwin. Vi kommer också att ändra ett av de existerande kommandona och menyvalen till en »Hej-meny«. Vi byter också till en »rad-layout« i stället för den ursprungliga vyn som använde en »grid-layout«. Den nya texteditorns id och det nya kommandots id måste definieras i filen MobilDel1.hrh. Det är en includefil som används både av resursfilen och c++-koden. I programmets vy:

- Inkludera eikedwin.h för att kunna använda texteditor-klassen CEikEdwin.

- Fångar det nya »Hej«-kommandot i HandleCommandL.

- Läser in texten som användaren har matat in i textfältet.

- Manipulerar texten genom att lägga till »Hej«.

- Skriver ut texten i vår labelkomponent.

- Begär att textkomponent ska rita om sig själv, genom att anropa metoden Drawnow. Skärmen uppdateras inte automatiskt bara för att man ändrar texten.

Gör ändringarna i programmet och bygg om för både emulatorn och telefon. Ibland kan man behöva göra en clean build efter att ha gjort ändringar: Project | Clean.

Övning: Ett program för minnesanteckningar

Tanken är att göra en enkel applikation som efter ett avslutat telefonsamtal ger användaren möjlighet att skriva en notering om samtalet som sedan lagras i "anteckningsfältet" för den man just pratat med. En förutsättning är då förstås att den man pratat med finns lagrad som en kontakt i telefonen.

Vi börjar på samma sätt som i förra exemplet, vi skapar ett skal för en applikation m h a Carbides wizard. Starta Carbide.c++ och välj File | New | C++ Application for UIQ Project i menyn. Ge ditt projekt ett namn, t ex "SamtalsNotering". Välj template "UIQ 3.x GUI Application". Gå sedan igenom resten av guiden, man behöver inte mata in något mer eller ändra något av de förvalda alternativen. Detta exempel är lämpligast att bygga direkt för telefonen och testar på den.

Allmänt om aktiva objekt

Symbian-applikationer använder sig normalt bara av en tråd. För att kunna göra flera saker "samtidigt" så använder man sig istället av något som kallas aktiva objekt. I praktiken så innebär det att man definierar och implementerar egna klasser som ärver från klassen CActive.

Ofta har då en applikation flera olika aktiva objekt som väntar på att olika händelser skall inträffa och när händelsen inträffar tar man hand om den i klassens RunL() metod.

I detta sammanhang pratar man också om asynkrona metoder. I olika APIer finns det ofta både synkrona och asynkrona varianter av en funktion som gör samma sak. Den synkrona varianten kommer att blockera applikationens tråd till dess att funktionen är klar. Tar funktionen lång tid att utföra så kommer applikationen inte vara mottaglig för input från användaren under tiden och det är inte alls bra. En asynkron metod sätter bara igång funktionen och kodraden efter exekveras omgående. Asynkrona metoder anropar man oftast från ett aktivt objekt. När sedan funktionen är klar anropas det aktiva objektets RunL() metod. Under tiden har applikationen kunnat göra andra saker, lyssna på användarinput och andra aktiva objekt kan ha körts.

CMyActive klassen

Vi börjar att utöka vår applikation med en ny klass CMyActive. Vi lägger därför till filerna:

- \inc\CMyActive.h (klassdefinition)

- \src\CMyActive.cpp (Implementation av klassens metoder)

Header-filen ser initialt ut så här:

#ifndef CMYACTIVE_H_

#define CMYACTIVE_H_

#include

//Aktivt objekt som prenumerarar på samtalsinformation

class CMyActive: public CActive

{

public:

static CMyActive* NewL();

~CMyActive();

void Start();

protected:

//Implementerar metoder definierade i basklassen CActive

void RunL();

void DoCancel();

TInt RunError(TInt aError);

private:

CMyActive();

void ConstructL();

private:

enum TState

{

EStart,

EWaitingForCall,

ECallInProgress,

EFindingContact,

EUpdatingContact

};

TState iState; //Tillstånd

protected:

//Implementerar metoder definierade i basklassen CActive

void RunL();

void DoCancel();

TInt RunError(TInt aError);

private:

CMyActive();

void ConstructL();

private:

enum TState

{

EStart,

EWaitingForCall,

ECallInProgress,

EFindingContact,

EUpdatingContact

};

TState iState; //Tillstånd

Notera hur klassen ärver från CActive och att man måste definiera metoderna RunL och DoCancel. Ofta är ett aktivt objekt en tillståndsmaskin, det är därför vi har definierat medlemsvariablen iState som kan anta ett antal olika värden.

Hur en första implementation i CMyActive.cpp ser ut kan du se i exempel1.txt

NewL() metoden är Symbians sätt att skapa objekt, så kallad tvåfas-konstruktion. Detta är intimt förknippat med några andra grundbultar i Symbian-programmering nämligen Cleanup-stacken och TRAP/Leave. Dessa tekniker används för att hantera möjliga felsituationer speciellt då att det är slut på internminne (RAM) i telefonen och programmet inte kan allokera mer minne. Allt detta beskrivs mycket detaljerat i SDK dokumentation och annan Symbian dokumentation så vi går inte in i mer detalj här.

Information om samtal

Vi vill veta när ett telefonsamtal kopplas upp och när det sedan avslutas. För detta kommer vi använda klassen CTelephony så vi måste inkludera:

#include //CTelephony med mera

I CMyActive klassen definierar vi också en medlemsvariabel som är en pekare till ett CTelephony objekt plus några andra medlemsvariabler som används för att hämta ut information om samtalet:

CTelephony* iTelephony;

CTelephony::TCallStatusV1 iLineStatus;

CTelephony::TCallStatusV1Pckg iLineStatusPckg;

I CMyActive::ConstructL() så skapar vi vårt CTelephony objekt:

void CMyActive::ConstructL()

{

//Skapa objekt för telefoni

iTelephony = CTelephony::NewL();

:

iLineStatus/iLineStatusPckg variablerna måste initieras.

CMyActive::CMyActive():CActive(EPriorityStandard),

iLineStatusPckg(iLineStatus)

{

CActiveScheduler::Add(this); //Måste göras för varje aktivt objekt

}

Kom även ihåg att ta bort detta objekt i klassens destruktor annars läcker vi minne.

CMyActive::~CMyActive()

{

Cancel();

//Ta bort alla objekt vi skapade i konstruktor

delete iTelephony;

}

Nu kommer vi till det aktiva objektets kärna, ett asynkront anrop (prenumeration) och RunL() metoden där vi hanterar att händelsen har inträffat.

void CMyActive::Start()

{

//Lyssna/prenumerera på samtalshändelser, ändringar av s k "call state"

iTelephony->NotifyChange(iStatus, CTelephony::EVoiceLineStatusChange, iLineStatusPckg);

SetActive();

iState = EWaitingForCall; //Nytt tillstånd, vi väntar på att ett samtal kopplas upp

}

Här anropar vi NotifyChange och definierar att vi vill bli informerade när "voice line status" ändras. Telefonlinjens tillstånd kommer vi att kunna läsa ut ur variabeln iLineStatusPckg som vi skickar med funktionsanropet. Notera att asynkrona metoder alltid har ett argument av typen TRequestStatus. Alla aktiva objekt har en medlemsvariabel, iStatus av denna typ, och denna skickar vi med i anropet.

RunL metoden blir ganska omfattande så det finns inte utrymme att ha med all kod i tidningen utan vi hänvisar till hemsidan.

I RunL kommer vi att hamna varje gång samtalet ändrar tillstånd. Tillståndet förändras typiskt så här för ett inkommande samtal: Ringing - Answering - Connected - (Disconnecting) - Idle.

1. Ladda ner och installera utvecklingsmiljön.

Du behöver en utvecklingsmiljö för att skriva C++-kod.

Carbide.c++ rekommenderas för nybörjare.

2. Skriv programmet

Den svåraste biten men

också den roligaste.

3. Testkör

Testa först i emulatorn på

datorn. När det fungerar

kan du gå vidare och

testa i en riktig telefon.

för steg>

\data\

Innehåller resursfiler

som delvis definierar

användargränssnittet. Alla

textsträngar bör defi nieras

här för att underlätta

översättning.

\group\

Viktiga filer som specificerar projektet. Vilka

källkodsfiler ingår, vilka

bibliotek ska man länka

mot. Dessa filer är oberoende

av vilket IDE man

använder.

\images\

Bitmap-filer som definierar

applikationens ikon (i olika

storlekar).

\inc\

Include-filer (*.h) som

definierar de ingående

klasserna.

\src\

Själva C++-koden där

klassernas metoder implementeras.

.project, .cdtbuild,

.cdtproject

Carbide-specifi ka fi ler

som lagrar inställningar

för projektet. Dessa har

genererats av Carbide++

och är ingenting man själv

ändrar i.

&Filer>

Var hittar jag mer information och får hjälp?

Efter att ha skrivit dina första enkla applikationer kanske du undrar var man hittar mer information för att komma vidare med att skriva mer avancerade applikationer.

Här är våra bästa tips:

- UIQ3 SDK innehåller dokumentation och en del exempelprogram. Dokumentationen består av referensdokumentation för alla klasser och API, men även mer beskrivande how-to-guider.

- Det är en bra idé att registrera sig på olika utvecklarforum. Här finns ytterligare programexempel, kunskapsdatabaser och forum med frågor och svar. De viktigaste adresserna för en utvecklare är:

UIQ Developer Community

http://developer.uiq.com

Sony Ericsson Developer World

http://developer.sonyericsson.com

Forum Nokia

www.forum.nokia.com

Innehåller nyttig information även om man utvecklar för en UIQ-telefon.

Symbian Developer Network

http://developer.symbian.com

www.newlc.com

Information>

De senaste Symbian-telefonerna använder version 9.1 av operativsystemet. Detta innehåller »platform security«, vilket innebär att applikationer måste certifieras enligt Symbian Signed för att komma åt viss funktionalitet.

Telefonens funktionalitet är uppdelad i olika »Capabilities« som sedan är grupperade i olika säkerhetsklasser Basic, Extended och Device Manufacturer. En applikation som bara använder basic capabilities, till exempel läser användardata, behöver inte signeras. Istället får användaren information om vad applikationen kan göra vid installationen och får därmed själv ge applikationen tillåtelse. Utvecklare kan förstås välja att certifiera även applikationer som bara använder basic capabilities. Det är kvalitetsstämpel och dessutom slipper användaren en del irriterande dialoger vid installationen.

Om din applikation använder extended capabilities så behöver man ett så kallat utvecklar-certifikat som man får via www.symbiansigned.com. I en liten applikation får man mata in vilka funktioner man behöver använda och test-telefonens(eller flera telefoners) IMEI-nummer.

På Symbian Signed finns de testkriterier som en applikation ska uppfylla för att den ska bli godkänd. När man testat sin applikation enligt denna specifikation laddar man upp den på Symbian Signed och väljer ett test-hus (Cap Gemini, mPhasiS, NSTL) som gör själva testningen och signeringen. Kostnaden per test varierar mellan 185 och 560 euro.

Platform Security och Symbian Signed är inte speciellt populärt bland tredjepartsutvecklare. Många anser att det är extremt struligt och hämmar utvecklingen av nya tredjepartsprogram till Symbian- plattformen.

En av de största marknadsplatserna för Symbian-program är Handango, www.handango.com. Förutom att ditt program läggs upp på deras webbplatser så sköter de hanteringen av licenser och betalningar.

När telefonlinjens status ändras till Connected kommer vi att lagra undan starttid. Dessutom kommer vi använda metoden CTelephony::GetCallInfo för att hämta ut:

- Inkommande eller utgående samtal

- Numret på den man pratar med om det finns tillgängligt.

if (iLineStatus.iStatus == CTelephony::EStatusConnected)

{

//Ett samtal har kopplats upp

TTime startTime;

startTime.HomeTime(); //Nu

iSamtalsInfo.iStart = startTime; //lagra undan start-tid

iState = ECallInProgress; //Nytt tillstånd

callSelectionV1.iSelect = CTelephony::EActiveCall;

//Hämta information om detta samtal

TInt err = iTelephony->GetCallInfo(callSelectionV1Pckg, callInfoPkg, remotePartyInfoPkg);

if (err == KErrNone)

{

CTelephony::TTelNumber number = remotePartyInfo.iRemoteNumber.iTelNumber;

CTelephony::TTelNumber dialledNumber = callInfo.iDialledParty.iTelNumber;

iSamtalsInfo.iDirection = remotePartyInfo.iDirection;

if (remotePartyInfo.iDirection == CTelephony::EMobileTerminated)

iSamtalsInfo.iTelNumber = number; //Incoming call

else

iSamtalsInfo.iTelNumber = dialledNumber; //Outgoing call

:

När status sedan ändras till EStatusIdle så räknar vi ut samtalets längd.

All information vi får fram lagrar vi en medlemsvariabel iSamtalsInfo av typen TSamtalsInfo som vi själva definierat i klassen CMyActive.

//Struktur där vi lagrar information om ett samtal

class TSamtalsInfo

{

public:

TTime iStart;//Starttid

TTimeIntervalSeconds iDuration;//Samtalets längd

CTelephony::TTelNumber iTelNumber;//Telefonnummer

CTelephony::TCallDirection iDirection;//Inkommnade/Utgående samtal

TContactItemId iCntId;//id på matchande kontakt

};

TSamtalsInfo iSamtalsInfo;

Andra tillståndsförändringar ignorerar vi, då anropar vi bara NotifyChange() igen så vi kommer att bli anropade när nästa tillståndsförändring sker.

iTelephony->NotifyChange(iStatus, CTelephony::EVoiceLineStatusChange, iLineStatusPckg);

SetActive();

När man använder en ny klass som CTelephony i sin applikation så kommer man få länkningsfel om man inte pekar ut motsvarande bibliotek (lib) i sitt projekt.

_image_

Man kan lägga till bibliotek i projektets properties.

Gör Add, och lägg till följande fil:

_image_

Notera att när man jobbar i emulatorn så lägger man till motsvarande *.lib fil som ligger under \epoc32\release\winscw\udeb.

I och med att vi använder CTelephony::GetCallInfo så måste vi ge applikationen en capability, ReadUserData. Även detta görs i Properties.

Sök i kontaktdatabasen

När ett samtal är avslutat så har vi samlat på oss information om starttid, samtalets längd och förhoppningsvis telefonnummer för den vi pratat med. Numret använder vi nu för att göra en sökning i kontaktdatabasen.

Vi börjar med att utöka CMyActive klassen med följande medlemsvariabler och de inkludera motsvarande header-filer.

CContactDatabase* iContactsDb;

CContactItemFieldDef* iCntFieldDef;

CIdleFinder* iFinder; //Används för sökning i kontakter

Sedan skapar vi några av dessa i klassens konstruktor.

void CMyActive::ConstructL()

{

//Skapa objekt för telefoni och kontakt-hantering

iTelephony = CTelephony::NewL();

iContactsDb = CContactDatabase::OpenL();

iCntFieldDef = new(ELeave) CContactItemFieldDef();

iCntFieldDef->AppendL(KUidContactFieldPhoneNumber); //search only tel numbers

iState = EStart;

}

Vi kommer att använda metoden FindAsyncL() i CContactDatabase.

CIdleFinder *FindAsyncL(const TDesC &aText, const CContactItemFieldDef *aFieldDef, MIdleFindObserver *aObserver);

aText är den sträng(telefonnummer) vi letar efter, aFieldDef är de fält som man vill leta i, vi har definierad att bara leta i fält som lagrar telefonnummer. Det här asynkrona anropet har inget TRequestStatus argument, utan använder sig av en annan teknik. Här skall man skicka med en pekare till ett objekt som man vill skall bli anropat med resultatet av sökningen.

I detta fall vill vi att vår CMyActive klass skall vara denna observer. Därför låter vi CMyActive ärva även från MIdleFindObserver.

class CMyActive: public CActive, public MIdleFindObserver

Att ärva från denna klass (eller så kallade mixin interface) innebär att vi måste implementera metoden IdleFindCallback() i CMyActive. Det är genom denna callback funktion vi kommer att få veta hur sökningen fortlöper.

Innan vi drar igång sökningen så tar vi och manipulerar det telefonnummer vi vill söka efter. Vi behåller bara de 8 sista siffrorna, detta för att undvika problem med hur nummer lagras i kontakter, t ex med +46, mellanslag, inledande nollor.

/Använd bara 8 sista siffrorna vid sökning, bli av med +46, 0, etc. 7 annat vanligt //värde också,

CTelephony::TTelNumber strippedNumber = iSamtalsInfo.iTelNumber.Right(8);

// Dra igång asynkron sökning i kontakt-databasen,

// IdleFindCallBack kommer rapportera hur sökningen går!

iFinder = iContactsDb->FindAsyncL(strippedNumber, iCntFieldDef, this);

this = pekare till sig själv, dvs vi talar om för kontaktdatabasen att det är vårt CMyActive-objekt där det finns en IdleFindCallback metod som skall anropas för att rapportera hur sökningen går.

Hur vår implementation av IdleFindCallback ser initialt ut kan du se i exempel2.txt.

IdleFindCallback kommer anropas ett flertal gånger men vi väntar tills vi får veta att sökningen är klar. Om det finns ett eller flera träffar så lagrar vi undan id för den första träffen.

Ytterligare en observer

Nu har vi all information inklusive kontaktid. Nu vill vi låta användaren mata in en notering och lagra den tillsammans med annan information om samtalet i motsvarande kontakt. Innan vi visar en dialog vill vi att vår applikation får fokus. Detta är lättast att implementera i AppUi-klassen och därför vill vi att CMyActive skall anropa AppUi-klassen. Detta löser vi med att göra en egen observer-klass. Lägg till följande i början av CMyActive.h

// Mixin-klass (motsvarande Javas interface)

// HandleContactLookupComplete metod måste implementeras i // ärvd klass

class MMyObserver

{

public:

virtual void HandleContactLookupComplete(const TSamtalsInfo& aSamtalsInfo)=0; //Pure virtual metod

protected:

virtual ~MMyObserver() {}

};

Sedan lägger vi till en medlemsvariabel i CMyActive.

MMyObserver* iObserver;

Och ändrar vårt interface till CMyActive något.

static CMyActive* NewL(MMyObserver* aObserver);

CMyActive(MMyObserver* aObserver);

CMyActive::CMyActive(MMyObserver* aObserver):CActive(EPriorityStandard),

iObserver(aObserver), iLineStatusPckg(iLineStatus)

{

Detta innebär också att konstruktionen av vårt CMyActive objekt måste ändras.

iTeleMonitor = CMyActive::NewL(this);

I vår AppUi-klass så ärver vi nu även från MMyObserver och implementerar callback-funktionen HandleContactLookupComplete.

class CSamtalsNoteringAppUi : public CQikAppUi, public MMyObserver

{

public:

// from CQikAppUi

void ConstructL();

~CSamtalsNoteringAppUi();

void HandleContactLookupComplete(const TSamtalsInfo& aSamtalsInfo);

Implementationen av callback-funktionen ser ut så här. Vi kommer att återkomma till iDialogHandler.

void CSamtalsNoteringAppUi::HandleContactLookupComplete(const TSamtalsInfo& aSamtalsInfo)

{

//Aktivera vår egen applikations vy så vår app får fokus:

TVwsViewId viewId(KUidSamtalsNoteringApp,KUidSamtalsNoteringView);

TRAPD(err, ActivateViewL(viewId));

iDialogHandler->Start(aSamtalsInfo);

//Börja lyssna efter nästa samtal.

iTeleMonitor->Start();

}

Till slut måste vi se till att callback-funktionen anropas från CMyActive klassen efter att vår sökning lyckats.

if (idArray->Count() >= 1)

{

//1 eller flera träffar

iSamtalsInfo.iCntId = (*idArray)[0];

//Anropa vår observer = AppUi-objektet

iObserver->HandleContactLookupComplete(iSamtalsInfo);}

En enkel (asynkron) dialog

Vi definierar ytterligare en klass som är ett aktivt objekt. Denna klass följer samma mönster som CMyActive. Hur den ser ut kan du se i exempel3.txt

I Start metoden kommer vi att dra igång en dialogbox som inte blockerar vårt program. När användaren stänger dialogen med någon knapp så kommer vår RunL metod att anropas.

void CAsyncDialogHandler::Start(const TSamtalsInfo& aSamtalsInfo)

{

//Lagra undan samtalsinfo i objektets medlemsvariabel.

iSamtalsInfo = aSamtalsInfo;

if (!IsActive())

//Om dialogen fortfarande visas för föregående samtal, så struntar vi att ta hand om //nästa samtal....kan göras bättre såklart

{

iStatus = KRequestPending; //Workaround pga ofullkomlighet i UIQ3 Simple dialog

iDialog = new (ELeave) CQikSimpleDialog(); //Skapa dialog objekt

iDialog->PrepareL(R_DLG_OK_CANCEL); //Läs in layout från resursfil

iDialog->RunL(iStatus); //Kör/visa dialogen, metoden returnerar omedelbart

SetActive();

}

}

Dialogens utseende definieras som en struktur, R_DLG_OK_CANCEL, i resursfilen SamtalsNotering.rss, se källkoden på vår hemsida, i filen exempel 4

Uppdatera information i kontaktdatabasen

Metoden CreateCallLogTextL skapar en textsträng som innehåller tidpunkt för samtalet, samtalets längd, inkommande eller utgående samtal och den text som användaren matat in i dialogboxen. UpdateContactNotesFieldL tar sedan texten och lägger in den under rätt kontakt. Se exempel5.txt

I och med att vi ändrar data i kontakter så måste vi ge vår applikation ytterligare en capability, WriteUserData.

Källa