首 页 | 新 闻 | Symbian | Android| Windows Mobile | J2ME | 下载中心 | 游戏策划招聘与求职 | 购书指南 | 视频教程
您现在的位置: 开发视界 >> Symbian英文资料 >> Network >> 正文
Launching an application on a file arriving into the Inbox
作者:佚名    文章来源:不详    更新时间:2006-5-7 11:17:24

Our final aim is to create an application that can be used in two ways: first, launched as usual using its icon in one of the application folders, second, to have it launched for us if the user starts a specific file received in the Messaging Inbox (arriving from another phone, through SMS, MMS, e-mail or via Bluetooth or infrared). We expect our application to be able to handle this file, either by displaying or processing it-the exact details will, of course, depend on your actual application.

A Detour on Recognizers

Recognizers are described in another tutorial (and also in the Document Handler documentation PDF in the SDK) but let’s quickly recap the relevant details here.

Recognizers are separate DLLs (they work completely independently from your main application) copied into a fixed directory in the phone. When the user launches a file from the Inbox, the system calls the recognizers in turn to help decide the nature of the file. The recognizers get a chance to check both the file extension and to actually read into the beginning of the file to look for header data they might recognize. As a result, the recognizer can report how certain it is to have recognized the file and its format. In the end, the recognizer will return a MIME type (the same recognizer can recognize different file types and return several MIME types, you only have to write one DLL even if your program can handle more than one file format).

It’s this MIME type returned that creates the link between the recognizer and your application. Your application has to advertise the list of MIME types it claims to accept in its AIF resource. The system will choose arbitrarily from the applications present in the phone. Applications can specify their priority in handling the given format and also can claim the status of being the default handler but this might not be enough in all cases (eg. the user might run another application and set it the default handler, thus stealing this status before your application gets a chance to reclaim it).

If you want to be sure that your application is and remains the only one to handle your proprietary format, you have to take several steps. First, try to devise a unique extension. This is not yet bulletproof as somebody else might happen to use the same name. Add a unique header consisting of, for instance, your application ID and other unique data, including some kind of a checksum to check for the integrity of the header data and create your recognizer to recognize this information. Also, create a unique MIME type for your application.

Once you have your recognizer working, all you have to do is to make your application embeddable (eg. allowing it to be called from the context of another application, Messaging in this case) by settings its embeddability property to KAppEmbeddable in the AIF resource file.

*

Now, we will see how to make our application accept to be launched from the Inbox. The document handler architecture makes this completely automatic: if the recognizer in fact recognizes the incoming file and returns the appropriate MIME type and your application happens to be selected the appropriate handler (which is always the case if it is the only one in the system that handles this format), the application will be started automatically. You can easily recognize its embedded status if you check the icon in the title pane: it will be that of Messaging, not your own.

The more interesting question is how to learn what file the user clicked on and how to process it. Here, we have two alternative solutions. You can only use the simpler one if processing the file can happen in the background, fast enough not to require any warning or progress note, and not relying on any form of user interaction. If you might need to warn the user, ask for permission to overwrite files or anything similar, you have to use the second alternative.

The Simpler Solution

First, create a public function in your application user interface class (the one derived from CAknViewAppUi). Its only task will be to make the iDoorObserver member field available-it is protected so it couldn’t be called directly from other classes:

public:
 inline TBool IsRunningEmbedded () {
   return iDoorObserver != NULL;
 };

Second, override OpenFile() in your document (this is the class you derive from CAknDocument). This step is required in the documentations on the document handler but we’ll implement it slightly differently. Normally, the document handler expects the file to be a usual Symbian file store but we won’t rely on it: this allows us to accept any file format, plain text, pictures, anything.

So, instead of calling CEikDocument::OpenFileL() as instructed in all available documentation, we will call the otherwise empty and non-functional variant CAknDocument::OpenFileL():

CFileStore* CMyDocument::OpenFileL (TBool doOpen, const TDesC& filename, RFs& fs) {
 CFileStore* result = CAknDocument::OpenFileL (doOpen, filename, fs);
 CMyAppUi MyAppUi = (CMyAppUi) iAvkonAppUi;
 if (MyAppUi->IsRunningEmbedded ()) {
   ProcessTheFileAsYouPlease (filename);
   }
 return result;
}

OpenFile() is called by the system before the event loop is started to handle the normal running of the program. Therefore, we have to stress again, you only can use this approach if your processing is reasonably fast and completely self-contained, not relying on any other part of the application architecture or user interface. If it does, you have a little more work to do.

