2011年2月27日日曜日

ぽやっきー

 くそー、blogger の html コード編集の validator のバグで、リンク中に &layout=... と指定してあると、「;」で閉じてないとか、訳わからんエラーを出しやがる。使えねぇー

 macbook で windows 使っている場合のキーボード option と command のキー配置は逆だろー、なんとかなんねぇの?と調べたら、AppleKbWin なるものを見つけた。これは、素晴らしい。

またーりな休日

 本日は、boostjp 勉強会のストリーミングを見て過ごしました。
結構、proto と fusion を除くと、boost じゃない話題の方が圧倒的に面白かったです。楽しみにしていた dtl 、ストリーミングが途中で切れて残念・・・。あと、全般的に息子の面倒を見ながらだったので、いまいち集中しきれなかった。
 個人的には、テクニックに走りすぎるのは、如何なものか?というのも感じました(Twitter のツッコミは、もっとストレートな表現で、結構、爆笑してますた)。
 畑違いな「ゲーム開発のC++」、めちゃ面白かったです。

 触発されて、proto いじりたくなってきました・・・。

2011年2月22日火曜日

坊ちゃんスキー

 日曜日に、例のごとく、手稲ハイランドへ。山頂からオリンピアへ降りて、「なんちゃってクロス」を滑りました。ぼっちゃん、なんちゃってクロスがお気に入りのようで、いけてる時は、こけずにスイスイ滑ります。ビデオに撮ろう頑張りましたが、滑りながらの撮影では、全然追いつけなかったorz。
 ちなみに、「僕、どんな斜面でもお父さんと一緒なら滑れるから大丈夫」と言って、女子大回転コースの方に行かされました。いやいや、俺がしんどいですから、勘弁してください(一番急な所は坊ちゃん抱えて横滑りで降りる)。聖火台アタックコースを降りると言い出した時は、さすがに勘弁してもらいました。今度は、コブ用の板を持っていって、後半は坊ちゃんをキッズパークで遊ばせて、聖火台アタックコース滑ろう。 

2011年2月19日土曜日

Android TimerHandler

postDelayed の機構が理解できたという訳で、TimerHandler クラスを作成してみました。ネーミングはちょっといまいちかも?

  2011/2/20 に nextPost() に重要な修正が入ってます

import android.os.Handler;
import android.util.Log;

public class TimerHandler {
  private static final String TAG = "TimerHandler";
  private static final boolean DEBUG_ON = true;
  private Handler handler_;
  private Runnable timeRunner_;
  private Runnable intervalRunner_;
  private long intervalMillisecs_;

  private void nextPost() {
    if(DEBUG_ON) Log.d(TAG,"nextPost");
    // ここでの実行する順序は重要。先にポストしておかないと、
    // timeRunner_ 中から stopTimer(); が呼び出せない。
    handler_.postDelayed( intervalRunner_, intervalMillisecs_);
    timeRunner_.run();
  }

  public void startTimer() {
    if(DEBUG_ON) Log.d(TAG,"startTimer");
    handler_.removeCallbacks(intervalRunner_);
    handler_.postDelayed(
    intervalRunner_,
    intervalMillisecs_ );
  }

  public void stopTimer() {
    if(DEBUG_ON) Log.d(TAG,"stopTimer");
    handler_.removeCallbacks(intervalRunner_);
  }

  TimerHandler(
    Runnable timeRunner,
    long intervalMillisecs
  ) {
    if(DEBUG_ON) Log.d(TAG,"TimerHandler");
    handler_ = new Handler();
    timeRunner_ = timeRunner;
    intervalMillisecs_ = intervalMillisecs;
    intervalRunner_ = new Runnable() { public void run() { nextPost(); } };
  }
}


