Symbian3/SDK/Source/GUID-A8130D83-E684-5B6C-BDFE-EB6EE3CD49E8.dita
author Dominic Pinkman <Dominic.Pinkman@Nokia.com>
Thu, 21 Jan 2010 18:18:20 +0000
changeset 0 89d6a7a84779
child 2 ebc84c812384
permissions -rw-r--r--
Initial contribution of Documentation_content according to Feature bug 1266 bug 1268 bug 1269 bug 1270 bug 1372 bug 1374 bug 1375 bug 1379 bug 1380 bug 1381 bug 1382 bug 1383 bug 1385

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-A8130D83-E684-5B6C-BDFE-EB6EE3CD49E8" xml:lang="en"><title>Writing
a UPS Dialog Creator</title><prolog><metadata><keywords/></metadata></prolog><conbody>
<section><title>Introduction</title> <p>Dialog creators are EComplug-ins that
device creators can write to generate the dialogs containing prompts for phone
users. </p> <p>The plug-in has an API that consists of two asynchronous functions: </p> <ul>
<li id="GUID-96CBCE79-4F5D-5F87-AC6B-C366346447AB"><p>The <codeph>PrepareDialog()</codeph> function.
This function is called first by the UPS server. It enables the dialog creator
to query other system servers such as AppArc or the SIS registry to retrieve
additional information to display in the dialog. For example it might query
the SIS registry using the client application’s secure id. </p> </li>
<li id="GUID-A439E217-B95B-5B68-8893-BDBD61D694D1"><p>The <codeph>DisplayDialog()</codeph> function.
This function is called second by the UPS server. It displays the prompt,
most commonly through the notification framework. This function also returns
the option selected by the user and, if applicable, the fingerprint for a
new decision record. </p> </li>
</ul> <p>The UPS displays only one prompt at a time so it is possible for
there to be a delay between calling the function to prepare the dialog and
the function to display the dialog. It is also possible for other dialogs
to be displayed between the dialog being prepared and its being displayed. </p> <p>Both <codeph>PrepareDialog()</codeph> and <codeph>DisplayDialog()</codeph> are asynchronous and must support cancellation through <codeph>CActive::Cancel</codeph>.
If either function is cancelled, the dialog creator instance is destroyed
without calling further methods. </p> <p>The work split between <codeph>PrepareDialog()</codeph> and <codeph>DisplayDialog()</codeph> described
above is a recommendation, and some of the functionality could be implemented
directly in the notifier implementation. </p> <p>In the example given in this
document, the functionality for dialogs is implemented separately from the
functionality for policy evaluators. This allows multiple policy evaluators
to share common UI code. However, it is possible to deliver policy evaluator
and dialog creator plug-ins in the same DLL. </p> </section>
<section><title>Procedure</title> <p>Dialog creators implement the <codeph>CDialogCreator</codeph> interface.
This section shows how to implement the functions that prepare and display
the user prompt. </p> <ol id="GUID-0F29F8B7-F303-5D42-BB95-A32B1FE13A9A">
<li id="GUID-9FDDAD1F-4B9A-516A-8A00-0C331F38C4CA"><p>Prepare a dialog using
the <xref href="GUID-2308E2F4-A878-3B0A-951B-EFC4908AD9BB.dita"><apiname>PrepareDialog()</apiname></xref> function. </p> </li>
<li id="GUID-45C16A52-A05E-545A-AB3A-967CCA35BB15"><p>Display the dialog using
the <xref href="GUID-E6C3B0F0-43A7-3656-946B-5CFE97DCFC80.dita"><apiname>DisplayDialog()</apiname></xref> function. </p> </li>
</ol> <p>The Dialog Creator plug-in creates a dialog prompt in cases where
no previous decision is found in the decision database. </p> <p><b> Preparing
the dialog</b> </p> <p>The parameters to <codeph>PrepareDialog()</codeph> are
mostly <codeph>const</codeph> pointers and references to the data that has
already been generated by the UPS or policy evaluator. </p> <p>The following
table describes the parameters for the <codeph>PrepareDialog()</codeph> function: </p> <table id="GUID-6D139216-B6A8-55A1-8D9B-C15134198198">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<thead>
<row>
<entry>Parameter</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><p> <codeph>aRequest</codeph>  </p> </entry>
<entry><p>Data that the system server provides to the UPS, including the ClientSid,
ServerSid and ServiceId. </p> </entry>
</row>
<row>
<entry><p> <codeph>aPolicy</codeph>  </p> </entry>
<entry><p>Details of the policy for the service. </p> </entry>
</row>
<row>
<entry><p> <codeph>aFingerprints</codeph>  </p> </entry>
<entry><p>A pointer to the fingerprints array generated by the policy evaluator.
(If the user selects "Always" or “Never”, the dialog creator returns a pointer
to an existing fingerprint object instead of re-generating the fingerprint.) </p> </entry>
</row>
<row>
<entry><p> <codeph>aClientEntity</codeph>  </p> </entry>
<entry><p>Details of client entity (will be null if the client process is
not an execution host or the policy evaluator does not support client entities). </p> </entry>
</row>
<row>
<entry><p> <codeph>aEvalPrivateData</codeph>  </p> </entry>
<entry><p>Opaque data, which can be any other information for use in the fingerprint
or to be displayed in the dialog. </p> </entry>
</row>
<row>
<entry><p> <codeph>aStatus</codeph>  </p> </entry>
<entry><p>The request status used to contain completion information for the
function. </p> </entry>
</row>
</tbody>
</tgroup>
</table> <p><note/> The UPS does not allow any responses to be returned
to the system server except those defined in the UPS policy file. If the dialog
creator returns an option that was not specified in the policy, the request
is rejected and <codeph>EUpsDecNo</codeph> is returned. </p><p>Your implementation
can assume that the pointers remain valid until after <codeph>DisplayDialog()</codeph> has
been called. </p><p>The <codeph>PrepareDialog()</codeph> function sets values. </p><p>The<codeph> DoPrepareDialogL()</codeph> function
prepares the data for the prompt. The DoPrepareDialogL() function is called
through a switch statement, which can be seen in the full code sample at the
end of this. </p> <p><b>Displaying the dialog </b> </p> <p>The <codeph>DisplayDialog()</codeph> function
displays the dialog created by <codeph>PrepareDialog()</codeph>. On completion,
it sets the option selected by the user and the fingerprint value if “Always”
or “Never” was selected. Usually, dialogs are displayed using the notifier
framework, but device creators are free to use other mechanisms. </p> <p>On
completion <codeph>iOptionSelected</codeph> must be set to the option selected
by the user: Yes, No, Session, Always or Never. </p> <ul>
<li id="GUID-C657A459-6ED4-59EF-9A8A-C9FE41AF2DD0"><p>If the user selects
“Always” or “Never”, <codeph>iFingerprint</codeph> must be set to point to
the fingerprint to use for the new decision record. Usually, this would just
point to one of the fingerprints passed to <codeph>PrepareDialog()</codeph>,
but generating a new fingerprint is also permitted. </p> </li>
<li id="GUID-0E2690AB-B44B-5C8B-9365-E09BC3031398"><p>If the decision record
already exists and <codeph>DisplayDialog()</codeph> modifies the value of <codeph>aEvaluatorInfo</codeph>,
the record is updated with the new value. </p> </li>
</ul> <p>In the example at the end of this section, the <codeph>DisplayDialog()</codeph> function
sets values. The <codeph>DoDisplayDialogL()</codeph> function calls the notifier
framework to display the dialogs. The <codeph>DoDisplayDialogL()</codeph> function
is called through a <codeph>switch</codeph> statement, which can be seen in
the full code sample at the end of this section: </p> </section>
<section><title>Example</title> <p>The following code shows an example of
a full implementation of the dialog creator file: </p> <codeblock id="GUID-314673F2-BBA0-56C0-A76D-07862BB4592F" xml:space="preserve">// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Symbian Foundation License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.

