★はじめに★
第6話 Phase2.5の新機能を使ったEZアプリを作る
[JAVA PRESS Vol.33]

ゲーム:待ち受けアプリ
対応端末:A5301T・A5302CA・A5303H・A5303HU・A5305K・A5401CA・A5402S


 テキスト 布留川 英一 (ん・ぱか工房)
 イラスト つきみの せひら (せひらねっと)



ねぇ、へにへに〜。今後発売されるau端末のアプリ実行環境は「BREW」がメインになって、Java対応端末は少なくなっちゃうって聞いたんだけど、BREWってJavaよりもスゴイの?
BREWではC言語を使ってJavaより高速なネイティブアプリが作れるんだけど…、その分セキュリティ関連もオープンになってるから、一般ユーザーがBREWのアプリを作れる可能性は低そうだね。
Javaはアプリから操作できる機能をわざと制限することで、セキュリティを高くして一般ユーザーでも自由にアプリを作れるようにしてるんだもんねー。
BREWの上でJava実行環境を作るって話もあるけど、現状だと処理能力もゼビウスくらいで精一杯みたいだし、実現するのはいったいいつになることやら…。
うぅ〜ん、自分でアプリ作れなくちゃ面白くないけど、auはJavaも貧弱すぎて実用に耐えないしなぁ…。
いやいや、そらみちゃん。auのJavaが貧弱なのは昔の話で、最近では実行環境も少しずつ進化してるんだよ。…ドコモやボーダフォンの進化に比べると地味ではあるけどね。
えっ、そうなんだ?…auの端末って最近あまり触ってなかったから知らなかったよ(汗)
高性能CPU「SH-Mobile」の採用で処理速度も格段に速くなったし、APIの拡張で「音の同時再生」や「待ち受けアプリの作成」だってできるようになったんだ。
そうだったんだ…。それじゃあ今回は、auのJavaの新機能を使って、待ち受けアプリを作ってみよう!


★EZアプリ★


EZアプリ
NTTドコモの携帯電話のWeb閲覧サービスを「iモード」、アプリのダウンロードサービスを「iアプリ」と呼ぶのに対し、auの携帯電話のWeb閲覧サービスを「EZWeb」、アプリのダウンロードサービスを「EZアプリ」と呼びます。「EZアプリ」は以前「ezplus」と呼ばれていましたが、わかり難いということで名称が変更されました。
Web閲覧サービスとアプリのダウンロードサービスの名称
WEB閲覧サービス アプリのダウンロードサービス
NTTドコモ iモード iアプリ
au EZWeb EZアプリ
ボーダフォン ボーダフォンライブ! Vアプリ

また、auのJavaアプリの実行環境は、ドコモやボーダフォンに比べて処理能力が悪かったため、それを解決するために「BREW」というC言語によるネイティブアプリの実行環境も用意されました。

Javaはアプリから操作できる機能をわざと制限することによって、その外部へ悪影響が及ぶのを防いでいますが(サンドボックスモデルと呼びます)、BREWにはそれがなく、プログラミング言語の違いからiアプリやVアプリからの移植も困難になるため、BREW一本に絞りきれないでいます。

2003年10月現在、BREWを採用することでアプリを高速化する端末と、高性能CPU「SH-Mobile」の搭載などによりJavaを高速化する端末に2分し、同じキャリアでありながら同じアプリを実行できない状況に陥っています。auのJavaアプリのことを「EZアプリ(JavaTM)」、auのBREWアプリのことを「EZアプリ(BREW)」と呼んで区別します。

EZアプリ(Java)のダウンロードサイトとしては,老舗である「EZLIB」の他に,10月にオープンした「アプリ★ゲットEZ」があり、一般ユーザーが作ったアプリがたくさん登録されています。


MIDPとKDDIプロファイル
「MIDP(Mobile Information Device Profile)1.0」は、auやボーダフォンの携帯電話をはじめとする多くの携帯端末で採用されているJavaのAPI仕様です。

しかし、携帯端末の進化ははやく、MIDP1.0の仕様だけではアプリ作成には不十分なため、EZアプリ(JavaTM)には「KDDIプロファイル」と呼ぶ拡張APIが用意されており、「Phase1」、「Phase2」、「Phase2.5」の3つのバージョンがあります。主な拡張機能は次の通りです。
対応機種 前Phaseからの拡張点
Phase1 C451H/C452CA -
Phase2 C3001H/C3002K/C3003P
C5001T
A3011SA/A3012CA/A3013T/
A3014S/A3015SA
バックライト制御
ブラウザやメーラーとの連携
音声通話連携
自動起動
Phase2.5 A5301T/A5302CA/A5303H/
A5303H U/A5305K/A5401CA/
A5402S
複数の音の同時再生
待ち受けアプリ
ブラウザからのアプリ起動時のパラメータ引渡し