使い方は、こんなんです。
class Hoge extends Activity {
  private final String TAG = "Hoge";
  private TimerHandler timerHandler_;
  //...
  boolean bTimer = false;
  private void onTimer() {
    Log.d(TAG,"onTimer");
    bTimer = !bTimer;
    if( bTimer ) Toast.makeText(this, "○",Toast.LENGTH_SHORT).show();
    else Toast.makeText(this, "×",Toast.LENGTH_SHORT).show();
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //...
    timerHandler_ = new TimerHandler( new Runnable() { public void run() { onTimer(); }}, 3000 );
  }

  @Override
  protected void onPause() {
    timerHandler_.stopTimer();
    super.onPause();
  }

  @Override
  protected void onResume() {
    timerHandler_.startTimer();
    super.onResume();
  }

  @Override
  protected void onDestroy() {
    // 念のために呼び出ししておかないと、ハンドラが残ったままゾンビ化する
    // onDestroy で、メッセージキューのクリーンアップ処理とかが
    // まともに実行されていないくさい。
    timerHandler_.stopTimer();
    super.onDestroy();
  }
  //...
}

android Handler による timer 機構

 本日は、Handler の timer 絡みのコードを深堀りしました。

Handler.postAtTime は、Handler.sendMessageAtTime をコールしています。
そして、Handler.sendMessageAtTime は、MessageQueue.enqueueMessage をコールしています。

ここでのトリックは、MessageQueue が、現在取得できる機器の稼働時間 SystemClock.uptimeMillis() と、引数で指定された稼働時間を比較して、指定された稼働時間を過ぎていた場合には、Handler を取り出して実行するというものです。稼働時間が過ぎていない場合には、MessageQueue が queue に溜まっている次の Handler を処理します。
postDelayed の場合は、現在取得できる機器の稼働時間に指定された millisec を足して、sendMessageAtTime しています。

なるほど、これはスマートなやり方だ。ちなみに、だからといって一度に大量の Handler を postDelayed で投入するのは、賢いやり方とは言えない。

機器の稼働時間がオーバーフローする事は無いのかな・・・

MapActivity couldn't get connection factory client 手詰まり???

 いろいろと解決策を探って試してみたが、まったく解決できない。手詰まりだ。
実行すると、MapActivity couldn't get connection factory client と表示される。地図自体は表示される。
デバッグで実行しようとすると、ダイアログが出てブラックスクリーンになる・・・と思っていたら、なんかしらんが、今、実行できるようになってしまった。なんなんだ、一体?

推定するに、キーを検証するのに時間がかかって、一回はエラーになるが、その後キーの検証が通って普通に実行できているという状況なのだと思う。ちなみに、未だに MapActivity couldn't get connection factory client は表示されている。

対処法参考:
Androidのデバッグ用キーストアとキーを生成する方法
 [Android] debug.keystoreが生成されていなかったときにやるべきこと

2011年2月17日木曜日

android の設計がいろいろ気になる

 PreferenceActivityが、使いでが無いのである。個々の値が表示されないので、ユーザは何が設定されているか脳内に記憶しとけという事らしい。ReadOnly の項目が無いくさいので、結局自前でダイアログを書いた方がマシってもんである。UIに関しても、iOS と比較すると圧倒的なデザイン力の差が出ていると断言できます。

 Activity の onResume と onPause が Activity を切り替える時に発生するので、このタイミングで unbindService したり、bindService してると、onActivityResult のイベント時に、サービスの準備が整っていなくて、どはまりするという…。いやはや、参りますね…。

 こういう事ばかり経験していると、以下のようなバッドノウハウが当たり前になってくる…。
  Handler handler_ = new Handler();
  public void postHoge() {
    handler_.post( new Runnable() {
      public void run() {
         // メインスレッドで実行したいコード
         hoge();
      }
    });
  }

  new Thread(new Runnable() {
    public void run() {
      // 1秒後に、Looper のメッセージキューへハンドラが投入される
      // この1秒という数字には、何の根拠も無い。
      // 9割方は、うまく動作するだろう。しかし、稀にエラーを引き起こすだろう。
      Thread.sleep( 1000 );
      postHoge();
    }
  }).start();

 もちろん、こんな根拠の無いコードは書かない。ただし、何かウェイトを入れなければならない場合には、関数 hoge() のコード内から、状況を確認した上で、Thread.sleep を駆使して、postHoge() するようなコードは、十分考えられる。ただし、状況が改善されるのが、異なるスレッドからによる場合に限定される。