// refdialogcreator.cpp


#include "refdialogcreator.h"
#include &lt;ecom/implementationproxy.h&gt;
#include &lt;apaid.h&gt;
#include &lt;apgcli.h&gt;
#include &lt;ups/promptrequest.h&gt;
#include &lt;swi/sisregistrypackage.h&gt;
#include &lt;swi/sisregistrysession.h&gt;
#include &lt;scs/nullstream.h&gt;
#include &lt;s32mem.h&gt;

static const TUint KRefDialogCreatorImplementationId = 0x10283694;

static const TUint KRefNotifierImplementationId = 0x1028369B;

CDialogCreator* CRefDialogCreator::CreateDialogCreatorL()
/**
Factory method that instantiates a new dialog creator EComplug-in.

@return A pointer to the new reference dialog creator object.
*/
    {
    CRefDialogCreator* self = new (ELeave)CRefDialogCreator();
    CleanupStack::PushL(self);
    self-&gt;ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

static const TImplementationProxy ImplementationTable[] = 
    {
    IMPLEMENTATION_PROXY_ENTRY(KRefDialogCreatorImplementationId, CRefDialogCreator::CreateDialogCreatorL)
    };

EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt&amp; aTableCount)
/**
Standard EComfactory
*/
    {
    aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
    return ImplementationTable;
    }    
    

