2015年12月30日水曜日

Android Library の生産性の悪さ

年末に小ネタを Android 開発、生産性が悪いですね〜。自分は Java を生産性の低い言語だと考えてるのもあって、イライラもマックスですね。 Androidライブラリにリソースを組み込めないのも、生産性を下げる大きな要因だと思いませんか? DRY の原則を適応できない。 小ネタで、ログイン・ダイアログをライブラリ用として書いてみました。 Activity からは、下のような感じで呼出ます。
  showLoginDialog(this, new OnLoginListener() {
    @override
    public void onLogin(String name, String pass, int which) {
       if( DialogInterface.BUTTON_POSITIVE == which ) {
          if( validPassword(name, pass ) {
          } else {
          }
       } else {
          finish();
       }
    }
  });
import を略してすみませんが、以下の感じです。
  public interface OnLoginListener {
    public void onLogin(String name, String pass, final int which);
  }

  public static AlertDialog.Builder createLoginDialog(final Context context, final OnLoginListener l ) {
    final LinearLayout ll = new LinearLayout(context);
    final EditText userEditView = new EditText(context);
    final EditText passEditView = new EditText(context);
    final TextView tv1 = new TextView(context);
    final TextView tv2 = new TextView(context);
    final DialogInterface.OnClickListener ocl = new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialogInterface, int which) {
        l.onLogin(userEditView.getText().toString(), passEditView.getText().toString(), which);
      }
    };
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT);
    ll.setLayoutParams(params);
    ll.setOrientation(LinearLayout.VERTICAL);
    tv1.setText("USER:");
    userEditView.setInputType(android.text.InputType.TYPE_CLASS_TEXT);
    tv2.setText("PASSWORD:");
    passEditView.setInputType(android.text.InputType.TYPE_CLASS_TEXT);
    ll.addView(tv1);
    ll.addView(userEditView);
    ll.addView(tv2);
    ll.addView(passEditView);
    return new AlertDialog.Builder(context)
            .setIcon(android.R.drawable.ic_dialog_info)
            .setTitle("login")
            .setView(ll)
            .setPositiveButton(android.R.string.ok, ocl)
            .setNegativeButton(android.R.string.cancel, ocl);
  }

  public static void showLoginDialog(final Context context, final OnLoginListener l) {
    createLoginDialog(context,l).show();
  }
  
  

2015年12月15日火曜日

Windows版 PostGIS x64版の shp2pgsql が動かない

PostgreSQL は、x86 版のサーバを使用するよりも x64 版のサーバを使った方が良いんじゃないかなー?と思って、x64版をインストールしたんですわ。

そしたら、shp2pgsql が 0xc000007b とかエラー吐いて動かないとか言われました。
ググってみたら、この問題は、もう、かれこれ3年以上前から放置されています。
しかも回答者の認識も「 libiconv-2 は windows では使われてないから無くても大丈夫あるよ」てな感じで、脱力感が半端ない。
その他、あちこちで、この問題に関して質問されているけども、ほぼ放置プレー。

はいはい、またかよっ。

って、事で libiconv-2.dll の x64 版を、どこかから入手しなくては!
検索したら、dll のダウンロードサイトが軒並み引っかかりますが、この手のサイトから dll をダウンロードする勇気は、私にはありません。マルウェア配布の巣窟なんじゃないか?と思うのが普通の感覚でしょう。

はい、QGIS Lyon x64 版をインストールして

C:\Program Files\QGIS Lyon\apps\grass\grass-6.4.3\bin\libiconv-2.dll



C:\Program Files\PostgreSQL\9.4\bin

にコピーしましょう。


Postgis のメンテナーさんは、grass のメンテナーさんにコンタクトを取って、PostGISのインストーラに libiconv-2.dll をちゃんとバンドルした方が良いです。

2015年12月13日日曜日

MVNOを検討していてわかった事

自分の携帯は、ガラケーです。スマートフォンにすると通信料が高くつくので敬遠していました。 しかし、
  • ガラケーの端末が、強く閉じると電源OFFになってしまい、今にも壊れそう
  • 今時スマートフォンにしないとコミュニケーションにも支障をきたす
  • MVNOというサービスが出てきて通信費が手頃になってきた