Android Exif GPS

どういう形式なのか、さっぱりわからなかったが、以下のようで良いようだ。

  public static String latlong2GeoFormat (double latlong) {
    // doubleからintへ変換
    Double _latlong = latlong;
    int num1 = _latlong.intValue();
    double num2d = ((_latlong - (double)num1) * 60);
    int num2 = (int)num2d;
    double num3d = ((num2d - (double)num2) * 60 * 100000);
    int num3 = (int)num3d;
    // フォーマット num1/denom1,num2/denom2,num3,denom3
    return String.format("%d/1,%d/1,%d/100000", num1, num2, num3);
  }

  public static void embedExif(String fileName, Location loc) {
    ExifInterface exif = new ExifInterface(fileName);
    exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, latlong2GeoFormat(loc.getLatitude()));
    exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, "N");
    exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, latlong2GeoFormat(loc.getLongitude()));
    exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, "E");
    exif.saveAttributes();
  }

参考:ExifInterface.TAG_GPS_LATITUDEには何を入れるのか?

2011年2月16日水曜日

Android マジ難い

 いやー、まさか、Android で、Handler による async 処理をやるはめになるとは思わなかった…。
じゃないと、「このアプリケーションは、応答していません」って、怒られちゃう。
こんなコード、本当に必要なの???
つか、普通の人には書けないんじゃないの???

android 開発はマジ難しい

 だいぶ Android 開発の肝も心得てきました。現在販売されている Android 書籍を見ても、ネット上にある Android の開発情報を見ても、まともな Android のコードを書けているのは、10パーセントにも満たないような気がしています。
どこが難しいかは、やはり、イベント絡みでスレッドを意識しなくてはならない事にあります。同じイベントでも、カメラのコールバックと、GPSのイベント通知では機構が異なり、ライブラリの設計そのものが変です。
カメラのコールバック Camera.takePicture で登録したイベントは、推定、Android 実機の実装に依存しそうで、IS03 では、Activity のメインスレッド外で発生します。そのため、巷のコードはアプリケーション・エラーでハングするか、ハングする可能性が高いものが流通しています。 IS03で、カメラをオープンしているアプリがハングすると、どうなるか?電源を切って再起動するまで、カメラが開けません。
Camera.startPreview のコードは、Camera.takePicture の直後に置いては、いけません。スレッドの競合を起こします。 もし、Camera.startPreview が Activity のメインスレッドから呼ばれなければならないのであれば、Handler を使ってコールするように Runnable を post する必要があります。この辺の基準は、正直わかりません。何故なら、Android のライブラリ設計者も、よくわかっていない節があるからです。

Handler は特殊で、ハンドラを生成したメッセージループ Looper スレッドに作用します(実行時のカレントスレッドに作用します)。Handler を保持するクラスに作用するのではありません。従って、別スレッドから、メインスレッドで実行したいコードは、Runnable クラスとして、Handler に post させます。

宣言は、どこでも良いが、スコープには注意した方が良い(Javaは関係ない?)という意味で同一クラスに置く。
Handler handler_ = null;
 しかしそして、Looper.loop(); の実態があるメインスレッドにて
handler_ = new Handler();
する必要があります。Activity に限定すれば、@Override を施したメソッド内で new Handler() をすればよい。ただし、生成は1回のみで十分なので、自ずと onCreate() や、メンバ変数宣言で Handler handler_ = new Handler(); するのが妥当。
ルーパースレッドでは、
public void run() {
    Looper.prepare(); 
    handler_ = new Handler();
    Looper.loop();
  }