今回は、Phase2.5からの新機能である、「複数の音の同時再生」と「待ち受けアプリの作成」について説明します。


★開発環境を整える★


今回のアプリを作るのに必要な開発ツールは次の4つです。全て無償で入手できます。


Java 2 SDK, Standard Edition Version(JDK1.3)
パソコン上で動くJavaアプリを作るための開発キットです。サン・マイクロシステムズのサイトで入手できます。次に説明する「J2ME Wireless Toolkit」を実行するのに必要なので、それより先にインストールします。インストーラの指示に従ってインストールしてください。JDK1.4でない点に注意してください。

J2ME Wireless Toolkit 1.0.3(日本語版)
MIDP1.0仕様のJavaアプリを作るための開発キットです。サン・マイクロシステムズのサイトで入手できます。インストーラの指示に従ってインストールします。J2ME Wireless Toolkit 2.0でない点に注意してください。MIDPのAPIリファレンスはdocsディレクトリの中(C:\J2mewtk\docs\api)にあります。

EZアプリ(Java)開発キット
EZアプリ(Java)を作るための開発キットです。KDDIのサイトで入手できます。インストーラの指示に従ってインストールしてください。同サイトには、 などの開発に役立つドキュメントもあるので、いっしょに入手してください。

EZアプリ(Java) Phase2.5対応 Stab File
EZアプリ(Java)開発キットをPhase2.5に対応させるための差分ファイルです。KDDIのサイトで入手できます。ダウンロードと解凍を行うと「kddip.jar」が出現します。それをEZアプリ(JavaTM)開発キットに含まれている同名ファイル「C:\ezplusTools\Tools\KDDI-P\kddip.jar(*1)」に上書きすればインストール完了です。
(*1)パスはEZアプリ(JavaTM)開発キットのインストール先によって変わります。


★EZアプリ(Java)開発の基礎★


まずはじめに、「Hello World!」という文字列を表示するプログラムを作りながら、EZアプリ(JavaTM)開発の基礎について説明します。今回のプログラムは、次の2つのクラスで構成されています。

Micro JBlend cmdtoolの設定
まずはじめに、「EZアプリ(JavaTM)開発キット」の核となるツール「Micro JBlend cmdtool」を起動します。コマンドプロンプトで「C:\ezplusTools\Tools\CmdTool」ディレクトリに移動し、次のコマンドを入力してください。
java -jar CmdTool.jar



コマンドプロンプトを毎回開くのが面倒な人は、ショートカットを作っておくと良いでしょう。


リンク先:C:\jdk1.3.1_04\bin\java.exe -jar CmdTool.jar
作業フォルダ:C:\ezplusTools\Tools\CmdTool

メニューの「tool」→「default env...」を選択すると、各種環境設定を行う「EnvironmentEditDialog」ダイアログが開きます。ここで各種パスを設定してください。




次に「EnvironmentEditDialog」の「MIDlet」ボタンで、MIDletの設定画面に切り替えます。ここでは、プロジェクトを生成した時の初期状態を設定します。今回は「MIDlet-Jar-Vendor」を指定してください。


プロジェクトの生成
メニューの「file」→「new projects」を選択すると、「NewProjectDialog」が開くので、「Project Name」に"HelloWorld"と入力してください。


「Project Name」は「プロジェクト」、「実行ファイル」、「一番はじめに実行されるクラス」の名前として使います。「Project Detail」は空のままでOKです。「OK」ボタンを押すと、「C:\ezplusTools\Tools\CmdTool\project」ディレクトリの下に「Project Name」と同じ名前のディレクトリ(今回は"HelloWorld")が生成されます。さらにその下に次の5つのディレクトリが生成されています。 アプリの属性を設定するダイアログも開きますが、今回は先ほど指定した設定のまま(MIDlet-Jar-VendorにNPAKA)で良いので、そのまま「OK」ボタンを押して閉じてください。


HelloWorldクラス
HelloWorldクラスは、プログラムの本体となるクラスです。プログラムファイルは前回(JAVA PRESS Vol.32)と同じものなので説明は省略します。
HelloWorld.java
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

