2013/03/30

Visual Studio 2012 で TypeScript 開発環境を構築

先日、「Visual Studio 2012 で jQuery 開発環境を構築」というエントリを書いたのですが、このタイミングで Visual Studio 使い始めるなら TypeScript を使うのも手かと思い、TypeScript の開発環境も作ってみました。
使ってみると、TypeScript なかなか良い感じです。
2013/03/21

Android端末 を Ubuntu 12.04 にメディアデバイスとして接続する

昨日、Nexus7 を Ubuntu にメディアデバイスとして接続する というエントリを書いたのですが、このご時世に、いちいち手動でマウントポイントを用意するのも何だなぁと思い、gvfs でマウントできないものか調べてみることに。
すると、結構あっさり以下のサイトにたどり着きました。
なぜ昨日たどり着かなかった、俺…

ふむふむ。Ubuntu 13.04 では gvfs がアップデートされて Android 4.0 の端末MTPアクセスの端末という意味だと思われますにアクセスできるようになったと。
そして、12.04, 12.10 では PPA レポジトリを追加することによって、gvfs をアップデートでき、同じようにアクセス可能になるってことだそうです。

というわけで、早速やって見ました。

まず、以下のコマンドで PPA を追加・更新し、パッケージを更新します。

$ sudo add-apt-repository ppa:langdalepl/gvfs-mtp
$ sudo apt-get update
$ sudo apt-get upgrade

正常に終了したら、再起動。

Nexus 7 を接続すると、Nautilus に自動的に表示されました。
んー、非常に簡単。

2013/03/20

Nexus7 を Ubuntu にメディアデバイスとして接続する

@ Ubuntu 12.04 LTS
2013/3/21 追記
以下の方法で手動マウントするのも良いのですが、gvfs を利用して自動マウントする方が簡単でした。
穀風: Android端末 を Ubuntu 12.04 にメディアデバイスとして接続する

我が家の Ubuntu は Nexus7 を接続しても、うんともすんとも言ってくれません。
これでは少々使い勝手が悪いので、USBメモリのように接続したら自動でマウントして表示されるようにしてみました。
参考にしたのは以下のサイトです以下のサイトでは go-mtpfs を使用していますが、私は標準の mtpfs を使用しました
2013/03/18

OnItemClickListener.onItemClick() の中で isChecked() を呼んではいけない?

穀風: onListItemClick() の中で isChecked() を呼んではいけない? というエントリを書きましたが、同様に OnItemClickListener.onItemClick() の中ではどうなのか、調べてみました。
public class MainActivity extends ListActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        String[] listItems = { "1", "2", "3" };

        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        ListAdapter adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_multiple_choice, listItems);
        setListAdapter(adapter);

        getListView().setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                CheckedTextView cv = (CheckedTextView) view;
                Log.d(TAG, "isChecked " + cv.isChecked());
            }
        });
    }
}

これを、Android 4.0.4 のエミュレータで動作させると以下の通り
// OFF → ON
isChecked false

// ON → OFF
isChecked true

Android 4.2 のエミュレータで動作させると以下の通り
// OFF → ON
isChecked true

// ON → OFF
isChecked false

やはり逆転してしまいました。
先程も書いたとおり、とりあえずの対策は出来ると思いますが、正しい対処方法がわかりません…

onListItemClick() の中で isChecked() を呼んではいけない?

少し前に、知人に頼まれて作った Androidアプリの動作がおかしいとのこと。
どうも、Galaxy Nexus を 4.0.2 → 4.1.1 にアップデートしてからおかしくなったらしい。

調べてみると、ListActivity.onListItemClick() の中で CheckedTextView.isChecked() を呼んだ時の挙動が変化した模様。

というわけで、以下のようなコードを用意して実験してみました。
public class MainActivity extends ListActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        String[] listItems = { "1", "2", "3" };

        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        ListAdapter adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_multiple_choice, listItems);
        setListAdapter(adapter);
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        // ↓ 少なくとも Android 4.2 までは空関数
        // super.onListItemClick(l, v, position, id);
        CheckedTextView cv = (CheckedTextView) v;

        Log.d(TAG, "isChecked " + cv.isChecked());
    }
}

これを、Android 4.0.4 のエミュレータで動作させると以下の通り
// OFF → ON
isChecked false

// ON → OFF
isChecked true

Android 4.2 のエミュレータで動作させると以下の通り
// OFF → ON
isChecked true

// ON → OFF
isChecked false

完全に動作が逆転しています…

そもそも、以前は「チェックしたのに isChecked が false」という直感に反した仕様だったので、正しい動作をするようになったと言えるのかもしれません。

ただ、この変更がどのような意図で行われたのかが不明です。
Android Developersはチェックしたのですが、それらしい記述を見つけることはできませんでした。
バグフィックスなのか、たまたま挙動が変わってしまったのか…
もし、詳しい方がいらっしゃいましたら、コメントやTwitterで是非教えてください。

とりあえずは、以下のように Android のバージョンをチェックして乗り切ることは可能かもしれません。
        CheckedTextView cv = (CheckedTextView) v;

        boolean isChecked = (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) ?
                !cv.isChecked() : cv.isChecked();

ただし、仕様が明確に提示されていない以上、今後もまた変更が入る可能性はあります。
つまり、onListItemClick() の中では isChecked() を呼ばない方が無難だという事になります。

しかし、チェックされた瞬間に動作させたいことってありますよねぇ…

続き: OnItemClickListener.onItemClick() の中で isChecked() を呼んではいけない?
2013/03/17