とするのが良いでしょう。

 これに対して、Callback 系のメソッドや、ワーカースレッドなどの別スレッドから、UI に関わるようなメインスレッドで実行しなければならないコードは、
public void postHoge() {
    handler_.post(
      new Runnable() {
        @Override
        public void run() {
           // メインスレッドで実行したいコード
           hoge();
        }
      }
    );
  }
というコードを用意しておいて、別スレッドから
// Activity のメソッドであれば
  postHoge();
  // ルーパースレッドのメソッドであれば
  looperThread_.postHoge();

というようにコールすれば良いようです。

ルーパースレッドを終了させるスマートな方法は、ルーパースレッドのメソッドとして
public void postExit() {
    handler_.post(
      new Runnable() {
        @Override
        public void run() {
          Looper.myLooper().quit();
        }
      }
    );
  }
定義したものを、looperThread_.postExit(); してやる事です。looperThread_.interrupt(); するよりは良いでしょう。
まだ、Handler の使いかたは、いろいろあるようですが、難しすぎです。

追記:
2011/02/16 修正 どこでもよい -> 同一クラスに置く,
2011/02/20 修正 どこでもよい -> OK
handler_.post() に相当する関数 runOnUiThread なるものがあるらしい。こいつを使うと
  Handler handler_ = new Handler();
を省略できて、かわりに
  public void postHoge() {
    runOnUiThread(
      new Runnable() {
        @Override
        public void run() {
           // メインスレッドで実行したいコード
           hoge();
        }
      }
    );
  }
と、できるようだ。

2011年2月14日月曜日

まだまだ続くよ Android

 スリープモード時のサービスの継続に関してですが、PowerManager の WakeLock を制御する事で、問題なく解決する事ができました。今度は、カメラを制御しないといけない感じなのですが、思ったよりも面倒くさそうです。

なんつーか、Java は、関数ポインタが無く、Interface しか無いので、似たようなコードが並んで、リファクタリングしたいけど、どうにもスマートに行かないので、悶々とします。いっその事、reflection を使って、メソッド名を引数にとってループを回すようなコードを書いてみようか?という誘惑にも駆られてしまうのですが、今のところ、まだ我慢の子なのであった。

HPが WebOS を発表して、そいつをノートパソコンにも載せるというので、うひょーーーー。反マイクロソフトの狼煙が、こんなところから上がったーーーーと、ビビりました。そこへ来て、ノキアがマイクロソフトと組んで Windows Phone を出すとか・・・。おら、もう何がなんだか理解できねぇよ・・・。Opera の行く末はどうなるの??? なんて混乱していると、ノキアは、Android に勝ちたいらしい。なるほど・・・なのかなぁ???全然わかんねぇです。mac も iPhone の廉価版を出すという噂もあるし、ほんと戦々恐々ですよね。個人的には、WebOSの本気度も、かなり気になります。

Android サービス化での最低ラインクリア

 とりあえず、Android サービス化での最低ラインはクリア・・・。もう大きなハマリどころは、無いと思いたい。アプリは終了しても、サービスは継続できる。後は、スクリーンロックされた状態でも動作するかどうか?まぁ、これで動作しないのであれば、この挙動に関しては、諦めるしかない。
とまぁ、こんな時間になってしまいましたが、上出来でしょうか?
Effective Java」 買ってきたけど、今回の件で参考になる情報は無かった・・・。

2011年2月13日日曜日

Android ぼやきまくろーりん展開

 もはや、ほとんど意味のない「ぼやき」に突入しております。
