Gearいろいろ

Spiacente Solamente giapponese
Sorry Only Japanese


忘れないうちにGaerについてのTIPSやいじったところのメモを残しておきたいと 思う。LGPLなライブラリなので、サポートはしませんが、丸ごとソースが必要な 場合は連絡ください。

ソースファイルの構成
src/gear/application メインのイベント関係のクラスが含まれています。utilsもこのフォルダ にありJ2ME用のサポートクラスやBase64のクラスがあります。
src/gear/communication クッキーの処理を追加したHTTPアクセスクラスが入っています。 HttpConnectionを継承してるのでJV-Liteではヘッダーが256倍との制限が ありOAuthなどのヘッダーに256バイト以上のデータが必要な場合は使えません。
src/gear/exceptions エクセプションのクラスが入っています。
src/gear/hardware 機種チェックなどのクラスが入っています。
src/gear/location 位置情報の処理用のクラスが含まれています。これはGearの開発者が最初 に作ったアプリケーションが位置情報を使ったサービスだったためだと思われます。 ヨーロッパ系の携帯用のコードと思われ、日本では使えません。
src/gear/widgets キャンバスやリストのUIクラスが含まれています。UIはiPhoneの スプリングボードのようなインターフェースとリストのインターフェース だけしかありません。フォームや文字入力はJ2MEのインターフェースを そのまま使うことになります。独自に描画を行う場合はGWCanvasを継承して クラスを作ります。

GWTextEditのmicroemulatorでの不具合の修正は これです。

Gearで注意が必要なのはWidgetを表示する時にクラスを指定できる事がある。 これはおそらく内部的にはインスタンスになっているが、使い回しが出来る ように内部的にインスタンスをプールして再利用しているようにみえる。表示 の時は直接newで作ったインスタンスを指定する事も出来るので使い分ければ 良いのかもしれない。

とりあえずWILLCOMを判定する処理は以下をHardwareInfo.javaに追加。
    public static String getPlatform() {
      :
	        else if (currentPlatform.indexOf("wx3") == 0)
	        	return Platform.WILLCOM;



	/**
	 * Checks if the application is running on a Willcom mobile phone
	 * @deprecated Use getPlatform() method instead
	 * @return true if the application is running on a Willcom mobile phone
	 */
	public static boolean isWillcom() {
		try {
			return System.getProperty("microedition.platform").indexOf("WX3")==0;
		} catch (RuntimeException e) {
			return false;
		}
	}
カメラと位置情報のサポート確認はHardwareInfo.javaに以下を追加
    /**
      * Checks if the the support willcom location
      */	
    public static boolean isWillcomSupportLocation(){
        // detecting Location support
        try {
            Class.forName("com.jvlite.device.Location");
            return true;
        } catch (ClassNotFoundException ex) {
        }
        return false;
    }
    /**
      * Checks if the the support willcom camera
      */	
    public static boolean isWillcomSupportCamera(){
        // detecting Camera support
        try {
            Class.forName("com.jvlite.device.Camera");
            return true;
        } catch (ClassNotFoundException ex) {
        }
        return false;
    }
うまく動かないかも。WX320KでisWillcomSupportCameraがtrueが返るっぽい。

GearではCommandをJ2MEの処理ではなく自前で処理するように作られている。これ は、おそらくJ2MEのCommandだと画面の下に自分たちのイメージと違うボタンが勝 手に表示される事を嫌ったためではないかと思う。しかしJV-Lite2でははCommand のボタンが出たままなので、ただでさえ狭い画面でボタンの上にGearのボタンバー が表示されて無駄だ。 ということで、自前の処理ではなく、J2MEの処理を使えるようにしてみた。 GWCanvas.javaに追加したコードは以下。
    /**
      * Adds the selected command to the widget
      * @param cmd the command to be added
      * @param listener the J2ME listener
      */
    public void addJ2MECommand(Command cmd, CommandListener listener) {
        sharedGWCanvas.addCommand(cmd);
        sharedGWCanvas.setCommandListener(listener);
    }
バーの領域を確保しないためのコードはGWCanvas.javaで以下の変更
    if(HardwareInfo.getPlatform() != HardwareInfo.Platform.WILLCOM)
        bottomBarHeight = commandsFont.getHeight()+titlePadding*2;
Gearのコマンドとの違いはCanvas毎にCommandを設定できないと。これは widgetでCanvasを使い回しているためです。EXITとかはすべてのwidgetで 使えても良いかもとか、同等にするには根本的なGearの構造をいじる必要 があるかもでこれでよしとしたい。

プログレスダイアログのサポートはGWCanvas.javaに以下を追加。
    /**
      * 
      */
    protected void startProgress(String message){
        alertMessage = message;
        alertMessageLines=null;
        progressPopUp = captureFrame(screenWidth,screenHeight);
        new progressThread().start();
        repaint();
    }

    /**
      * 
      */
    protected void stopProgress(){
       synchronized(progressPopUp) {
           progressPopUp = null;
       }
       repaint();		
    }

    /**
      * 
      */
    class progressThread extends Thread {
        public void run() {
            while(true) {
                try{
                    Thread.sleep(200);
                }catch(Exception e){
                }
                if(progressPopUp == null)
                    break;
                repaint();
                ++progCount;
                if(progCount == 8)
                    progCount = 0;
            }
        }
    }

    :
    :
    } else if (progressPopUp != null){
         if (alertMessageLines==null){
             alertMessageLines = StringHelper.wrapText(alertMessage, 
                 titleFont, 6*screenWidth/8 - 20);
         }
         graphicContext.drawImage(progressPopUp, 0, 0,
             Graphics.TOP | Graphics.LEFT);

         graphicContext.setColor(getSelectedBackground());
         graphicContext.fillRoundRect(screenWidth / 8, 2*screenHeight / 6, 
             6*screenWidth/8, 2*screenHeight/6, 10, 10);

         graphicContext.setColor(getSelectedBorder());
         graphicContext.drawRoundRect(screenWidth / 8, 2*screenHeight / 6,
             6*screenWidth/8, 2*screenHeight/6, 10, 10);

         graphicContext.setFont(titleFont);
         graphicContext.setColor(getForeground());
         for (int i=0;i<alertMessageLines.length;i++)
             graphicContext.drawString(alertMessageLines[i],
                 screenWidth / 8 + 10 ,
                 2*screenHeight / 6 + 10 + (titleFont.getHeight()+titlePadding)*i,
                 Graphics.TOP | Graphics.LEFT);

         Image progContImg = null;
         try{
             progContImg = Image.createImage("/prog.png");
         } catch(Exception e){
         }
         Image prog = Image.createImage(progContImg, 0+32*progCount, 0,
             32, 32, Sprite.TRANS_NONE);
         graphicContext.drawImage(prog, screenWidth / 2, screenHeight/2 + 10,
             Graphics.TOP|Graphics.HCENTER);
    }