CRefDialogCreator::CRefDialogCreator() 
/**
Constructor
*/
    : CDialogCreator(), iPromptResult(), iPromptResultPckg(iPromptResult), iState(EIdle)
    {
    CActiveScheduler::Add(this);    
    }
    
CRefDialogCreator::~CRefDialogCreator()
/**
Destructor
*/
    {
    Deque();
    delete iPromptData;
    iPromptDataDes.Close();
    iNotifier.Close();
    }

void CRefDialogCreator::ConstructL()
/**
Second phase constructor
*/
    {
    User::LeaveIfError(iNotifier.Connect());
    }

void CRefDialogCreator::DoCancel()
    {
    if (iState == EProcessResult)
        {
        iNotifier.CancelNotifier(TUid::Uid(KRefNotifierImplementationId));
        }
    if (iClientStatus)
        {
        User::RequestComplete(iClientStatus, KErrCancel);
        }
    }
    
TInt CRefDialogCreator::RunError(TInt aError)
    {
    if (iClientStatus)
        {
        User::RequestComplete(iClientStatus, aError);
        }
    return KErrNone;
    }

void CRefDialogCreator::RunL()
    {
    User::LeaveIfError(iStatus.Int());
    switch (iState)
        {
        case EPrepareDialog:
            DoPrepareDialogL();
            break;
        case EDisplayDialog:
            DoDisplayDialogL();
            break;
        case EProcessResult:
            DoProcessResultL();
            break;
        default:
            ASSERT(EFalse);            
        }
    }
    
void CRefDialogCreator::DoPrepareDialogL()
    {
    iPromptData = CPromptData::NewL();
    
    // Only one state at the moment but more should be
    // added for long running operators e.g. querying the SIS registry
    // or resolving the client entity.
    ResolveClientNameL(iRequest-&gt;ClientSid());
    
    // Get the vendor name for the client process
    ResolveVendorNameL(iRequest-&gt;ClientVid());
    
    // Server / Service localized names generated in notifier plug-in. 
    iPromptData-&gt;iServerSid = iRequest-&gt;ServerSid();
    iPromptData-&gt;iServiceId = iRequest-&gt;ServiceId();
    
    // Different dialog text is displayed depending on whether the client application
    // is signed.
    // N.B. Protected SID is assumed to be signed or included at ROM build.
    if (iRequest-&gt;IsClientSidProtected()) iPromptData-&gt;iFlags |= ETrustedClient;
    
    // Use the options specified by the policy
    iPromptData-&gt;iOptions = iPolicy-&gt;Options();
    
    // Add the descriptions of the fingerprints. This could be used
    // to allow the user to grant access to all destinations 
    // or a single destination.
    TInt count = iFingerprints-&gt;Count();
    for (TInt i = 0; i &lt; count; ++i)
        {
        HBufC* description = (*iFingerprints)[i]-&gt;Description().AllocLC();
        iPromptData-&gt;iDescriptions.AppendL(description);
        CleanupStack::Pop(description);
        }
    
    User::RequestComplete(iClientStatus, KErrNone);
    // DisplayDialog is invoked by the UPS, this just verifies 
    // that PrepareDialog was called first.
    iState = EDisplayDialog;
    }
    