The More Difficult Solution

In this more common case, we have to deter running our processing function until a safer time when the application event loop has already been started. We can accomplish this by using an active object.

But first, let’s add a public field to our AppUi class. Its purpose will be to store the launched file name:

public:
 TFileName ImportFile;

Second, we need IsRunningEmbedded() again, just like in the first solution:

public:
 inline TBool IsRunningEmbedded () {
   return iDoorObserver != NULL;
 };

Third, we will continue to override OpenFile() but our processing will be slightly different this time:

CFileStore* CMyDocument::OpenFileL (TBool doOpen, const TDesC& filename, RFs& fs) {
 CFileStore* result = CAknDocument::OpenFileL (doOpen, filename, fs);
 CMyAppUi MyAppUi = (CMyAppUi) iAvkonAppUi;
 if (MyAppUi->IsRunningEmbedded ()) {
   MyAppUi->Launcher = CMyLaunch::NewL ();
   MyAppUi->ImportFile = filename;
   MyAppUi->Launcher->Start (0);
   }
 return result;
}

We create an active object and start it immediately. The object contains a timer and when the specified time interval will have been elapsed, it will call our processing routine. Active objects will be served by the event loop mechanism itself, so in this way we can make sure it won’t be called earlier than that. But we don’t need to wait any more than that, either, so we can simply specify zero as a delay for firing our object.

The active object itself is practically out of the book. The header is completely standard:

class CMyLaunch : public CActive {
 public:
   static CMyLaunch* NewL ();
   ~CMyLaunch ();
   void Start (TTimeIntervalMicroSeconds32 delay);
 private:
   CMyLaunch ();
   void ConstructL ();
   void RunL ();
   void DoCancel ();
   TInt RunError (TInt error);
 private:
   RTimer Timer;
 };

The implementation is very straightforward, too. We use EPriorityUserInput to give it a relatively high priority so that it will be started very early, as soon as possible after the event loop takes off:

CMyLaunch::CMyLaunch () :
 CActive (CActive::EPriorityUserInput) {
 CActiveScheduler::Add (this);
}

The following member functions are standard again:

CMyLaunch* CMyLaunch::NewL () {
 CMyLaunch* self = new (ELeave) CMyLaunch ();
 CleanupStack::PushL (self);
 self->ConstructL ();
 CleanupStack::Pop (self);
 return self;
}

CMyLaunch::~CMyLaunch () {
 Cancel ();
 Timer.Close ();
}

void CMyLaunch::Start (TTimeIntervalMicroSeconds32 delay) {
 _LIT (KTimerPanic, "Launch");
 __ASSERT_ALWAYS (!IsActive (), User::Panic (KTimerPanic, 1));
 Timer.After (iStatus, delay);
 SetActive ();
}

void CMyLaunch::ConstructL () {
 User::LeaveIfError (Timer.CreateLocal ());
}

void CMyLaunch::DoCancel () {
 Timer.Cancel ();
}

TInt CMyLaunch::RunError (TInt) {
 return KErrNone;
}

The only interesting part is the function called when the delay elapses but this only calls our processing function, passing it the name of the file used to launch the application:

void CMyLaunch::RunL () {
 CMyAppUi* MyAppUi = (CMyAppUi*) iAvkonAppUi;
 ProcessTheFileAsYouPlease (MyAppUi->ImportFile);
}

The CMyLaunch* Launcher variable is in our AppUi class. After our processing, we can dispose of the active object by deleting it (we could also put it into our CAknDocument-derived document class and leave it to its destructor to delete it).

delete MyAppUi->Launcher;

And this concludes our description. Our application will be launched when the user clicks on its incoming file and we will be able to process it as required by our application logic.

(Gbor DE K JAHN)

相关文章:
How to reset the alternate makmake entry in Codewarrior
Observer Pattern in Symbian application
Change the application language at runtime for Series 60 3rd Ed.
How to detect if an application is launched by user or the startup list
Retrieving IMEI, IMSI, Network Info (Cell Id, Location Code) on 3rd Edition.
Hashtable implementation for Symbian
Carbide.vs - Disabling the MMP/PKG File update feature
Codewarrior: how to avoid the "Too Many Include Paths" error when using the UIQ 2.1 SDK
 

站点地图 | 加入收藏 | 联系站长 | 广告服务 |
QQ:280529124  Tel:0592-8271361 辽ICP备05021703号