Palm Programmer's Laboratory
Palm OS Programmer's Companion Volume I/10-1
10-1 ユーザーに対するアテンション
Palm OS 4.0 より、ユーザーアテンションに関するアプリケーションとドライバ間で競合する要求を管理するための標準的な仕組みが導入されました。この仕組みはアテンションマネージャとして知られています。
アテンションマネージャの役割
このセクションでは、アテンションマネージャについて簡単に紹介します。アテンションやアラームとノティフィケーションマネージャの間の関係について説明し、アテンションマネージャの使用が適切な状況について説明します。
アテンションマネージャは、重要な何かが発生したことをアプリケーションからユーザーに知らせるための標準的なメカニズムを提供します。これは明示的なユーザー操作なしでデバイスがデータを受け取れるようなコミュニケーションをサポートするようにデザインされています。アテンションマネージャはユーザーとのやりとりだけを担当し、イベントの生成は行ないません。アラームマネージャをアテンションマネージャと組み合わせて使うことで、特定の日時の到達をユーザーに知らせることができます。
“アラームのような”ものを全て1つのリストで管理することにより、アテンションマネージャはユーザーが長期間ハンドヘルドに触れていないかった場合の操作性を向上しています。古いアラームのダイアログをいくつもタップすることはありません。通常、ユーザーは過ぎさった予定のほとんどを気にしませんが、そのうちのいくつかは気にするかもしれません。アテンションマネージャがないと、ユーザーは選択的に破棄したりフォローアップしたりできません。
アプリケーションは使用可能なアテンションの種類について、完全に制御できます。アプリケーションはハンドヘルドに対し、サウンド、バイブレーション、LED を含む利用可能な特殊効果を問合せて、それを利用することができます。デフォルトオプションはビーブ音で、その他の全てのオプションはオンまたはオフになっています。複数の振動パターンやマルチカラー LED は現在サポートされていません。この特殊効果は拡張可能であることに注意して下さい。ハンドヘルドメーカーは LED やバイブレーションが予期されるところに別の手段を使うことでユーザーの注意を喚起することができます。
- IMPORTANT
- アテンションマネージャは Palm OS 4.0 から導入されました。それよりも古いバージョンの Palm OS で動作するアプリケーションでは、“アラーム”で説明するテクニックを使用する必要があります。
Palm OS 4.0 では、予定表、SMS、およびクロックアプリケーションがアテンションマネージャを使用しています。アテンションマネージャとアラームマネージャの使用に関する実践的な例については、Datebook アプリケーションのソースコードを参照して下さい。
アテンション、アラーム、およびノティフィケーション
アテンションマネージャ、アラームマネージャ、およびノティフィケーションマネージャは、組み合わせて使用されることの多い別々のサブシステムです。
- アテンションマネージャは、ユーザーに注意を促す必要のあるイベントがユーザーと対話するためだけにデザインされています。
- アラームマネージャは特定時刻の到来に対して、単純にアプリケーションにイベントを送信します。アプリケーションはアテンションマネージャや他のなんらかの仕組みを使用してユーザーに注意を促すためのアラームを表示します。
- ノティフィケーションマネージャは、システムレベルやアプリケーションレベルのイベントが発生した際に、そのイベントの受信を登録しているアプリケーションに通知を行ないます。ユーザーがイベントを通知を受けることになっていれば、アプリケーションはアテンションマネージャを使用します。アテンションマネージャ自身はノティフィケーションマネージャを使用してユーザーの注意を換気したり、既存のアテンション項目について再通知をしたりします。
アテンションマネージャの使用が不適切な場合
アテンションマネージャは、効果的に注意喚起を行うことができるようにのみデザインされています。即時的な応答 ―― 例えば別のユーザーへの接続リクエストやビーム中の“put away”ダイアログなど ―― が要求される局面には適していません。また、アテンションマネージャはエラーメッセージの置き換えを意図したものでもありません。アプリケーションはこのようなケースについてはモーダルダイアログやその他の OS の機能を使用して処理しなければなりません。
アテンションマネージャは ToDo アプリケーションの置き換えを意図しているわけでもありませんし、普遍的な「受信ボックス」として機能するものでもありません。アプリケーションはアテンションマネージャによって表示される項目が単なるリマインダであり、それを削除することが項目自体を削除することにはならないということを明確に認識する必要があります。つまり、アラームに対して“OK”とすることは予定を削除することではありませんし、SMS のリマインダを消去することは SMS の受信ボックスから SMS メッセージを削除することにもなりません。
アテンションマネージャの操作
このセクションでは、ユーザーの視点から見たアテンションマネージャの操作について詳しく説明し、この章の残りの部分で使用する用語の紹介と、アテンションマネージャを使用したアプリケーションの開発で注意すべき処理上の詳細について指摘します。
アテンションを提示するための方法は、直接的か遠回しのいずれかになります。これらの違いは、アテンションを表示するまでの長さだけです。直接的な方法では、“目の前に”ダイアログをポップアップし、その他の視覚的・聴覚的な特殊効果を使用して重要なイベントをユーザーに提示します。会議のリマインダや重要な電子メールメッセージの受信であれば、このやり方でユーザーに割り込んでも正当といえるかもしれません。遠回しなアテンションでは、ダイアログのかわりにオンスクリーンの小さなアテンションインジケータを使用して、それほど重要でないイベントをユーザーの操作を妨げることなく通知します。様々な特殊効果を使用することはできますが、遠回しなアテンションでは通常使用しません。遠回しなイベントの例としては、近付いている誕生日や休日、あるいは SMS メッセージの受信に関する通知があります。
直接的なアテンション
アプリケーションが直接的にアテンションを行う場合、詳細ダイアログが表示されます。
図 10.1 詳細ダイアログ
アテンションマネージャはタイトルとボタンを描画します。それ以外の部分を描画するのはアプリケーションの役目です。ほとんどのアプリケーションは図 10.1 に示すように、テキストと適切なアイコンを描画します。
他のアプリケーションがアテンションを表示しようとしたり、最初のアプリケーションが別の通知をしようとした場合、最初のアテンションは消去されたり延期されたりせず、ウィンドウが一覧ダイアログに変更されてユーザーの注意を促す項目のリストが表示されます。
図 10.2 一覧ダイアログ
このダイアログでは、アテンションマネージャはタイトルとボタンを描画し、左端にチェックボックスのついた項目のリストを管理します。項目は発生した順に、新しいものが先頭にきます。各項目の一部を描画するのはアプリケーションの役目のため、何を表示するかについては多少の自由があります。アプリケーションにはリストの右側の領域にアイコンと標準フォントで2行のテキストを描画するスペースを与えられます。
詳細ダイアログでは、OK ボタンをタップすると項目を消去できます。一覧ダイアログでは、項目の左にあるチェックボックスをタップすることで項目を消去します。“Clear All”ボタンを使えば一覧の全ての項目を消去できます。項目の消去により、一覧から項目を消したり、詳細ダイアログを閉じることになりますが、アテンションマネージャから項目が消えても、項目自体はアプリケーションに残っていることに注意して下さい。
一覧ビューに独特なものとして、“Done”ボタンがあります。これは、単純に一覧ビューを閉じます。アテンションマネージャのリストやスヌーズタイマーに対しては何の変更も行ないません。
いずれのダイアログでも、“Snooze”ボタンをタップすることで一時的にアテンションマネージャのダイアログを消すことができます。アテンションインジケータは表示された状態のままになり、いつでもダイアログを再表示できます。5分間のインターバルが過ぎてもペンディング状態のアテンションが残っている場合、アテンションマネージャはダイアログを再表示します。このスヌーズによってアテンション項目が削除されることはありません。
“Snooze”タイマーは1つしかなく、スヌーズ操作はアテンションマネージャ全体に対して行なわれます。スヌーズ状態で新たなアテンション項目が追加される場合、これは奇妙な振舞いに見えるかもしれません。しかし、このような状況はレアケースです。
それぞれの項目に“移動する”には、一覧ダイアログではアイコンまたはテキストをタップし、詳細ダイアログでは“Go To”ボタンをタップします。この操作により一時的にアテンションマネージャは消去され、その項目の詳細を表示するために適切なアプリケーションが起動されます。SMS メッセージであれば、メッセージの中身を表示するダイアログを表示するか、メッセージが複数ある場合には未読の SMS メッセージのリストを表示することもあるでしょう。アラームであれば、Datebook の現在日付を表示し、該当する会議が画面上に収まるようにスクロールします。“Go To”に成功すれば、アテンション項目は一覧から削除されます。
アテンションマネージャが表示されている間は、ハードボタンもソフトウェアボタンも無効化されることに注意して下さい。これはハードボタンを押下することによってハンドヘルドの電源を入れた場合にアテンション項目を見逃すのを防ぐためです。
遠回しなアテンション
アプリケーションが遠回しにユーザーの注意を喚起する場合、ダイアログは表示されません。そのかわり、標準的なフォームタイトルオブジェクトを使用している全てのアプリケーションのタイトルバーに点滅するインジケータが表示されます。
図 10.3 アテンションインジケータ
リストに1つ以上の項目があり、その全てが一度以上表示されたことがある場合、リストが空になるまで“星の形”のインジケータが点滅を繰り返します。リストに未表示の項目が含まれている場合、アテンションマネージャは“爆発する星”のアニメーションを表示します。
このインジケータをタップすると、アテンションマネージャを( 1項目しかない場合でも )一覧ビューで開きます。インジケータの右側をタップするか、ペンディングのアテンションがない状態でインジケータのエリアをタップすれば、通常通りメニューバーを開くことができます。
アテンションインジケータは、標準的なフォームタイトルオブジェクトを使用するアプリケーションにおいてのみ機能します。以下のような状況ではインジケータは表示されません。
- アテンションマネージャのキューに項目がない場合
- 実行中のアプリケーションがカスタムタイトルを使用している場合
- 実行中のアプリケーションがタイトルエリアに描画をしている場合
- 表示中のフォームがダイアログスタイルのタイトルを使用している場合
- 事項中のアプリケーションのフォームタイトルバーがアテンションインジケータを表示するには狭過ぎる場合
特殊効果
新しいアテンション項目が追加されると、アテンションマネージャはいくつかの特殊効果の組み合わせを実行します。これにはサウンドの再生、LED の点滅、バイブレーションなどが含まれます。どのような効果が組み合わされるかはユーザー設定とアプリケーションによります。
アテンションマネージャは特殊効果を実行する前にダイアログをオープンしようとします。そのため、どのようなアテンションが通知されようとしているのかをただちに知ることができます。しかし、アテンションマネージャのダイアログをオープンできない場合もあります。このような場合、アテンションマネージャはできるだけ早く特殊効果を実行します。ハンドヘルドがどのようなイベントかを正確に表示できなくても、何かが起こっていることに気付くことができた方がユーザーにとって良いでしょう。
特殊効果 ―― アラームの再生音量、(もしあれば)LED を点滅させるかどうか、(装備されていれば)バイブレーションを行うかどうか ―― は、システム全体のユーザープリファレンスによって制御されます。アプリケーションはこれらのシステム全体の設定をポジティブにもネガティブにも上書きすることができます。例えば、ユーザーが LED に点滅してほしくない、あるいは絶対に点滅してほしくないと望んでいる場合でも、アプリケーションは常に LED を点滅させることができます。
再注意
Palm OS 3.5 以前の Datebook のアラームと同様に、アテンション項目を明示的に消去あるいはスヌーズしない限り、事前に定義されたインターバルで、その項目に指定された特殊効果を使って繰り返し“再注意”を行ないます。どれくらいの頻度でユーザーに提示を行うか、および何回表示したらアテンションマネージャがあきらめるかはアプリケーションが指定します。
複数の“再注意”を行うアテンション項目が競合する場合、アテンションマネージャは直近の直接的なアテンション項目の設定を使用し、それがない場合には直近の遠回しなアテンション項目の設定を使用します。それぞれの特殊効果は別々に処理されます。あるリマインダがサウンドありでバイブレーションなし、別のリマインダがバイブレーションありでサウンドなしの場合、組み合わせの結果として1つめのサウンドと2つめのバイブレーションが使用されます。
アテンションマネージャと既存アプリケーション
アテンションマネージャが既存のアプリケーションの挙動を上書きすることはありません。バージョン 3.5 以前の Palm OS 向けに書かれたアプリケーションがユーザーの注意を喚起するためにダイアログを表示しても、アテンションマネージャはそれに関与しません。アテンションマネージャの機能を利用し、Palm のユーザビリティにシームレスに統合するためには、アテンションマネージャを使用するようにアプリケーションを明確に記述しなければなりません。
既存のサードパーティ製アプリケーションには、アラームライクなモーダルダイアログを表示するものがあります。これらのダイアログは潜在的にアテンションマネージャの妨害をする可能性があります。しかし、アラームマネージャによる UI 起動コードの送信は、アテンションマネージャがクローズされるまで延期されます。これにより、アテンションマネージャが表示されている状態で既存アプリケーションがダイアログを表示することを防ぐことができます。その逆が発生して、既存アプリケーションがアラームのようなダイアログを表示している状態でアテンションマネージャがポップアップした場合、“Go To”だけが問題になります。サードパーティ製アプリケーションのダイアログには、“Go To”実行のために必要なイベントを消費してしまい、移動を妨げるものがあります。しかし、アテンション項目はアテンションマネージャのキューに留まるため、この問題は許容できます。サードパーティのダイアログが消去されれば、アテンションマネージャを再表示して“Go To”を実行することができます。
事実上、これはアラームマネージャを使用する既存アプリケーションのアラームダイアログよりも上にアテンションマネージャが常に表示されることを意味します。これにより、長期間使用していなかった場合でも、ほとんど常にアテンションマネージャのリストが表示されることになります。
ユーザーに対するアテンション
このセクションでは、アプリケーションがアテンションマネージャを介してどのようにユーザーへのアテンションをリクエストするかを説明します。
ユーザーに対するアテンションは、単純に適切なパラメータを指定して AttnGetAttention をコールし、アテンションマネージャからのいくつかのコールバックを処理するだけです。これらのコールバックにより、アプリケーションはアテンションマネージャのダイアログに何が表示され、どのようなサウンドを鳴らし、その他の特殊効果を使用するかを制御し、ユーザーが既存のアテンション項目に対してアクションを行なった時に必要な処理を行うことができます。
AttnGetAttention 関数のプロトタイプは以下のようになっています。
Err AttnGetAttention (UInt16 cardNo, LocalID dbID, UInt32 userData, AttnCallbackProc *callbackFnP, AttnLevelType level, AttnFlagsType flags, UInt16 nagRateInSeconds, UInt16 nagRepeatLimit)
ユーザーアテンションを要求しているアプリケーションを cardNo および dbID 引数で指定します。DmGetNextDatabaseByTypeCreator 関数を使用することでこれらの値を取得することができます。
userData は与えられたアテンションを同じアプリケーションによって作成された他のアテンションと区別するために使用されます。ほとんどのアプリケーションは、アテンションリクエストの元となるレコードのユニーク ID やその他のキーを渡します。この値はコールバック関数を介してアプリケーションのコードに渡されるもので、アプリケーションが必要とする数値、ポインタ、あるいはその他の 32 ビット値を指定できます。
callbackFnP 引数はアテンションマネージャがアプリケーションのサービスをリクエストするためにコールバック関数を呼び出すか、あるいは起動コードを送信するかを制御します。アプリケーションは通常このパラメータに NULL を指定し、それによって cardNo および dbID 引数で指定されたアプリケーションに起動コードが送信されるようになります。コールバック関数と起動コードに関する説明については“コールバックか起動コードか?”を参照して下さい。
level 引数には、アテンションが直接的か遠回しかによって kAttnLevelInsistent か kAttnLevelSubtle のいずれかを指定します。
アテンションの level とは関係なく、サウンドの再生、LED の点滅、その他の特殊効果など、実行させたい効果に対応する適切なビットを flags 引数に設定します。ここで指定した flags によって、その特殊効果が常に発生するかユーザーによって抑止されうるかが決まります。例えば、ユーザー設定を尊重しつつサウンドをトリガーするには、kAttnFlagsSoundBit だけを設定します。あるいは、ユーザーの設定に関わらず LED を点滅させてサウンドは抑止する場合、kAttnFlagsAlwaysLED | kattnFlagsNoSound を指定します。最後に、バイブレーションだけを指定する場合は以下のようになります。
flags = kAttnFlagsNothing ^ kAttnFlagsNoVibrate | kAttnFlagsAlwaysVibrate;
上記の例はいくらか複雑ですが、バイブレーション以外の全てのデフォルトをネガティブに上書きし、バイブレーションだけをポジティブに上書きしています。flags 引数に組み合わせて適用できる定数の完全なセットについては、Palm OS Programmer's API Reference の AttnFlagsType の定義を参照して下さい。
- NOTE
- アプリケーションとしては、ハンドヘルドが希望の特殊効果を備えているかを確認したい場合があるかもしれません。その方法については、“デバイス機能の検出”を参照して下さい。ハンドヘルドが指定された特殊効果を装備していない場合、その特殊効果は実行されません。例えば、kAttnFlagsLEDBit フラグをセットしても、Palm ハンドヘルドに LED が装備されていなければ、そのアテンションは kAttnFlagsLEDBit が設定されていない場合と同様に処理されます。
ハンドヘルドが要求された特殊効果でアテンションを表示することができたとすると、引数 nagRateInSeconds と nagRepeatLimit によってアテンションによる特殊効果が実行される回数と間隔を指定することができます。名前からわかる通り、時間を秒単位で指定することで、アテンションマネージャは nagRateInSeconds 秒だけ特殊効果の実行に間隔をおきます。特殊効果をトリガーしたい希望の回数は nagRepeatLimit で指定します。アプリケーションは通常 nagRateInSeconds に 300 を、nagRepeatLimit に 3 を指定します。これにより、最初のアテンションから3回、5分おきに特殊効果が実行されます。
以下のコードは、SMS アプリケーションが新しい SMS メッセージを受信したときにアテンションマネージャをどのようにコールしているかを示しています。SMS メッセージを受信するたびにユーザーが割り込みを受けることにならないよう、遠回しなアテンションにしていることに注意して下さい。また、アプリケーションがアテンションに関するユーザー設定を上書きしていないことにも注意して下さい。最後に、ユーザーが最初のアテンション表示に応答しなかった場合、特殊効果は追加で3回、5分おきに繰り返されます。
err = AttnGetAttention(cardNo, dbID, NULL, NULL, kAttnLevelSubtle, kAttnFlagsUseUserSettings, 300, 3);
コールバックか起動コードか?
与えられたアテンション項目に対して、アテンションダイアログの内容を描画する必要がある場合やその項目に関連するアクティビティを通知する必要がある場合、アテンションマネージャはその項目を作成したコードリソースをコールバックします。アテンションマネージャはこのコールバックを2通りの方法で行ないます。
- アテンション項目にコールバック関数が指定されている場合、アテンションマネージャはそれをコールします。このコールバックルーチンは大域を利用できません。そのため、描画に必要なものは commandArgsP を通して利用することになります。コールバックルーチンは通常ライブラリやシステム拡張で使用されます。コールバックルーチンの指定については、Palm OS Programmer's API Reference の AttnCallbackProc の説明を参照して下さい。
- アテンション項目にコールバックルーチンが指定されていない場合、アテンションマネージャはかわりに sysAppLaunchCmdAttention 起動コードをそのアテンションを登録したアプリケーションに送信します。この起動コードに伴って、前述の3つのパラメータを含む AttnLaunchCodeArgsType 構造体が渡されます。アプリケーションは通常、コールバックルーチンによる制約のために起動コードによる仕組みを使用します。
- IMPORTANT
- コールバック関数がコールされたときに、それがまだ同じ場所にあることを保証するのはアプリケーションの責任です。コードリソースがアンロックされてメモリ内の別の場所に移動する可能性や、そのコードリソースを含むデータベースが削除される可能性を考慮しなければなりません。ほとんどの場合、起動コードを使用すればこれらの問題は発生しません。
アテンションマネージャのコマンド
AttnGetAttention の呼び出しに加えて、アプリケーションはアテンションマネージャからのコマンドに応答しなければなりません。アテンションマネージャはコールバック関数呼び出しか起動コード送信のいずれかを使ってコマンドを発行します。どちらが使用されるかは、AttnGetAttention 呼び出しの際に callbackFnP 引数に何を指定したかによります。コマンドの内容は、アプリケーションに対する詳細ダイアログや一覧ダイアログの内容描画や、アプリケーション指定のサウンド再生やその他の特殊効果の実行、およびポストされたアテンション項目に対応するレコードへのアプリケーション内での移動などです。
詳細および一覧ダイアログの描画
アテンションマネージャの詳細および一覧ダイアログは、アテンションマネージャとアテンションをリクエストしたアプリケーションが共同で描画します。ダイアログの外枠やタイトル、およびボタンとチェックボックスはアテンションマネージャが描画しますが、残りの部分 ―― 各アテンション固有のテキストと付随するアイコン ―― はアプリケーション自身が描画します。これにより、どのような情報が表示されるかをアプリケーションが完全に制御することができます。
図 10.4 アテンションマネージャのダイアログ
アプリケーションはアテンション項目をどのように表示するかを完全に制御できますが、それは指定された領域の描画に限られます。スクロールバーやカスタムボタン、その他のウィジェットを含めることはできません。ユーザーには、“Go To”ボタンを使用してアプリケーションを起動し、アプリケーション側でリッチな UI を利用するように誘導すべきです。アプリケーションがうっかり指定領域の外側に描画を行なわないように、クリッピング領域が適切に設定されます。
kAttnCommandDrawDetail コマンドはアプリケーションが詳細ダイアログの内容を描画するように指示します。このコマンドでは、アテンションマネージャは drawDetail 型の構造体を渡してきます。この構造体にはアプリケーションが描画を行なうべきスクリーン矩形のウィンドウ相対の領域と、ユーザーがこのアテンションを目にするのが初めてかどうかを示すフラグ、およびどの特殊効果を実行すべきかを示すフラグのセットが含まれます。
- NOTE
- firstTime ビットが設定されていない限り、詳細ダイアログのアプリケーション描画領域が空であることは保証されません。firstTime がセットされていなければ、詳細ダイアログの内容を描画する前に bounds 矩形が示す領域をクリアして下さい。
以下のコード断片は、シンプルなアプリケーションが sysAppLaunchCmdAttention 起動コードによる kAttnCommandDrawDetail コマンドに応答して詳細ダイアログの中身をどのように描画するかを示しています。
リスト 10.1 詳細ダイアログの内部の描画
// Draw the icon resH = DmGetResource(bitmapRsc, MyIconBitmap); WinDrawBitmap(MemHandleLock(resH), paramsPtr->drawDetail.bounds.topLeft.x, paramsPtr->drawDetail.bounds.topLeft.y + 4); MemHandleUnlock(resH); DmReleaseResource(resH); // Draw the text. The content of the string depends on the // uniqueID that accompanies the kAttnCommandDrawDetail // command curFont = FntSetFont (largeBoldFont); x = paramsPtr->drawDetail.bounds.topLeft.x + 37; y = paramsPtr->drawDetail.bounds.topLeft.y + 4; WinDrawChars(alertString, StrLen(alertString), x, y); FntSetFont(curFont);
もっと複雑な、実世界の例は、Datebook アプリケーションの DrawDetailAlarm 関数を参照して下さい。特に、アプリケーションがどのようにして与えられたスペース内に表示テキストを収めるかに注意して下さい。
遠回しなアテンション項目は一覧ビューでしか表示されないため、アプリケーションが直接的なアテンションを行なわないのであれば kAttnCommandDrawDetail に応答する必要はありません。
kAttnCommandDrawList コマンドも同様です。このコマンドはアプリケーションが一覧ダイアログの内容を描画するように指示します。このコマンドとともに、アテンションマネージャは drawList 構造体を渡してきます。この構造体には前述の bounds、firstTime、および flags フィールドに加え、selected フラグが含まれています。selected フラグはその項目が選択されているかどうかを示しています。アプリケーションに kAttnCommandDrawList コマンドを送信する前に、その項目が選択されているかどうかによって背景色、前景色、および文字色を以下に示すように設定します。
設定対象 | 未選択状態 | 選択状態 |
---|---|---|
背景色 | UIFieldBackground | UIObjectSelectedFill |
前景色 | UIObjectForeground | UIObjectSelectedForeground |
文字色 | UIObjectForeground | UIObjectSelectedForeground |
特にアテンション項目のアイコンがカラーの場合、アテンション項目が選択されている場合は異なる描画をする必要があります。selected フラグはそれを可能にするためにあります。
一覧ダイアログにアテンション項目を描画するコードは、詳細ダイアログに項目を描画するのに使用したコードとほとんど同じです。以下にコード例を示します。
リスト 10.2 一覧ダイアログへの描画
// Draw the icon. Ignore the ‘selected’ flag for this example resH = DmGetResource(bitmapRsc, MySmallIconBitmap); iconP = (BitmapPtr)(MemHandleLock(resH)); // center it in the space allotted iconOffset = (kAttnListMaxIconWidth - iconP->width)/2; x = paramsPtr->drawList.bounds.topLeft.x; y = paramsPtr->drawList.bounds.topLeft.y; WinDrawBitmap(iconP, x + iconOffset, y); MemHandleUnlock(resH); DmReleaseResource(resH); // Draw the text curFont = FntSetFont(stdFont); WinDrawChars(alertString, StrLen(alertString), x + kAttnListTextOffset, y); FntSetFont(curFont);
もっとも大きな違いは、一覧ダイアログではより小さな領域に描画するということです。また、描画領域は常に消去されます。そのため、描画する前に消去する必要はありません。
アイコンは kAttnListMaxIconWidth ピクセルよりも幅があってはいけません。また、kAttnListMaxIconWidth よりも狭い場合はこの幅の中央に描画する必要があります。テキストは kAttnListTextOffset ピクセル分の左余白を保つようにします。上記の例では、テキストは利用可能なスペースに収まるものと仮定しています。利用可能なスペースに収まりきらないようなイベントのテキストをアプリケーションがどのように調整するかについては、Datebook アプリケーションの DrawListAlarm 関数を参照して下さい。
- NOTE
- 特殊な状況においては、アプリケーションは kAttnCommandDrawDetail あるいは kAttnCommandDrawList コマンドを無効な項目に対して受信する場合があります。そのような場合は AttnForgetIt をコールするか、何も描画しないか、あるいはエラーメッセージを描画します。
サウンドの再生あるいはカスタム効果の実行
多くのアプリケーションは、アテンション表示の際サウンドの再生を行ないます。アプリケーションが AttnGetAttention をコールした時に kAttnFlagsAlwaysSound をセットしていれば、アテンションマネージャはアテンション表示の際に kAttnCommandPlaySound コマンドをアプリケーションに送信してきます。アプリケーションはこのコマンドに応答して適切なサウンドを再生しなければなりません。Datebook や SMS アプリケーションは両方ともアテンション表示時にユーザー設定に従ってサウンドを再生します。kAttnCommandPlaySound コマンドにどのように応答するかについては、Datebook アプリケーションのソースコードを参照して下さい。
アテンションマネージャはダイアログの表示やアテンションインジケータの点滅に加え、サウンドの再生、LED の点滅、バイブレーションなどを行なうことができるため、ほとんどのアプリケーションは別のアプリケーション特有の特殊効果の実行をリクエストしません。アプリケーションが何か別のものを必要とする場合、AttnGetAttention をコールする時に kAttnFlagsAlwaysCustomEffect を指定することができます。これにより、希望の特殊効果を実行すべき時に kAttnCommandCustomEffect コマンドが送られてきます。通常のアプリケーションであれば kAttnCommandCustomEffect コマンドを受信することはないため、このコマンドにどのように応答すべきかを心配する必要はありません。
kAttnCommandPlaySound も kAttnCommandCustomEffect も、再生すべきサウンドや実行すべき効果を指示するデータ構造体のようなものは付随してきません。これらの情報をハードコーディングしない限り、アプリケーションのプリファレンスデータベースに保存しておいた方が良いでしょう。
移動
詳細ダイアログで“Go To”ボタンをタップしたり、一覧ビューで(チェックボックスではなく)テキストやアイコンをタップすると、アプリケーションは kAttnCommandGoThere コマンドを受信します。アプリケーションはこれに対してアプリケーションの切り替えを行ない、選択されたアテンション項目に関連した情報を表示しなければなりません。kAttnCommandGoThere コマンドは起動コード sysAppLaunchCmdGoTo に似ていますが、アプリケーションが kAttnCommandGoThere コマンド受信した時点ではグローバル領域を持たず、アプリケーションは SysUIAppSwitch でなく SysAppLaunch で起動されます。このため、多くのアプリケーションは kAttnCommandGoThere 受信時に SysUIAppSwitch を実行します。
アプリケーションはアテンションの元となるデータがまだ有効かどうかを検証すべきであることに注意して下さい。例えば Datebook ではユーザーは以下のような操作をできます。
- アテンションマネージャからの予定の通知を受ける
- “Snooze”をタップする
- Datebook を起動してアテンションの元となった予定を削除する
- 点滅しているアテンションインジケータをタップする
- 削除した予定に対応するアテンション項目をタップする
このシナリオでは、Datebook アプリケーションは削除されたレコードを参照するユニーク ID とともに kAttnCommandGoThere コマンドを受信することになります。Datebook アプリケーションが kAttnCommandGoThere を削除されたデータベースレコードのユニーク ID とともに受け取った場合、Datebook は既に無効となったアテンション項目に対して AttnForgetIt をコールして復帰します。
実際には、Datebook はユーザーがアラームを削除した場合やアラームが無効にされた場合にはいつでも AttnForgetIt をコールします。これは、そのアラームがアテンションマネージャが現在管理しているものの中に含まれているかどうかをチェックすることなく行なうことができます。AttnForgetIt に渡したカード番号、データベース ID 、およびユニーク ID の組み合わせがアテンションマネージャのキューにない場合、AttnForgetIt はなにもせずに false を返します。
ほとんどのアプリケーションは、アテンション項目に対応するデータをユーザーが見た時点で AttnForgetIt をコールしようとするでしょう。これは SMS アプリケーションのやり方です。受信メッセージはアテンションマネージャを介してユーザーの注意を喚起し、ユーザーが1度でもメッセージを読むとアテンションマネージャから削除されます。
Got It
ユーザーが特定のアテンション項目を削除すると、kAttnCommandGotIt コマンドがアプリケーションに送信されます。kAttnCommandGotIt は AttnForgetIt コールの成功によっても送信されるため、このコマンドにはユーザーによって明示的に削除されたかどうかを示す真偽値が付随します。このコマンドを受信したら、メモリの開放やアラームの削除、あるいはその他のアプリケーション固有の処理をすることになるでしょう。
反復
アプリケーションのアテンション項目が無効になりうるような事態が発生した場合、アプリケーションは AttnIterate をコールすべきです。AttnIterate はアプリケーションのペンディング状態のアテンション項目それぞれに対する一連の kAttnCommandIterate コマンドを発行します。そのため、kAttnCommandIterate コマンドを受け取ったアプリケーションは、指定されたアテンション項目の有効性を検証し、無効であれば ―― その項目を指定して AttnForgetIt をコールすることを含めた ―― 適切なアクションをとる必要があります。
SMS アプリケーションは kAttnCommandIterate に応答しませんが、Datebook アプリケーションは応答します。このコマンドはユーザーがプリファレンスを更新すると常に発行されます。多くのアプリケーションでは、起動コード sysAppLaunchCmdSyncNotify を受信した後、HotSync 操作によって影響を受けたアテンション項目を(AttnUpdateで)更新または(AttnForgetItで)削除するために AttnIterate をコールします。
AttnForgetIt はレコードに削除マークをつけるだけなので、反復を混乱させることはありません。そのため、反復の最中にも AttnForgetIt を安全にコールすることができます。
スヌーズ
ほとんどの ―― Datebook や SMS を含む ―― アプリケーションは、kAttnCommandSnooze コマンドを無視します。これは、ユーザーが Snooze ボタンをタップしたことを示すものです。アテンション項目を識別するユニーク ID 以外には、Snooze コマンドにはなにも付随しません。kAttnCommandSnooze はその時点でペンディングになっている、直接的なアテンションと遠回しなアテンション全てについて個別に発行されます。つまり、複数のペンディング状態のアテンション項目があるアプリケーションは、その個数分だけこのコマンドを受信することになります。
特殊効果の実行
アテンションマネージャは各アテンション項目について要求された特殊効果を実行しますが、アプリケーションがアテンション項目をキューにポストすることなくこれらの特殊効果を実行したい場合もあります。これは、AttnDoSpecialEffects をコールすることで実現できます。希望する特殊効果のフラグを組み合わせて指定します。フラグの完全な一覧については、AttnFlagsType を参照して下さい。
アテンションとアラーム
アテンションマネージャは、特定日時にユーザーの注意を喚起するために、アラームマネージャと共同で頻繁に利用されます。アラームマネージャの基本的な使い方は“アラーム”で説明されていますが、UI の制御はアテンションマネージャが行ないます。アラームマネージャをアテンションマネージャとともに使用する場合、以下の要領で行なって下さい。
- アプリケーションが起動コード sysAppLaunchCmdAlarmTriggered を受信したら、AttnGetAttention をコールします。
- sysAppLaunchCmdAlarmTriggered を処理するコードの中で、復帰する前に起動コードのパラメータブロック内の purgeAlarm フィールドに true を設定します。これによりキューからアラームが削除され、アプリケーションが sysAppLaunchCmdDisplayAlarm 起動コードを受信することはなくなります。
AttnGetAttention をコールするにあたって sysAppLaunchCmdDisplayAlarm 起動コードの受信を持たないで下さい。別のアラームマネージャダイアログが表示されている間は sysAppLaunchCmdDisplayAlarm は発行されないため、“レガシー”なアプリケーションがアラームマネージャのダイアログを表示しているとアテンションマネージャの動作を妨害することになります。
- NOTE
- アラームマネージャをアプリケーションのアテンション項目の定期的な更新に使用したい場合、アラームマネージャの起動コードの受信後に AttnUpdate をコールしないで下さい。なぜなら、これはハンドヘルドがスリープ状態のままでも行なわれるからです。かわりに、“プロシージャアラームの設定”で説明しているプロシージャアラームを使用し、プロシージャアラームのコールバック関数の中から AttnUpdate をコールして下さい。
保留アテンションの検出と更新
アプリケーションがアテンションマネージャに対してアテンション表示をリクエストすると、そのアテンションリクエストを更新する必要が生じます。例えば、アプリケーションが単一のアテンション項目を使って未読の受信メッセージ数を提示する場合、その後の受信やメッセージを読むことによってアテンション項目を更新する必要があります。アテンションマネージャは、アプリケーションがアテンションマネージャのキューを調べてその中のアテンション項目を更新するためのいくつかの関数を提供しています。
AttnGetCounts 関数を使うことで、その時点でどれだけのユーザーアテンションが存在しているを取得することができます。この関数は常に項目の総数を返しますが、遠回しな、あるいは直接的なアテンション項目だけを返すこともできます。また、全てのアプリケーションの項目数を返すこともできます。例えば、以下のコードでは保留状態の全てのアテンション項目の総数を numItems に設定しています。
numItems = AttnGetCounts(0, 0, NULL, NULL);
単一のアプリケーションのリクエスト総数に加えて、遠回しなアテンションと直接的なアテンションの数を取得するには、以下のようにします。
numItems = AttnGetCounts(cardNo, dbID, &insistentItems, &subtleItems);
あるアプリケーションの保留アテンション項目のそれぞれを検証するには、アテンションマネージャの関数である AttnIterate を使用します。このセクションの“反復”を参照して下さい。
HotSync の直後は AttnIterate を呼び出すべきタイミングの良い例です。HotSync 操作はアプリケーションに属するデータを変更してアテンション項目を無効あるいは不正にする場合があるためです。
保留アテンション項目の削除
多くの場合、アテンション項目を削除する必要が発生します。例えば、HotSync がアテンションを無効にするような変更をアプリケーションデータに加えるかもしれません。あるいは、ユーザーがデータに対して手作業で同じような変更をするかもしれません。例えばアラームが保留になっている予定を削除するなどです。AttnForgetIt はこのような状況に対処するために存在します。単純にこの関数を呼び出し、カード番号、データベース ID、アテンションを識別するユーザーデータを渡すだけです。アテンションがアテンションマネージャのキューに存在するかどうかを検証する必要もありません。AttnForgetIt はアテンションが存在しなくても文句を言わず、faise を返却してこの状況を示します。
保留アテンション項目の更新
既存のアテンション項目を更新するには AttnUpdate 関数を使用します。この関数は AttnGetAttention と非常に似通っていますが、実際の値のかわりに更新したいデータのポインタを渡します。flagsP, nagRateInSecondsP, nagRepeatLimitP をそのままにしておきたい場合には NULL を渡します。例えば、アテンション表示において使用する特殊効果を制御するフラグを変更するには、以下のようにします。
リスト 10.3 既存アテンション項目の更新
// This assumes that cardNo, dbID, and myUserData are // declared and set elsewhere to values that identify the // attention item we're trying to update Boolean updated; AttnFlagsType newFlags; // set newFlags appropriately updated = AttnUpdate(cardNo, dbID, myUserData, NULL, &newFlags, NULL, NULL); if (updated){ // update succeeded } else { // update failed - attention item may no longer exist }
- NOTE
- AttnUpdate は指定されたアテンション項目を再描画しますが、アテンション項目が追加された時に使用した特殊効果は(あったとしても)再実行しません。特定の項目についてアテンションマネージャに特殊効果を実行させたい場合は、AttnForgetIt をコールしてから AttnGetAttention をコールして下さい。
AttnUpdate をコールする場合、カード番号だけでなくデータベース ID やアテンションを一意に識別するユーザーデータも指定しなければならないことに注意して下さい。コールバック関数を使用する場合は、そのポインタも指定する必要があります。
アテンション項目をアップデートする際にハンドヘルドの電源が入っていてアテンションマネージャのダイアログが表示されている場合、AttnUpdate はアテンション項目を再描画します。この際、AttnUpdate はダイアログの一部を更新できるようにクライアントアプリケーションをコールバックします。AttnUpdate はその項目が可視状態であれば、flags、nagRateInSeconds、および nagRepeatLimit とは無関係にその項目を再描画します。つまり、AttnUpdate はアテンション項目のどの部分が更新されたかの制限を受けません。そのため、アプリケーションはアテンションマネージャのダイアログを破棄して再構築することなくアテンションのテキストを更新することができます。
ハンドヘルドの電源がオフの場合、更新は次にハンドヘルドの電源が入る時まで遅延します。AttnUpdate 自身がスクリーンをオンにすることはありません。
デバイス機能の検出
そのハンドヘルドでどの特殊効果がサポートされているかをチェックせずに、バイブレーションのような特定の特殊効果をアテンション表示に使用するようリクエストすることもできますが、特定のデバイス機能がない場合には別の方法を使用するようにした方が良いでしょう。アテンションマネージャは FtrGet 関数を使用してデバイスの物理的な機能を調べることができるようなフィーチャを定義しています。このフィーチャを使用することで、アテンション表示に関するプリファレンスを取得することもできます。以下に例を示します。
リスト 10.4 バイブレーション機能のチェック
// See if the device supports vibration FtrGet(kAttnFtrCreator, kAttnFtrCapabilities, &capabilities); if (capabilities & kAttnFlagsHasVibrate){ // Vibrate-specific processing goes here ... }
関連する全てのフラグの説明については、Palm OS Programmer's API Reference の“アテンションマネージャのフィーチャ定数”を参照して下さい。
アテンションインジケータの制御
ほとんどの場合、アプリケーションはタイトルバーの一部を使うアテンションインジケータを無視できます。表示されているフォームにタイトルバーがない場合やモーダルフォームの場合、アテンションインジケータは描画されません。しかし、アプリケーションがスクリーン全体を使用したりタイトルバーを使って何かをする場合、そのフォームが表示されている間アテンションインジケータを明示的に無効にするべきです。
例えば、Datebook アプリケーションは以下の状況ではアテンションインジケータを無効にします。
- Datebook エントリに関連付けられたノートが表示されている場合
- 週表示でエントリの説明が表示されている場合
- タイトルバーの日付部分に時刻が表示されている場合
アテンションインジケータを無効にするには、単純に AttnIndicatorEnable をコールして enableIt 引数に false を指定します。再度有効にする場合は、もう一度 AttnIndicatorEnable をコールして今度は引数に true を渡します。
アプリケーションでアテンションインジケータを無効にする場合、アテンションマネージャの一覧ダイアログを表示させる方法をユーザーに提供したい場合もあるかもしれません。AttnListOpen 関数を使用すればこれを行なうことができます。