Service Callback で、StackOverflow するので悩んでいたら、なんと、関数名をダブって定義しているのに気がつかず、再帰コールでStackOverflowしてました orz。Java はソースの見通しが悪いので嫌いです(と言語のせいにしてみる…ちくしょー…つか、気づくよ普通…)。
ハンドラーにも、うんざりしてます。スレッドからスレッドへとメッセージを受け渡すスマートな方法が、ありそうなもんだけど、いちいちカスタム・ハンドラを生成して、自作自演ならぬ自送自受…。
Looper も柔軟そうに見えて融通が利かないです。 incoming event を設定し直す芸当ができないので、Looper 用 Listener Thread を interrupt() して、破棄して、また新たに Listener Thread を new してます。何故かスレッドを再利用しようとすると怒られるので、再利用はできません。

Android ぼやっきー

 くそー、画面を傾けて縦レイアウトから横レイアウトになる時、Activity の onDestroy と onCreate が呼ばれやがる…。つまり、いつ死んでも良いように常に状態を onSaveInstanceState と onRestoreInstanceState で保存と復元をしておけと・・・。
サービス化しても、傾ける度にサービスを再起動させられるんじゃ、たまったもんじゃねぇ。onDestroy では、unbindService しないと怒られる。しょうがねぇ。傾きレイアウトは禁止するか?しかし、画面がオン・オフになっても onDestroy と onCreate が呼ばれるのかもしれん。ここら辺は、もうちょい調べないとわからない。
最悪、スクリーンロックして、ディスプレイを暗くする?

2011年2月12日土曜日

坊ちゃんスキーそして筋肉痛

 またまた、坊ちゃん連れてスキーに行ってきました。今度は、オーンズに行こうと思ってたのに、ハイランド行きのバスが来たら、坊ちゃん、いきなり「僕、ハイランドに行きたい」の爆弾発言…。ええーっ?今度はリフト4時間券を買って滑るのに4千円ちょいと踏んでいたのに・・・ハイランドだと、確か家族パックでベースが5千円・・・と頭で計算して、結局ハイランドへ。
家族パックに500円の割引を付けてもらって、さぽーと札幌の割引券2枚プラスして3900円になりました。これは有難い。山頂に行って、また林道を降りましたが、雪が積もった後だったので、スキーをとられて、やられ気味の坊ちゃん…。1本滑っただけで、もう寒いと言いだす始末。とほほ
休憩を入れて「フライドポテト&フランクフルト」500円なりを食べて、パラダイスを上がって、オリンピアへと滑る。今度は、オリンピアの「なんちゃってクロス」を滑らせたら、結構気に入ったようだ。しかし、2回ほど滑ったら、またまた体が冷えたと言っては休憩。とほほ
とりあえず、チェリトスが食べたいというので、「なんちゃってクロス」3回で手をうった。で、なんちゃってクロスの最後にジャンプ台があって、調子こいて飛んでたら、派手に転んで、鞭打ち筋肉痛です。現在、湿布中。坊ちゃんは、コケルものの、そこそこ順応して滑ってました…。ま、親父がジャンプして転んでいる姿が、何よりも嬉しかった模様…

雪あかりの路

恒例、雪あかりの路でございます。
今年は、張碓「ちびっこ大将のくに」会場にも行ってきました。例年よりも気温が低く寒かった。



















2011年2月11日金曜日

Android Service and Looper and Handler

 GPS は有限のハードウェアリソースなので、requestLocationUpdates を使わないといけないかと考えていたが、どうも LocationManager.getCurrentLocation(provider) で取得できるようだ。であれば、定期的に自前でポーリングして、ステータス等もチェックすれば、Looper や Handler の問題には遭遇しない。また、こっちの方がコードもシンプルに書ける。

 冷静に考えてみると、Handler の問題が無ければ、わざわざサービス化しなくても、スレッドだけで対処できるはずである。requestLocationUpdates は、フロントエンドなアプリだけに有効な手法なのだと思う。しかし、ガッツリと1日かけてサービス対応にしたので、もう戻れない…。プロトタイプのつもりで書いていたので、リビジョン管理すらしていないです…。ちゃんとリポジトリ用意しとけば良かった orz。