//HelloWorld(本体)
public class HelloWorld extends MIDlet {

    //コンストラクタ
    public HelloWorld() {
        Display.getDisplay(this).setCurrent(new HelloCanvas());
    }

    //アプリの開始
    public void startApp() {
    }

    //アプリの一時停止
    public void pauseApp() {
    }

    //アプリの終了
    public void destroyApp(boolean unconditional) {
    }
}      


HelloCanvasクラス
HelloCanvasクラスは、キャンバスとなるクラスです。こちらの説明も省略します。
HelloCanvas.java
import javax.microedition.lcdui.*;

//HelloWorld(キャンバス)
public class HelloCanvas extends Canvas {

    //描画
    public void paint(Graphics g) {
        g.setColor(255,255,255);
        g.fillRect(0,0,getWidth(),getHeight());
        g.setColor(0,0,0);
        g.drawString("Hello World!",0,0,g.LEFT|g.TOP);
    }
}


ビルド
プログラムファイルをsrcディレクトリ(C:\ezplusTools\Tools\CmdTool\project\HelloWorld\src)に置いて、「build」ボタンを押してください。メッセージボックスに"build finished"と表示されたらビルド成功です。binディレクトリ(C:\ezplusTools\Tools\CmdTool\project\HelloWorld\bin)に"HelloWorld.kjx"が生成されています。「KJXファイル(*.KJX)」ルはJADファイルとJARファイルを繋げたau独自のファイル形式で、これがau端末での実行ファイルとなります。EZアプリ(Java)の実行ファイルサイズは最大50Kバイト、ハイスコア等を保存できるデータ保存領域は最大10Kバイトです。

エミュレータでの実行
次にEZアプリ(Java)のエミュレータで実行します。エミュレータを操作するための「ezplus Emulator Control Panel」を起動してください。コマンドプロンプトで「C:\ezplusTools\Tools\Emulator」ディレクトリに移動し、次のコマンドを入力します。
java -jar jbmidp.jar

コマンドプロンプトを毎回開くのが面倒な人は、ショートカットを作っておくと良いでしょう。
リンク先:C:\jdk1.3.1_04\bin\java -jar jbmidp.jar
作業フォルダ:C:\ezplusTools\Tools\Emulator

「...」ボタンを押すとファイルダイアログが開くので、先ほど生成した"Hello.kjx"を選択し、「Run」ボタンを押してください。
   


XHTMLによるダウンロード
Phase2.5以前のau端末にEZアプリをダウンロードするには、「HDML」という一世代前のコンテンツ記述言語でダウンロードサイトを作成し、KJXファイルにチェックバリュー(受信データの正当性をチェックするための情報)の付加と、ダウンロードCGIの準備が必須なため、かなり手間のかかる作業でした。

Phase2.5からは「XHTML」と呼ぶ「HTML」に似たコンテンツ記述言語で、直接KJXファイルをダウンロードできるようになりました。


MIMEタイプ
XHTMLによるダウンロードを行うには、サーバに次の「MIMEタイプ」を指定する必要があります。
拡張子 MIMEタイプ
.kjx application/x-kjx

.htaccessの使用が許されているサーバでは、.htaccessとうい名前のファイルをKJXファイルを置くディレクトリに作り、次の命令を記述してください。
.htaccess
AddType application/x-kjx .kjx

詳しくは、サーバ管理者の人に聞いてください。


ダウンロード用XHTML
XHTMLを使ってKJXファイルをダウンロードする時は「objectタグ」を使います。書式は次の通りです。
HelloWorld.html
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
"http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>HelloWorld</title>
<meta http-equiv="Cache-Control" content="no-cache" />
</head>
<body>
<center>
HelloWorld<hr>
<object data="KJXファイル名" type="application/x-kjx" copyright="no" standby="download">
<param name="disposition" value="devkdj2" valuetype="data" />
<param name="size" value="ファイルサイズ" valuetype="data" />
<param name="title" value="アプリ名" valuetype="data" />
</object>
</center>
</body>
</html>
今回は、ファイルサイズ"1553"(開発環境によって若干変わります)、アプリ名"HelloWorld"の"HelloWorld.kjx"をダウンロードするので次のように記述します。
HelloWorld.html
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>HelloWorld</title>
<meta http-equiv="Cache-Control" content="no-cache" />
</head>
<body>
<center>
HelloWorld<hr>
<object data="HelloWorld.kjx" type="application/x-kjx" copyright="no" standby="download">
<param name="disposition" value="devkdj2" valuetype="data" />
<param name="size" value="1553" valuetype="data" />
<param name="title" value="HelloWorld" valuetype="data" />
</object>
</center>
</body>
</html>