というように、移行する条件が揃ってきたので、これを期にフリーSIMの使える端末について調べてみました。

 自分のライフスタイルに合ったスマートフォンというと、京セラのTORQUE G01, G02 あたりになります。ところが、こいつのフリーSIMの入手が厄介です。

 この機種は au から販売されていますが、フリーSIM化するためには、総務省の指針により購入後6ヶ月経過しないとダメです。auと契約しないで端末を購入できれば良いのですが、契約しないで端末を買う事はできません。

 中古の携帯が流通していて、その中で購入後6ヶ月以上経ってフリーSIM化されているものを買えば良い事になりますが、これがまたリスクが高い。フリーSIM化されていても、様々な要因で後から通信ロックを食らってしまう状況がある事がわかってきました。通信ロックを食らう状況は、以下のようなもの
  • 元の持ち主が手放した携帯がオレオレサギに利用され、その持ち主の携帯がブラックリスト扱いにされてしまう。
  • 元の持ち主が料金滞納をしてしまったため、巻き添えで通信制限を食らってしまう。
  • 元の持ち主が紛失したと嘘をついて携帯を売約したため、実はリモートロックがかかって外せない状態のまま
見ればわかるように、中古販売店からフリーSIM化された状態で買っても、いつ巻き添えを食って携帯が使えなくなってしまうか、予測できません。確率は低いにせよ、常に使えなくなる可能性があるわけです。
 こうやって考えて行くと、
  • 最初からフリーSIM化された機種を買う
  • 元の持ち主が判明していて、信頼できる携帯
の2択で行くのがリスクが無くて良いです。
スマートフォン、高いけど、リスクを考えたらフリーSIMの端末を選択するのが良さそうですね!
 Zenfone 2 なんか、コスパが良いなぁと思ってたんですが、日本の家電製品として販売するために取っておかないといけない「技適」マークを取得していないという理由で、MINEO の au プランで使えないんだとか…(使えるけど、使うと違反になる)

いやー、悶々としますね。

2015年10月25日日曜日

grep 拡張子を指定して検索 忘備録

自分用。 拡張子を指定して、今のディレクトリから hoge を再帰的に検索したい場合
$ grep hoge --include = "*.java" -r -n .

2015年10月9日金曜日

eclipseADT から Android Studio への移行

 mac が EL Capitan に変わって Java 6 とかゴッソリ削られて eclipse で build するのが面倒臭くなってきたのをきっかけに、Android 開発環境の移行をしました。 eclipse ADT がサポートを打ち切られるのも年内がリミットですしね。
 自分は、巷に解説されるように プロジェクトとサブプロジェクトでライブラリも構築するという事はやっていませんでした。 複数プロジェクトからライブラリを参照しているからで、基本 jar ファイルを参照する方式をとっていました。
|-- Application
|   |- Foo
|   |- Bar
|
|-- Libraries
|   |-- Hoge
|   |-- Fuga
|
|-- Ref
      |-- Java
      |      hoge.jar
      |      fuga.jar
      |
      |-- Key
             debug.keystore
             release.keystore
eclipse ADT は、こんな感じですわ。
それを
   |- Foo
   |- Bar
   |-- Hoge
   |-- Fuga
   |-- Ref
      |-- Java
      |      hoge.jar
      |      fuga.jar
      |
      |-- Key
             debug.keystore
             release.keystore
という構成に Android Studio では、しました。
まずは、ライブラリの移行です。
Android Studio から、 import project (eclipse ADT, gradle, etc) を選択しライブラリを変換します。
依存関係の構築を行うために
Hoge/app/build.gradle
ファイルを編集します。
apply plugin: 'com.android.application'