void CRefDialogCreator::DoDisplayDialogL()
/**
Uses the notifier framework to display the dialog.
*/
    {
    // Externalize the prompt data to a descriptor
    RNullWriteStream ns;
    ns &lt;&lt; *iPromptData;
    ns.CommitL();
    iPromptDataDes.CreateL(ns.BytesWritten());
    RDesWriteStream ws;    
    ws.Open(iPromptDataDes);
    ws &lt;&lt; *iPromptData;
    ws.CommitL();    
    iNotifier.StartNotifierAndGetResponse(iStatus, TUid::Uid(KRefNotifierImplementationId),
        iPromptDataDes, iPromptResultPckg);
    SetActive();
    iState = EProcessResult;
    }
    
void CRefDialogCreator::DoProcessResultL()
/**
Processes the result returned by the notifier.
*/
    {
    if (iPromptResult.iSelected == CPolicy::EAlways ||
        iPromptResult.iSelected == CPolicy::ENever)
        {
        // The Always or Never option was selected so return the fingerprint 
        // for the new decision record.
        // 
        // In this implementation a copy of the original fingerprint is returned. However,
        // it is permitted to return a different fingerprint e.g. a modifier description.        
        if (iPromptResult.iDestination &gt;= 0 &amp;&amp; iPromptResult.iDestination &lt; iFingerprints-&gt;Count())        
            {
            *iFingerprint = (*iFingerprints)[iPromptResult.iDestination];
            }
        else
            {
            ASSERT(EFalse);    // should never happen, unless the notifier has errors.
            }
        }            
    *iOptionSelected =    iPromptResult.iSelected;
    iState = EIdle;
    User::RequestComplete(iClientStatus, KErrNone);        
    }

void CRefDialogCreator::ResolveVendorNameL(const TVendorId&amp; aVid)
/**
Looks up the localized vendor name for the client process and writes
this to iPromptData-&gt;iVendorName.

Typically, this would be resolved from the SIS registry or a lookup table.

@param aVid    The vendor id of the client process.
*/
    {
    if (iPromptData-&gt;iVendorName.Length() != 0)
        {
        // already obtained vendor name from SIS registry
        return;
        }
        
    if (aVid.iId == 0x70000001)
        {
        _LIT(KSymbian, "Symbian Foundation");
        iPromptData-&gt;iVendorName.Create(KSymbian);
        }
    else 
        {
        _LIT(KUnknown, "Unknown vendor");
        iPromptData-&gt;iVendorName.Create(KUnknown);
        }
    }
    
void CRefDialogCreator::ResolveClientNameL(const TSecureId&amp; aSid)
/**
Generates a human readable name for the client process. In order of 
preference the following data is returned

- The AppArc caption name.
- The localized package name that owns this SID.
- A value from a lookup table.
- The filename for the client process executable.

@param aSid    The secure id of the client process.
*/
    {
    TBool found = EFalse;
    
    // Although the client name from AppArc takes precedance the SIS
    // registry is always invoked in order to retrieve the vendor name
    found |= ResolveClientNameFromSisRegistryL(aSid);
    found |= ResolveClientNameFromAppArcL(aSid);
            
    // A lookup that maps secure-ids to application names could
    // be used here.

    // Fall back to the filename of the client process
    // The original thread may have exited so the process handle is used instead.
    // because the client-side object e.g. RSocket may be shared between threads.

    // If the process has exited then it's o.k. to leave.
    if (! found)
        {            
        RProcess clientProcess;
        User::LeaveIfError(clientProcess.Open(iRequest-&gt;ClientProcessId()));
        CleanupClosePushL(clientProcess);
        iPromptData-&gt;iClientName.Create(clientProcess.FileName());        
        CleanupStack::PopAndDestroy(&amp;clientProcess); 
        }
    }