追記:やられた、getCurrentLocation って、SDKから、消滅してんじゃん…。途中でロケーションの取得間隔を変更したいのに、詰んでるじゃん…。ハンドラ使うしかねぇよ。

2011年2月10日木曜日

Android の スレッドは難しい

 どうも、情報が錯綜していて、よくわらん。onDestroy は ANDROID HACKS によると呼ばれない事がある。と書かれているが、isFinishing で強制終了なのか、ユーザによる終了なのかが判断できるという情報もある。であれば、スレッドで十分なのではないか?とも、思ったが、Activity がシングルスレッドで動作しているので、onStop が呼ばれた後は、イベントが処理されないくさい。では、サービスではどうか?というと、メッセージループが存在しないので、そのままでは、やはりイベントが処理されない(というか、スルーされる)。
 で、どうやら、ウィンドウズで言うところのメッセージループに該当するものが、Looper というものらしく、こいつを自前でハンドラを処理できるようにゴリゴリ書いて用意してやって、そのLooperをスレッドに食わせてやるというのが、王道のような気がする。ハンドラの例が、いろいろと見つかるが、どいつも、糞みたいに複雑で訳がわからん。みんな、よくこんなコード書く気になるなーと感心する。Javaプログラマー恐るべし…。
 なんか、デスマーチに突入してきた気がするぞ

2011年2月9日水曜日

Android アプリ開発、最低ラインは突破

 とりあえず、最低ラインの開発はクリアした。しかし、気になる事がいろいろ出てきて、結局、アプリはサービスとして書き換える予定。サービスに関しては、これから調べる。

 気になった点は、以下。

  • アプリから作成したスレッドは、終了処理をちゃんとしないとゾンビとして残る
  • サービスマネージャから登録したリスナの制御をちゃんとしないと、サービス・リソースが残る

 デバッグしていて、アンドロイドのログ出力を見ると、スレッドが2つある事に気がついた。あちゃー、スレッド終了させるの忘れてたよ…。
 これには、事情がある。Android アプリのイベントで、onDestroy 等はメモリ不足時等の対処で呼び出されない可能性がある。かと言って、バックグラウンドになった時も処理を行いたい場合、onPause や onResume のイベントでスレッドを停止するわけにはいかない。つまり、アプリでバックグラウンド・スレッドを使うのは、詰み筋っぽいのだ。どうやって、このスレッドを殺そうか?と思って、アプリをアンインストールしてみたところ、スレッドを殺すことができた。後で、アプリ設定の中から「強制停止」を実行してもアプリに関連するリソースやスレッドを停止できそうな感触を得ている。
 Android 自体は、アプリが作成したスレッド、アプリが有効にしたリソースを把握しているはずである。しかし、APIレベルでは、これらゾンビ化したスレッドやリソースを再取得したり解放したりする機能がわからなかった。もしかしたら、無いのかもしれない。あるにしても、この辺まで踏み込んだ書籍は、そうそうは無さそうである。
 個人的には、名前つきスレッドをアプリが生成できて、後から取得できるようなAPIが欲しいところである。リソースに関しては、所有権を明確にし、所有者が居なくなれば、さっさと破棄してほしいところだ。ここら辺は、相変わらずJavaのウィークポイントではなかろうか?ブラック・ボックス化されている分、ブラック・ボックスがちゃんと実装されていないと、アプリ側では制御ができずに、糞みたいな思いをする。

2011年2月8日火曜日