リモートロギングのソースはこれ。 使い方は以下をアプリのソースに追加。
    Logger.out = new RemoteLogger("socket://hoge.foo.jp:8000");
これでグローバルアドレスのhoge.foo.jpなFreeBSDなどでnc -l 8000すればOKです。

ローカルポート(USBポート)を使う場合は以下のような感じ。
    Logger.out = new RemoteLogger("comm:COM1;baudrate=115200;bitsperchar=8;stopbits=1;parity=none");
でMacOS Xのターミナルなどで下記を実行するとログが確認できます。
% cu -l /dev/cu.ah-k3001v.modem
リスト表示が遅いので、描画の無駄を減らせるようにちょっといじってみた。 GWList.JavaでaddItem処理の描画をコメントアウト。
    public ImageItem addItem(ListItem newItem) {
        super.addItem(newItem);
//      repaintIcons();
        return newItem;
    }
GWForm.Javaで以下をコメントアウト。
    public ImageItem addItem(ImageItem newItem) {
        synchronized (components) {
            newItem.setParent(this);
            components.addElement(newItem);
            newItem.setStretchIcon(isStretchIcons());
//          setSelectedIndex(0);
        }
        return newItem;
    }
アプリ側のコードでListにすべてのItemを追加した後に、setSelectedIndex(0) を呼ぶ必要があるが少し早くなった気がする。

GWTextEditから戻ってきた時に、何の入力だったかを判定するテクニック
  protected boolean showCheck(Display display, EventArg eventArgs){
    if (eventArgs.getClass() == TextEditArgs.class){
      TextEditArgs args = (TextEditArgs)eventArgs;
      String titelstr = args.getTitle();
      if(titelstr.equals("twitter status")) {
        :
        :
Widgetを移る時にHTTPでデータを読み込む場合は移った先のWidgetのコードに アクセス用の処理を入れておいて、処理が完了した時にもとのWidgetから移る 切り替わるようにしている。具体的には以下のようなinterfaceを用意している。
public interface WidgetListener {
        void changeWidget(GWDisplayable nextwidget);
        void errorWidget(Exception e);
}
親側の実装は以下のような感じ。
  public void changeWidget(GWDisplayable nextwidget) {
    stopProgress();
    repaint();
    EventManager.getInstance().enqueueEvent(new DisplayWidget(this, 
      nextwidget, SlideRight.class));
  }
        
  public void errorWidget(Exception e) {
    stopProgress();
    repaint();
    displayAlert("Network error. " + e.toString(), 2000); // 2000ms
  }
ブラウザーを起動するためにGearMidilet.javaに以下を追加してみた。WILLCOMの PHSの場合Javaアプリを終了しないとブラウザが起動できないのでかなり不便かも。。。
	public static void QuitAndPlatformRequest(String req)
	{
		try {
			midlet.platformRequest(req);
			if(HardwareInfo.isWillcom())
				midlet.notifyDestroyed();
		} catch (Exception e) {
		}		
	}
ImageHelper.GraphicEffects.blurFilter()がBAUMだと遅すぎてかなり厳しい。。。 なんらかの最適化するか、アルゴリズムを変更した方が良いと思われる。。

contentPaintで重い処理が含まれるキャンバスを表示するときにSlideLeftすると 動作が不安定になる。コンストラクタで処理してcontentPaintを軽くするか 重い処理が終わった後に前のキャンバスのメソッドをコールバックしてSlideLeft するとよい。


Copyright (C) 2009 Hiroki Mori All Rights Reserved.