Visual Studio で Javascript のデバッグ

2013/03/16

Visual Studio 2012 で jQuery 開発環境を構築

Javascript って王道の IDE (統合開発環境)が無いですよね。
ましてや jQuery もサポートしているものとなると微妙です数は結構あるみたいですけど、「とりあえず、これ使っとけ!」みたいなデファクトスタンダードなものが無いという意味です

そんな中、Visual Studio が意外と使えるという話を聞いたので、使って見ることにしました。
結論から言うと、結構良いです。
jQuery用の IntelliSense も使えますし、ステップ実行などのデバッグも可能。
Windows でしか使えないというところが残念ですが。

2013/3/18 追記
「結構良い」と書いたのですが、1点欲しい機能が無いことに気づいてしまいました。
それは、「リファクタリング→名前変更」の機能。
変数名や関数名を一箇所変えると、使用している全ての名前が変わるというものです。
IDE には必須の機能だと思うのですが、Visual Studio Express 2012 の Javascript では使用できないようです。
(C# や C++ ではちゃんと使えます。)
うーん。惜しい。

以下、環境構築と簡単な使用方法です。
2013/03/11

Canon のプリンタドライバ for Linux をインストールしようとしたら "Cannot specify package management system." で失敗した

Canon MP640 のプリンタドライバ for Linux を Ubuntu 12.04 LTS にインストールしようとしたのですが、エラーが出てしまいました。
$ tar zxf cnijfilter-mp640series-3.20-1-i386-deb.tar.gz
$ cd cnijfilter-mp640series-3.20-1-i386-deb
$ sudo ./install.sh
==================================================

Canon Inkjet Printer Driver Ver.3.20-1 for Linux
Copyright CANON INC. 2001-2009
All Rights Reserved.

==================================================
Error! Cannot specify package management system.

install.sh の中でこのエラーを出しているところを探してみると、以下にありました。

install.sh
C_FUNC_get_system()
{
 local c_system_rpm=""
 local c_system_deb=""

 ## Judge is the distribution supporting rpm? ##
 rpm --version 1> /dev/null 2>&1
 c_system_rpm=$?

 ## Judge is the distribution supporting dpkg(debian)? ##
 dpkg --version 1> /dev/null 2>&1
 c_system_deb=$?

 ## rpm and deb are error, or rpm and deb are no error, is error ##
 if [ $c_system_rpm = 0 -a $c_system_deb = 0 ] || [ $c_system_rpm != 0 -a $c_system_deb != 0 ]; then
  echo $C_err_msg1
  return $C_ERR_CODE
 else
  if test $c_system_rpm -eq 0; then
   C_system="rpm"
  else
   C_system="deb"
  fi
 fi
 
 return 0
}

ふむふむ。
rpm と dpkg のうち、一方だけがインストールされていないとだめなのね。
で、以下を実行してみると、
$ rpm --version
RPM version 4.9.1.1
$ dpkg --version
Debian `dpkg' package management program version 1.16.1.2 (amd64).
This is free software; see the GNU General Public License version 2 or
later for copying conditions. There is NO warranty.

両方インストールされてるわ…
記憶にないけど

というわけで、以下のように rpm を削除すると、問題なくインストールできるようになりました。
$ sudo apt-get remove rpm
$ sudo apt-get autoremove
2013/03/06

InstrumentationTestRunner の起動シーケンス図を描いてみた

Android JUnit のテスト実行役である InstrumentationTestRunner の起動シーケンス図を描いてみました。


Application.onCreate()AndroidTestRunner.runTest() は別スレッドで動作しているのです。(赤枠で囲ったとこ)
つまり、「テスト開始時に Application.onCreate() が呼ばれている保証はないよ」ってことですね。

mainスレッド(UIスレッド)を使ってテストを行う場合は問題ありませんが、テスト用のスレッドをそのまま使う場合バックグラウンド処理等は注意が必要です。

2013/03/05

Eclipse の Android JUnit Test は 2回実行される

Android で JUnit Test をしていた時、ちょっと気になる現象を発見してしまいました。
たまたま、android.app.Application を継承した独自実装の Application を使用して、その onCreate() にログを仕込んでいた状態だったので気づいたのです。
以下、その詳細です。

コード

実際のコードをあげるのは大変なので、以下に簡略化したものをあげておきます。

MyApplication.java (Target)
public class MyApplication extends Application {
    private static final String TAG = "MyApplication";

    @Override
    public void onCreate() {
        super.onCreate();

        Log.d(TAG, "onCreate");
    }
}

AndroidManifest.xml (Target)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.kokufu.android.test.sampletarget"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        
        <!-- 省略 -->
        
    </application>

</manifest>


このアプリに対し、以下のようなテストを作成。
(テストとしての役割は全く果たしていませんが…)

MyTest.java (Test)
public class MyTest extends TestCase {
    private static final String TAG = "MyTest";

    public void testA() {
        Log.d(TAG, "testA");
    }

    public void testB() {
        Log.d(TAG, "testB");
    }
}

Application.onCreate() が2度呼ばれている

Eclipse から
Run → Run As → Android JUnit Test
と実行してみると、
以下の様な結果が。
onCreate が2度呼ばれています。
間違えて 2度実行してしまったわけではありません。
たった1度、実行操作を行っただけです。

さらによく見てみると、最初の onCreate だけ PID が異なります。
どうも、別プロセスで 2回実行されているようですが、テスト自体は2回目だけ実行されるようです。