TBool CRefDialogCreator::ResolveClientNameFromAppArcL(const TSecureId&amp; aSid)
/**
Gets the caption name for the application from AppArc (if available).

@param    aSid    The secure id of the client process.
@return            ETrue if a match was found in apparc; otherwise, EFalse is returned.
*/
    {
    TBool found(EFalse);
        
    RApaLsSession apa;
    CleanupClosePushL(apa);    
    TInt err = apa.Connect();
    if (err == KErrNone)
        {        
        TApaAppInfo* info = new(ELeave) TApaAppInfo();
        CleanupStack::PushL(info);
        
        err = apa.GetAppInfo(*info, TUid::Uid(aSid));
        if (err == KErrNone)
            {
            iPromptData-&gt;iClientName.Close();
            iPromptData-&gt;iClientName.Create(info-&gt;iCaption);
            found = ETrue;
            }
        else if (err != KErrNotFound)
            {
            User::Leave(err);
            }    
        CleanupStack::PopAndDestroy(info); 
        }
    else if (err != KErrNotFound)
        {
        // If the connection to apparc failed with KErrNotFound
        // then the error is ignored becase we assume the dialog
        // creator was invoked from text-shell
        User::Leave(err);
        }
    CleanupStack::PopAndDestroy(&amp;apa);
    return found;
    }
    
TBool CRefDialogCreator::ResolveClientNameFromSisRegistryL(const TSecureId&amp; aSid)
/**
Retrieves the client and vendor information from the SIS registry.
@param aSid        The secure-id of the client application to lookup in the registry.
@return            ETrue, if the lookup was successful; otherwise, EFalse is returned.
*/
    {
    TBool found(EFalse);
    Swi::RSisRegistrySession r;
    User::LeaveIfError(r.Connect());
    CleanupClosePushL(r);
    
    Swi::CSisRegistryPackage* p(0);
    TRAPD(err, p = r.SidToPackageL(TUid::Uid(aSid.iId)));
    if (err == KErrNone)
        {
        iPromptData-&gt;iClientName.Create(p-&gt;Name());
        iPromptData-&gt;iVendorName.Create(p-&gt;Vendor());
        found = ETrue;
        delete p;
        }
    CleanupStack::PopAndDestroy(&amp;r);
    return found;
    }

// From CDialogCreator
void CRefDialogCreator::PrepareDialog(
    const UserPromptService::CPromptRequest&amp; aRequest, const CPolicy&amp; aPolicy,            
    const RPointerArray&lt;CFingerprint&gt;&amp; aFingerprints, const CClientEntity* aClientEntity,
    const TAny* aEvalPrivateData, TRequestStatus&amp; aStatus)
    {
    aStatus = KRequestPending;
    iClientStatus = &amp;aStatus;
    
    iRequest = &amp;aRequest;
    iPolicy = &amp;aPolicy;
    iFingerprints = &amp;aFingerprints;
    iEvalPrivateData = aEvalPrivateData;
    (void) aClientEntity;

    // Kick off dialog creator state machine
    iState = EPrepareDialog;
    iStatus = KRequestPending;
    TRequestStatus* status = &amp;iStatus;
    SetActive();
    User::RequestComplete(status, KErrNone);
    }
    
void CRefDialogCreator::DisplayDialog(CPolicy::TOptions&amp; aOptions, const CFingerprint*&amp; aFingerprint,
        TUint&amp; aEvaluatorInfo, TRequestStatus&amp; aStatus)
    {    
    aStatus = KRequestPending;
    iClientStatus = &amp;aStatus;
    
    iOptionSelected = &amp;aOptions;
    iFingerprint = &amp;aFingerprint;
    aFingerprint = 0;
    iEvaluatorInfo = &amp;aEvaluatorInfo;
    iClientStatus = &amp;aStatus;
    
    // Start state machine
    ASSERT(iState == EDisplayDialog); // PrepareDialog should have been called first
    iStatus = KRequestPending;
    TRequestStatus* status = &amp;iStatus;
    SetActive();
    User::RequestComplete(status, KErrNone);
    }
</codeblock> </section>
</conbody></concept>