Android その後

 とりあえず、丸1日半ほどアンドロイドの開発をしたが、Javaは、やっぱりコテコテでしんどい。Javaを好む人は、屍を乗り越えてガンガンとコーディングする無骨な体力と、斜に構えてとっつきにくい感じを合わせもったような、そんなイメージがあります(私の偏見です…)。1週間を目標にしてみたけど、なんだかんだと書く事が多くて、ちょっと届かなそうです。
 どの変が面倒かというと、関数で切り出す度に、いちいち関数に throws ほにゃららと呪文を唱えなければならなかったり、定数を定義するのに、いちいちファイルを切り出して、Interface を起こしたり、ちょっとした構造体もいちいちファイルに切り出してクラス宣言しなきゃならんかったり、あああああああああああああ、もうえぇっちゅうううねーーーーーーん。そして、何より、書きながらリファクタリングしにくいちゅうたら、あらしません。もう、ほんまコテコテです。安全という名の緊縛です。
 いやー、しかし、まじめにJava書くのは久しぶりで、新鮮ですわ。

そして今週も坊ちゃんスキーだったのだ

 日曜日は、また、坊ちゃんスキーでした。今回は、キロロ・スキー場に行ってきました。車が無いので、小樽まで汽車に乗り、小樽からはバスに乗ってキロロへ。バスは外人ばっかり乗っていて、最初、坊ちゃんは、ちょっとビビッてました。
 キロロでは、長嶺からセンターを2回滑って休憩し、もう一度長嶺からセンターを滑りました。上手に滑るので、調子に乗ってゴンドラへと坊ちゃんを拉致して頂上へ。ただし、風が強くゴンドラは低速運転しており、頂上は、おそらく氷点下10度以下…。坊ちゃんには厳しい環境だったようで、ガタガタと震えてハイポサミア気味。ほとんど、坊ちゃんを抱えながら滑りました。
 これは、ちょっと可愛そうな事をしたと反省して、冷えた体を温めるべく醤油ラーメンを二人で食べました。

2011年2月5日土曜日

Android とガラパゴス

 Android IS03 を弄ってみて、感想を・・・。iPhone,iPod touch は持っていないので、iPad との比較になってしまうため、若干不公平な感じもします。そこは、差し引いて読んでください。
 良くも悪くも、Android は自由です。しかし、どことなく違和感を覚えてしまいます。そう、ごっちゃりしていて、わかりずらいのです。例えるならば、頭の悪い人達が大勢で寄ってたかってテンコ盛りにした感じです。操作がしづらい。そしてIS03には脈々とガラパゴスの血が受け継がれています。機能が欲しけりゃ自分で入れるっちゅうねん。メーカー製のパソコンを買うと(俺はエプソンの80286以外は買った事ないけど)、目障りなソフトがインストールされている。そんな感じです。大抵は、こいつらをアンインストールするのに一苦労します。
 Mac(パソコンは除く)が提供しているものは、ツールをあなた色に染めてね!であり、最初からバンドルされているものは最小限のものです。それに比べると、IS03は、AU色にコッテリと塗りまくられていて嫌な気分になります。
 Android における操作は、あまり直感的ではありません。

2011年2月3日木曜日

アンドロイドする事になった

 とりあえず、急遽 Android のアプリをこさえる事になった。というわけで、IS03 をゲット・・・会社のだけど・・・。
期間が無いので、3週間以内にアプリを書き上げないといけない。目標は1週間。
 そんなこんなで、Ubuntu で開発環境を揃えようとおもったら、x86 の eclipse に x64 のライブラリが紛れていて動かない。しょうがないから、ウィンドウズで開発する事にした。久々の Java だぜぇ。プロジェクト稼働率70%が目標。余計な仕事が舞い込まない事を祈るばかり・・・。

 関係ないけど、仕事で、FreeType2 を弄っていて、文字フォントのビットマップの左オフセットに -1 の値が入る事があって、やられた。これは、ちょっと反則技じゃねぇの?と思ったが、仕様的には、あり得る。しかし、全く想定していなかった。だって、テキストエディタで、左端に特定の文字を書いたらエリア外にフォントがはみ出すって寸法だ。gcc で、-fshort-wchar オプションでコンパイルした場合 wcout がまともに動作しないっぽいので、何の文字が -1 オフセットなのかまでは確認していない。