android {
    compileSdkVersion 13
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "jp.co.company.Hoge"
        minSdkVersion 13
        targetSdkVersion 13
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

// ここに依存関係で使用しているライブラリを指定します。
dependencies {
    compile files('../../Ref/Java/helper.jar')
    compile files('../../Ref/Java/calc.jar')
    compile files('../../Ref/Java/sqlcipher.jar')
}

// 古い jar ファイルが存在した場合は削除するタスク
task cleanDebugJar {
    def classes = new File('build/intermediates/bundles/debug/classes.jar')
    if( classes.exists() ) {
        delete '../../Ref/Java/hoge.jar'
    }
}

// debug でビルドした時は Hoge/app/build/intermediates/bundles/debug/classes.jar が
// 生成されるようになっているので、それを共通のディレクトリにコピーするタスク
task generateDebugJar(type: Copy, dependsOn: [cleanDebugJar,assembleDebug] ) {
    from 'build/intermediates/bundles/debug/'
    into '../../Ref/Java/'
    include('classes.jar')
    rename('classes.jar', 'hoge.jar')
}

/*
// debug でビルドされる jar ファイルは、そのまま流用できる。
// release で自前で作成しても debug で作成されるものと同じなので
// コメントアウトしている=必要ない。
// 将来的にデバッグ情報が付加された jar が生成されるとか
// 状況が変われば、この辺のコードは有用かもしれない。

// release でビルドした時は、jar ファイルが生成されない。
// よって、自前で jar ファイルを生成するためのタスク
task makeReleaseJar(type: Jar, dependsOn: assembleRelease) {
    from fileTree(dir: 'build/intermediates/classes/release')
    from fileTree(dir: 'src/main/resources/')
    into 'build/intermediates/bundles/release/classes.jar'
}

// 古い jar ファイルが存在した場合は削除するタスク
task cleanReleaseJar {
    def classes = new File('build/intermediates/bundles/release/classes.jar')
    if( classes.exists() ) {
        delete '../../Ref/Java/release/hoge.jar'
    }
}

// jarファイルを共通のディレクトリにコピーするタスク
task generateReleaseJar(type: Copy, dependsOn: [makeReleaseJar, cleanReleaseJar, assembleRelease]) {
    from 'build/intermediates/bundles/release/'
    into '../../Ref/Java/release/'
    include('classes.jar')
    rename('classes.jar', 'hoge.jar')
}
*/

// 間抜けな事に Android Studio のビルドから Java class ファイルを
// コンパイル生成した後に task を実行する手段が見つけられない。
// (Build -> Clean Project, Build -> Rebuild Project)
// これは、ビルド・プロセスにおけるクリーンナップが行われる前に、前回生成した
// *.class ファイルを jar 化したものに対して、コピー操作を行うという方法
// 2回ビルドしないと最新の jar にならない。
// IDEからビルドしただけでは動作しないので、皆ターミナルから、
// task を指定する形で実行している。
//assembleDebug.dependsOn(generateDebugJar)
//assembleRelease.dependsOn(generateReleaseJar)
コメントに書いてあるように、ターミナル・ウィンドウから
./gradlew generateDebugJar
を実行します。

2015年8月7日金曜日

MediaScannerService ファッキュー

  Android プログラミング、難しいですね。地雷の山。

Android のアプリケーションから、ファイルストレージにディレクトリを作成したり、ファイルを作成したりしても、PCからUSBで接続するとファイルが見えません。
これは、Android の ファイルシステムとは別に、MTP 接続でのファイル問い合わせが別管理になっているからなんです。
だから、Android のアプリケーションからファイル操作をファイルストレージに対して行ったら、いちいち MediaScannerService 様にお伺いを立てて登録をお願いする必要があります。
ところが、この MediaScannerService 様、登録をお願いしたものは、ディレクトリも含めて、全部「ファイル」として処理をして下さいます。
途中に登録されていない「ディレクトリ」が存在すれば、ついでに、それは「ディレクトリ」として登録してくださる親切仕様。
あ、存在しないファイルに関しては、いちいち通知しなくても、よしなに計らってくださいます。だから、ファイルやディレクトリの削除を通知してはいけません。

昔は、MEDIA_MOUNTED というのを通知してたんですが、今は、こうするのがベストなんじゃないでしょうか?
  public static void makeFileDiscoverable(File file, Context context){
    if( file.isDirectory() )  return;
    if( !file.exists() )  return;
    MediaScannerConnection.scanFile(context, new String[] { file.getAbsolutePath() }, null, null);
  }

ぼけーヽ(`Д´)ノウワァァァン!!

2016/2/2 追記:どうも、この static void MediaScannerConnection.scanFile を使用すると、LogCat に ConnectionのLeakが報告されるようです。
 Java エコシステムにおいて、Leak って言われてもね〜。
Intent を使って通知する方が良いかもしれません。
参考: MediaScanner ServiceConnectionLeaked
参考2:MediaScannerに登録を依頼する方法
  Uri contentUri = Uri.fromFile(newFile);
  Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, contentUri);
  context.sendBroadcast(mediaScanIntent);

2015年7月22日水曜日

iPadのBackupをTimeCapsuleへ備忘録

参考 http://osxdaily.com/2011/03/05/how-to-move-the-iphoneipad-itunes-backup-folder-to-an-external-hard-drive/

バックアップ先は
~/Library/Application Support/MobileSync/

なんで
ln -sf /Volumes/Data/Rev/okimiyuki/Backup/ ~/Library/Application\ Support/MobileSync/Backup

というように、シンボリック・リンクにしてしまう。
尚、TimeCapsule を Data という形でマウントしている。

ところで、TimeCapsule のマウントは自動で行われるが、毎回、必ず Data にマウントされるわけではなく、Data-6 だったりと面倒くさい。なんとかならんものか?

2015年6月29日月曜日

QGISの作るshapefileのdbf

しばしば ISO-8859-1 というコードページに解釈されるケースが多いので、そのようなファイルがどうなっているのか調べてました。

DBFファイルの先頭から 29バイト目 の0x0057 とかで入っていて、87=ISO-8859-1となってます。
日本語版のArcGISで、これを読むと、ちゃんとSJISとして解釈してくれる。もうたまりませんわ。
 ISO-8859-1が多数派なんで、自然な流れかと。

ちゃんとしてくれないツールが多くて閉口します。

2015年6月11日木曜日

UTime デザイン

ユニクロのTシャツをデザインしました
もし気に入ったら、こちらからどうぞ







2015年5月8日金曜日

キーボード入力雑感

 プログラミングするには、やっぱり英語キーボードの方が {} [] \ ¥ が打ちやすい。 なんだけども、職業上、雑多な環境でキーボードを打たなくてはいけないので、結局、もう日本語キーボードで良いです。ってなってしまいました。 ローカルBBS時代には、自分は、T-Code 使いでした。 なんでも統計的にタイプ数の多い文字をうまく組み合わせて、2ストロークで自然と左右で打鍵できるように配置された手に負担の少ない配列というのに惹かれました。 けれども、全部を覚えきる事なく、MS-DOS から WINDOWS へと時代が変わりIME自体がしばらくサポートされないまま、廃れていきました。 友人は、「風」を使っていました。今にして思えば、日本語を1ストロークのカナ入力で行うので、断然タイプも速く、自分も、こちらを覚えれば良かったかなと…。 今は、だらだらとローマ字入力を使ってます。 これを機に、風とか探してみようかな・・・

2015年4月6日月曜日

postgis: 関数 ST_AsGeoJSON はユニークではありません 備忘録

function ST_AsGeoJSON is not unique 関数 ST_AsGeoJSON がユニークではありません。 こんなエラーが出た場合。 バージョンアップしてる環境に、古いDB をリストアすると、PostGIS の残骸が追加されるので、削除が必要
DROP FUNCTION IF EXISTS ST_AsGeoJson(geometry); -- this one changed to use default args 
DROP FUNCTION IF EXISTS ST_AsGeoJson(geography); -- this one changed to use default args 
DROP FUNCTION IF EXISTS ST_AsGeoJson(geometry,int4); -- this one changed to use default args 
DROP FUNCTION IF EXISTS ST_AsGeoJson(geography,int4); -- this one changed to use default args 
DROP FUNCTION IF EXISTS ST_AsGeoJson(int4,geometry); -- this one changed to use default args
DROP FUNCTION IF EXISTS ST_AsGeoJson(int4,geography); -- this one changed to use default args
DROP FUNCTION IF EXISTS ST_AsGeoJson(int4,geometry,int4); -- this one changed to use default args
DROP FUNCTION IF EXISTS ST_AsGeoJson(int4,geography,int4); -- this one changed to use default args
http://stackoverflow.com/questions/24204589/error-using-st-asgeojson-with-postgis

2015年2月4日水曜日

QGis Plugin builder エラー備忘録

QGis Plugin Builder を使ってプラグインを作成すると、途中から
Traceback (most recent call last):
  File "C:/PROGRA~2/QGISBR~1/apps/qgis/./python\qgis\utils.py", line 208, in startPlugin
    plugins[packageName] = package.classFactory(iface)
  File "C:/Users/oki.HNS/.qgis2/python/plugins\Bar\__init__.py", line 34, in classFactory
    from .Foo import Bar
  File "C:/PROGRA~2/QGISBR~1/apps/qgis/./python\qgis\utils.py", line 460, in _import
    mod = _builtin_import(name, globals, locals, fromlist, level)
  File "C:/Users/oki.HNS/.qgis2/python/plugins\Bar\Foo.py", line 26, in 
    import resources_rc
  File "C:/PROGRA~2/QGISBR~1/apps/qgis/./python\qgis\utils.py", line 460, in _import
    mod = _builtin_import(name, globals, locals, fromlist, level)
ImportError: No module named resources_rc
なるエラーに遭遇
c:\work\any>"c:\Program Files (x86)\QGIS Brighton\bin\pyrcc4.exe" resources.qrc -o resources_rc.py
として、リソースのコンパイルを行う事。

2015年1月9日金曜日

アウトプットしてみるテスト

しばらくアウトプットしてなかったので、アウトプットしてみるテスト。 すっかりクラウドも定着した感があります。 この先重要な事は何か?改めて考えるに、やはりデータありきなのではないかと思います。 例えば、モバイルマシンの性能の制約で、取得できるタッチセンサー値を間引きして記録してるとすると、それは勿体無い事だなぁなんて・・・ 間引いてなければ、マシンの性能が上がった時に再現されるデータは違ったものになっている可能性を捨てている事になります。 分析でも、達人のタッチセンサー値と、凡人のタッチセンサー値には、決定的な違いが見つかり、達人のタッチセンサー値を元に凡人のタッチセンサー値を改良して、素晴らしいユーザ体験を与える事ができるかもしれません。 要は、データ重要。 何を書いてるのか、自分でもわかりません。 アウトプットしてみるテストなので・・・