XHTMLについて詳しく知りたい人は、auの運営しているサイト「EZwebホームページを作ろう」を参照してください。


au端末での実行
KJXファイル「HelloWorld.kjx」とダウンロード用XHTML「HelloWorld.html」が用意できたら、FTPソフトでWebサーバに転送します。au端末で「HelloWorld.html」にアクセスして、アプリをダウンロードできるか試してください。


★複数の音を同時に再生する★


次に、複数の音を同時に再生するプログラム「PhrasePlayerEx」を作ります。画面下のメニューの「再生」を選択すると音が1回鳴ります。「ループ」を選択すると音が繰り返し鳴りつづけ、「停止」を選択するとループが終了します。

「ループ」を選択して音を繰り返し鳴らしながら「再生」を選択することで、2つの音が同時に鳴ることを確認できます。今回のプログラムは、以下の2つのクラスで構成されています。 「Project Name」に"PhrasePlayerEx"を指定して、プロジェクトを作成してください。


「OK」ボタンを押した後、アプリの属性を設定するダイアログが開くので、「MicroEditionProfile」に「KDDIP-2.5」を指定してください。これで、KDDIプロファイルのPhase2.5が使えるようになります。



サウンドファイルの準備
EZアプリで複数の音を同時に鳴らすことができるファイル形式は「SMAF/Phrase(*.spf)」です。SMFファイル(*.mid)をSMAF/Phraseファイル(*.spf)に変換するにはヤマハの公式ツールを使います。

今回のプログラムで使用するサウンドファイルは1つです。resディレクトリ(C:\ezplusTools\Tools\CmdTool\project\PhrasePlayerEx\res)に置いてください。

・アラーム
sound.spf


PhrasePlayerExクラス
PhrasePlayerExクラスは、プログラムの本体となるクラスです。
PhrasePlayerEx.java
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

//フレーズプレイヤー(本体)
public class PhrasePlayerEx extends MIDlet {

    //コンストラクタ
    public PhrasePlayerEx() {
        Display.getDisplay(this).setCurrent(new PhrasePlayerCanvas());
    }

    //アプリの開始
    public void startApp() {
    }

    //アプリの一時停止
    public void pauseApp() {
    }

    //アプリの終了
    public void destroyApp(boolean unconditional) {
    }
}


PhrasePlayerCanvasクラス
PhrasePlayerCanvasクラスは、キャンバスとなるクラスです。
PhrasePlayerCanvas.java
import  com.jblend.media.smaf.phrase.*;
import  javax.microedition.lcdui.*;

//フレーズプレイヤー(キャンバス)
class PhrasePlayerCanvas extends Canvas
    implements CommandListener,PhraseTrackListener {
    private PhrasePlayer player;//フレーズプレイヤー
    private Phrase       data;  //フレーズデータ
    private PhraseTrack  track0;//トラック0
    private PhraseTrack  track1;//トラック1
    private boolean      loop;  //ループ
    private Command      soft1; //ソフトキー1
    private Command      soft2; //ソフトキー2
    private Command      soft3; //ソフトキー3

    //コンストラクタ
    PhrasePlayerCanvas() {
        try {
            //フレーズプレイヤー
            player=PhrasePlayer.getPlayer();

            //フレーズデータ
            data=new Phrase("resource:sound.spf");

            //トラック0
            track0=player.getTrack();
            track0.setPhrase(data);

            //トラック1
            track1=player.getTrack();
            track1.setPhrase(data);
            track1.setEventListener(this);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //コマンド
        soft1=new Command("再生",Command.SCREEN,1);
        addCommand(soft1);
        soft2=new Command("ループ",Command.SCREEN,2);
        addCommand(soft2);
        soft3=new Command("停止",Command.SCREEN,3);
        addCommand(soft3);
        setCommandListener(this);
    }

    //描画
    public void paint(Graphics g) {
        g.setColor(255,255,255);
        g.fillRect(0,0,getWidth(),getHeight());
        g.setColor(0,0,0);
        g.drawString("PhrasePlayerEx",0,0,g.LEFT|g.TOP);
    }

    //コマンドイベント
    public void commandAction(Command c,Displayable s) {
        //音の再生
        if (c==soft1) {
            try {
                track0.play();
            } catch(Exception e) {
            }
        }
        //音のループ再生
        else if (c==soft2) {
            try {
                loop=true;
                track1.play();
            } catch(Exception e) {
            }
        }
        //音の停止
        else if (c==soft3) {
            try {
                loop=false;
                track0.stop();
                track1.stop();
            } catch(Exception e) {
            }
        }
    }

    //プレイヤーのイベント
    public void eventOccurred(int event) {
        if (loop && event==-1) {
            try {
                track1.play();
            } catch(Exception e) {
            }
        }
    }
}


com.jblend.media.smaf.phraseパッケージ
複数の音を同時にならすためのクラスは、com.jblend.media.smaf.phraseパッケージに含まれています。実はこのパッケージはボーダフォンのVアプリにも存在します。つまり、利用した拡張APIが音の再生だけであれば、auもボーダフォンも同じプログラムが動きます。ただし、属性や実行ファイル形式が異なるので再ビルドは必要です。


SMAF/Phraseデータ
SMAF/Phraseファイルを読み込むには、Phraseクラスを使います。コンストラクタは次の通りです。
Phrase(String location)
location:読み込み先

読み込み先を次の書式で指定します。
resource:ファイル名

今回は、"sound.spf"を読み込むので、次のようになります。
PhrasePlayerCanvas.javaの一部
data=new Phrase("resource:sound.spf");


SMAF/Phraseプレイヤー
SMAF/Phraseを鳴らすのにはPhrasePlayerクラスを使います。PhrasePlayerクラスのgetPlayer()メソッドでPhrasePlayerオブジェクトを取得します。
PhrasePlayerCanvas.javaの一部
player=PhrasePlayer.getPlayer();

SMAF/Phraseプレイヤーでは、複数のサウンドを同時に鳴らすために、複数のトラックを生成します。PhrasePlayerオブジェクトのgetTrack()メソッドでPhraseTrackオブジェクトを取得してください。このPhraseTrackオブジェクトを操作してサウンドを鳴らします。トラックにSMAF/Phraseデータを設定するには、PhraseTrackクラスのsetPhrase()メソッドを使います。

また、音を再生するにはplay()メソッド、停止するにはstop()メソッド、一時停止するにはpause()メソッド、再開するにはresume()メソッドを使います。
void play()
void play(boolean repeat)
repeat:繰り返し演奏するか
void stop()
void pause()
void resume()

今回は、PhraseTrackオブジェクトを取得してdata変数を設定するので、次のようになります。
PhrasePlayerCanvas.javaの一部
track0=player.getTrack();
track0.setPhrase(data);


PhraseTrackリスナー
PhraseTrackリスナーは、SMAF/Phraseプレイヤーの演奏が開始したことや、終了したことことなど、演奏イベントを受信するためのリスナーです。

まずはじめに、PhrasePlayerCanvasクラス自身にメディアリスナーのインタフェースを実装します。
PhrasePlayerCanvas.javaの一部
class PhrasePlayerCanvas extends Canvas
implements CommandListener,PhraseTrackListener {

次に、PhrasePlayerCanvasクラスのsetEventListener()メソッドで、演奏イベントが発生した時、そのことをどこへ送信すればよいかを指定します。今回はPhrasePlayerCanvasクラス自身がメディアリスナーになるのでthisをセットします。
PhrasePlayerCanvas.javaの一部
track1.setEventListener(this);

演奏イベント発生時には、メディアリスナーのeventOccurred()メソッドが呼ばれます。
void eventOccurred(int event)
event:イベント(1:再生終了、-2:ループ、0以上:ユーザイベント)

今回は、ループとして再生した音が再生終了した時、再び再生するために使用しています。
PhrasePlayerCanvas.javaの一部
public void eventOccurred(int event) {
    if (loop && event==-1) {
        try {
            track1.play();
        } catch(Exception e) {
        }
    }
}


エミュレータでの実行
2003年9月現在、Phase2.5のEZアプリの開発ツールは一般公開されていますが、エミュレータは提供されていません。そのため、実機で直接動作テストする必要があります。


★待ち受けアプリを作る★


それでは本題の、「待ち受けアプリ」作りに入ります。アプリを待ち受けアプリとして起動すると、そらみが画面中央に現れ、電話かかってきたり、メールが着信したことを教えてくれます。

iアプリの待ち受けアプリには「活性化状態」(キーイベントを受信できる状態)と「非活性化状態/休眠状態」(キーイベントはネイティブOSに通知し、電話としての操作できる状態)を切り替える機能がありますが、auにはありません。


今回のプログラムは、以下の2つのクラスで構成されています。 「Project Name」に"MAppliEx"を指定して、プロジェクトを作成してください。


画像ファイルの用意
このアプリでは以下の2枚の画像ファイルを使います。resディレクトリ(C:\ezplusTools\Tools\CmdTool\project\MAppliEx\res)に置いてください。


・待ち受け状態

-0.png
-128x128




・メッセージ表示状態

-1.png
-128x128



MAppliExクラス
MAppliExクラスは、プログラムの本体となるクラスです。
MAppliEx.java
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

//待ち受けアプリ(本体)
public class MAppliEx extends MIDlet {
    static MIDlet current;

    //コンストラクタ
    public MAppliEx() {
        current=this;
        Display.getDisplay(this).setCurrent(new MAppliCanvas());
    }

    //アプリの開始
    public void startApp() {
    }

    //アプリの一時停止
    public void pauseApp() {
    }

    //アプリの終了
    public void destroyApp(boolean unconditional) {
    }
}

MAppliCanvasクラスでMAppliExオブジェクトを操作できるように、スタティック変数currentに自身(this)をセットしています。
MAppliEx.javaの一部
static MIDlet current;//MAppliExオブジェクト

MAppliEx.javaの一部
current=this;


MAppliCanvasクラス
MAppliCanvasクラスは、キャンバスとなるクラスです。
MAppliCanvas.java
import com.kddi.matiuke.*;
import javax.microedition.lcdui.*;

//待ち受けアプリ(キャンバス)
public class MAppliCanvas extends Canvas
    implements AlarmEventListener,CallEventListener,
    CMailEventListener,EMailEventListener {
    //シーン
    private final static int
        S_NONE =0,           //なし
        S_ALARM=1,           //アラーム
        S_CALL =2,           //音声着信
        S_CMAIL=3,           //Cメール受信
        S_EMAIL=4;           //Eメール受信
    private int scene=S_NONE;//シーン
    private int init =S_NONE;//初期化

    //セリフ
    private final static String[][] SERIF={
        null,                                            //なし
        {"なになに!? アニメ","かアニラジの時間!?"}, //アラーム
        {"今の電話、お相手は誰","だったのぉ〜?"},       //音声着信
        {"Cメール届いたね。迷","惑でなきゃいいけど。"}, //Cメール受信
        {"Eメールキター!",    "どんな内容かなぁ〜?"}};//Eメール受信

    //イメージ
    private Image[] image=new Image[2];//イメージ

    //オフイメージ
    private Image    offImage;   //オフイメージ
    private Graphics offGraphics;//オフグラフィックス

    //コンストラクタ
    MAppliCanvas() {
        try {
            //イメージの読み込み
            image[0]=Image.createImage("/0.png");
            image[1]=Image.createImage("/1.png");

            //オフイメージの生成
            offImage=Image.createImage(128,128);
            offGraphics=offImage.getGraphics();

            //フォントの設定
            if (Font.getDefaultFont().stringWidth("A")>6) {
                offGraphics.setFont(Font.getFont(Font.FACE_MONOSPACE,
                    Font.STYLE_PLAIN,Font.SIZE_SMALL));
            }
        } catch (Exception e) {
        }

        //イベントマネージャの設定
        EventManager em=EventManager.getEventManager();
        em.setAlarmEventListener(this);
        em.setCallEventListener(this);
        em.setCMailEventListener(this);
        em.setEMailEventListener(this);
    }

    //描画
    public synchronized void paint(Graphics g) {
        if (offImage!=null) {
            //シーンの設定
            scene=init;

            //オフイメージに描画
            if (scene==S_NONE) {
                offGraphics.drawImage(image[0],0,0,
                    Graphics.LEFT|Graphics.TOP);
            } else {
                offGraphics.drawImage(image[1],0,0,
                    Graphics.LEFT|Graphics.TOP);
                offGraphics.setColor(255,255,255);
                offGraphics.drawString(SERIF[scene][0],4,93,
                    Graphics.LEFT|Graphics.TOP);
                offGraphics.drawString(SERIF[scene][1],4,108,
                    Graphics.LEFT|Graphics.TOP);
            }

            //実際の画面に描画
            g.drawImage(offImage,getWidth()/2,getHeight()/2,
                Graphics.HCENTER|Graphics.VCENTER);
        }
    }

    //アラームがあった時に呼ばれる
    public void alarmNotified() {
        init=S_ALARM;
        repaint();
    }

    //音声着信があった時に呼ばれる
    public void called(CallEvent event) {
        init=S_CALL;
        repaint();
    }

    //Cメール受信があった時によばれる
    public void cmailReceived(CMailEvent event) {
        init=S_CMAIL;
        repaint();
    }

    //Eメールのシグナル受信時に呼ばれる
    public void emailSignaled() {
        MAppliEx.current.notifyPaused();
    }

    //Eメール受信があった時に呼ばれる
    public void emailReceived(EMailEvent event) {
        init=S_EMAIL;
        repaint();
    }

    //キープレスイベント
    public void keyPressed(int keyCode) {
        if (keyCode!=0) {
            int action=getGameAction(keyCode);
            if (action==FIRE) {
                init=S_NONE;
                repaint();
            }
        }
    }
}


シーンの遷移
今回のアプリには、以下の5つのシーンがあります。現在のシーンはint型変数sceneで保持しています。次に遷移するシーンはint型変数initで保持しています。
MAppliCanvas.javaの一部
private final static int
    S_NONE          =0,  //なし
    S_ALARM         =1,  //アラーム
    S_CALL          =2,  //音声着信
    S_CMAIL         =3,  //Cメール受信
    S_EMAIL_RECEIVED=4;  //Eメール受信
private int scene=S_NONE;//シーン
private int init =S_NONE;//初期化

何かキーを押した時「なし」に遷移します。各シーンで表示するセリフはSERIF定数で保持しています。
MAppliCanvas.javaの一部
private final static String[][] SERIF={
    null,                                  //なし
    {"アラームキター",    "間違いだけど"}, //アラーム
    {"音声着信キター",    "間違いだけど"}, //音声着信
    {"Cメール受信キター","間違いだけど"}, //Cメール受信
    {"Eメール受信キター","間違いだけど"}};//Eメール受信


ダブルバッファリング
ダブルバッファリングとは、画面の描画部分と同じサイズのイメージ(オフイメージと呼びます)を用意し、必要なものをこのイメージに描画してから、実際の画面にまとめて描画させるという処理です。画面がちらつくことを防ぎます。

イメージを生成するには、ImageクラスのcreateImage()メソッドを使います。また、イメージに描画するためのGraphicsオブジェクトを取得するには、getGraphics()メソッドを使います。

MAppliCanvas.javaの一部
private Image offImage; //オフイメージ
private Graphics offGraphics;//オフグラフィックス

MAppliCanvas.javaの一部
offImage=Image.createImage(128,128);
offGraphics=offImage.getGraphics();

オフイメージや実際の画面に描画する処理は、paint()メソッドで行っています。アプリ起動時など再描画が必要な時や、Canvasクラスのrepaint()メソッドを呼んだ時、実機からこのメソッドが呼ばれます。

MAppliCanvas.javaの一部
public synchronized void paint(Graphics g) {
    if (offImage!=null) {
        //シーンの設定
        scene=init;

        //オフイメージに描画
        if (scene==S_NONE) {
            offGraphics.drawImage(image[0],0,0,
                Graphics.LEFT|Graphics.TOP);
        } else {
            offGraphics.drawImage(image[1],0,0,
                Graphics.LEFT|Graphics.TOP);
            offGraphics.setColor(255,255,255);
            offGraphics.drawString(SERIF[scene][0],4,93,
                Graphics.LEFT|Graphics.TOP);
            offGraphics.drawString(SERIF[scene][1],4,108,
                Graphics.LEFT|Graphics.TOP);
        }

        //実画面に描画
        g.drawImage(offImage,getWidth()/2,getHeight()/2,
            Graphics.HCENTER|Graphics.VCENTER);
    }
}


フォントサイズの設定
デフォルトフォントの幅は半角6ドットのものが多いですが、機種によってはそれより大きなものもあります。そこで、デフォルトフォントの幅が6ドットより大きい時は、小さなフォントを指定しています。
MAppliCanvas.javaの一部
if (Font.getDefaultFont().stringWidth("A")>6) {
    offGraphics.setFont(Font.getFont(Font.FACE_MONOSPACE,
        Font.STYLE_PLAIN,Font.SIZE_SMALL));
}

デフォルトフォントのオブジェクトが取得するにはFontクラスのgetDefaultFont()メソッド、文字列の幅を取得するにはstringWidth()メソッドを使います。
static Font getDefaultFont()
戻り値:デフォルトフォントのオブジェクト
int stringWidth(String str)
str:文字列
戻り値:文字列の幅

フォントを生成するにはFontクラスのgetFont()メソッドを使います。
static Font getFont(int face,int style,int size)
face:フォントフェイス
style:フォントスタイル
size:フォントサイズ
戻り値:フォント

faceにはフォントフェイス定数、styleにはフォントスタイル定数、sizeにはフォントサイズ定数を指定します。フォントフェイスやフォントスタイルを指定しても、端末が対応するフォントを持っていなければ、デフォルトフォントが使われます。
フォントフェイス定数
Font.FACE_SYSTEM システム
Font.FACE_PROPORTIONAL プロポーショナル
Font.FACE_MONOSPACE モノスペース

フォントスタイル定数
Font.STYLE_PLAIN プレーン
Font.STYLE_BOLD ボールド
Font.STYLE_ITALIC イタリック

フォントサイズ定数
Font.SIZE_LARGE
Font.SIZE_MEDIUM
Font.SIZE_SMALL

フォントを指定するには、GraphicsクラスのsetFont()メソッドを使います。このメソッドを使った後、それ以降の文字列描画時に、指定されたフォントが適用されます。
void setFont(Font font)
font:フォント


待ち受けイベントの設定
受信できる待ち受けイベントには次の4種類があり、イベントごとに待ち受けるリスナーを実装するインタフェースが用意されています。
アラーム AlarmEventListener
電話着信 CallEventListener
Cメール着信 CMailEventListener
Eメール着信 EMailEventListener

MAppliCanvas.javaの一部
implements AlarmEventListener,CallEventListener,
CMailEventListener,EMailEventListener {

待ち受けるイベントに対応するリスナを実装して、com.kddi.matiukeパッケージの「EventManagerオブジェクト」に登録します。EventManagerオブジェクトを取得するには、EventManagerクラスのgetEventManager()メソッドを使います。
MAppliCanvas.javaの一部
EventManager em=EventManager.getEventManager();

AlarmEventListenerを登録するにはsetAlarmEventListener()メソッド、CallEventListenerを登録するにはsetCallEventListener()メソッド、CMailEventListenerを登録するにはsetCMailEventListener()メソッド、EMailEventListenerを登録するにはsetEMailEventListener()メソッドを使います。
MAppliCanvas.javaの一部
em.setAlarmEventListener(this);
em.setCallEventListener(this);
em.setCMailEventListener(this);
em.setEMailEventListener(this);

アラームが発生すると、アプリは一時停止し、アラーム動作に遷移します。ユーザーがアラームを解除するとアプリが再開され、AlarmEventListenerのalarmNotified()メソッドが呼ばれます。
void alarmNotified()

電話着信が発生すると、アプリは一時停止し、着信動作に遷移します。通話が終了すると、アプリが再開され、CallEventListenerのcall()メソッドが呼ばれます。
void called(CallEvent event)
event:イベント内容

引数としてイベント内容を保持するCallEventオブジェクトが渡されますが、セキュリティのため一般ユーザーは使用できません。

Cメールを受信すると、単発モードの場合は受信直後にCMailEventListenerのcmailReceived()メソッドが呼ばれます。
void cmailReceived(CMailEvent event)
event:イベント内容

引数としてイベント内容を保持するCMailEventオブジェクトが渡されますが、セキュリティのため一般ユーザーは使用できません。

Eメールを着信すると、EMailEventListenerのemailSignaled()メソッドが呼ばれます。この時はまだEメールの中身を受信されていません。受信するにはMIDletクラスのnotifyPaused()メソッドを呼ぶなどして、アプリを一時停止状態にする必要があります。
void notifyPaused()

一時停止状態になった後、端末がEメールを受信するかどうかはユーザーの設定に依存します。Eメール受信後、アプリが再開した時、通常通りMIDletクラスのstartApp()メソッドが呼ばれます。端末がEメールを受信してた時、メール1通につきEmailEventListenerのemailReceived()メソッドが1回呼ばれます。
void emailReceived(EMailEvent event)
event:イベント内容

引数としてイベント内容を保持するEMailEventオブジェクトが渡されますが、セキュリティのため一般ユーザーは使用できません。


★おわりに★


次回は、ボーダフォンの新機能を使ったゲームを作る予定です。お楽しみに。



−戻る−


(C)Npaka/Sehira, 2003-2004