MapActivityがない?

しばらくAndroidから離れている間にAndroidStudioがどんどんバージョンアップを繰り返していってるみたいなので、EclipseからAndroidStudioに乗り換えることにした。

GoogleMapを使ったアプリでも作ってみるかと、
MapActivityを継承しようとしたんだけど・・・・MapActivityが見つからない。

調べてみると、MapActivityはGoogleMapAPIv1のAPIで、v2ではMapFragmentを使うんだとか。

http://stackoverflow.com/questions/22340762/mapactivity-could-not-be-found-android-studio-0-5-1

知らんかった・・・・。

Galleryから取得した画像のExifメタタグが読み込めない

IntentでGalleryを呼び出して、選択した画像のメタタグを読み込み、GPS情報等の情報を取得するプログラムを作ってみた。
メタタグの読み込みはExifInterfaceクラスを用いる。
インスタンス生成にはJPEGファイルのディレクトリが必要なので、
Galleryから取得したURIをContentResolverでディレクトリ文字列に変換したものを設定することにした。

Galleryからのコールバックメソッドの部分を以下に示す。

public void onActivityResult(int requestCode, int responseCode, Intent data) {
    if (requestCode == REQUEST_GALLERY && responseCode == RESULT_OK) {
        // URIを取得
        Uri uri = data.getData();
        // ContentResolverを用いてURIが示す画像ファイルの情報を取得
        Cursor c = getContentResolver().query(uri, new String[]{MediaStore.Images.Media.DATA}, null, null, null);
        String filePath = null;
        if (c.moveToFirst()) {
            int index = c.getColumnIndex(MediaStore.Images.Media.DATA);
            // 画像ファイルのディレクトリを取得
            filePath = c.getString(index);
        }
        try {
            // ExifInterfaceインスタンスを生成
            ExifInterface exif = new ExifInterface(filePath);
            // TODO タグ情報を取得
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

GalaxyS4(4.2)では取得できるのだが、Nexus7(4.4.2)では以下のようなエラーが発生する。

03-12 22:34:01.571 21283-21283/net.atlabo.sample.exif E/JHEAD﹕ can't open '/storage/emulated/0/Download/20140309_172716.jpg’

調べてみたら、こんなことが書いてあった。
http://stackoverflow.com/questions/21857327/exifinterface-jhead-cant-open-error-android

どうやらAndroidManifest.xmlにSDカード書き込み権限を付与してやらないといけないらしい。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

機種依存なのかAndroidAPIなのかは調べてないが、これで解決。

家族でグリーンランド遊園地に行ってきた 〜フリーパス?回数券?〜

グリーンランドで遊びまくってきたので、このブログの趣向とは異なるが、メモ書きついでに書いておく。

3/9(日) 晴れ
風が少し強く肌寒かったが、天候もよくまずまずの日だった。

家族で行ったので、自分と妻、娘(7歳)、息子(5歳)の4人。

フリーパスを購入した方がお得なのか、それとも回数券を購入した方がお得なのか、検証してみた。

・人が多く、待ち時間が長ければ、アトラクションにあまり乗れない?
・子どもたちもいるし、回数券が多く必要な絶叫系のアトラクションは乗らない?

こんな考えから、回数券の方がお得なのかなというのが、行く前の考えだった。
でも、せっかく楽しみに来たのに、回数券の残量を気にしながら遊ぶのもなぁ・・・・と思い、結局フリーパスにした。

経路や所要時間等前日に下調べをしておき、計画通りに開園の9:30に入場、閉園の17:30に退場した。

入園料+フリーパスの料金は以下のとおり。

おとな(高校生以上) 5,400円
こども(3歳以上中学生以下で120cm以上) 4,400円
こども(3歳以上中学生以下で120cm未満) 3,300円
シニア(65歳以上) 3,300円

うちはおとな2名、こども(120cm未満)2名で、計17,400円

ちなみに、入園料だけだと以下のとおりとなる。

おとな(高校生以上) 1,600円
こども(3歳以上中学生以下で120cm以上) 800円
こども(3歳以上中学生以下で120cm未満) 800円
シニア(65歳以上) 800円

3月1日〜6月1日までは春催事料金となり、入園料がおとな200円、それ以外が100円高いようだ。

入園料のみだと我が家の場合、4,800円
この他に回数券を購入してアトラクションを楽しむことができる。
回数券は30枚綴りで1枚あたり100円、1枚単位だと110円となる。

フリーパス込みと入園料の差額は12,600円となるため、1枚100円換算で126枚分以上使用すれば元が取れることになる。

さて、時間内に実際に乗ったアトラクションはというと・・・・・。

アトラクション 回数 1回に必要な回数券 金額
サラマンダー伝説 4回 5枚 2,000円
スカイシップ 4回 2枚 800円
ドラゴンリバー 3回 7枚 2,100円
GTゴーカート2人乗り 2回 4枚 800円
スカイリフト 4回 3枚 1,200円
魔女のフライングトリック 4回 4枚 1,600円
スーパースライダー 4回 3枚 1,200円
バンパーボート(2人乗り) 2回 5枚 1,000円
スフィンクスコースター 8回 3枚 2,400円
スプラッシュ 2回 4枚 800円
ミニバイキング 3回 2枚 600円
デンジャーメイズ 4回 3枚 1,200円
ロードトレイン 4回 3枚 1,200円
てんとう虫コースター 16回 3枚 4,800円
グランパスジェット 6回 5枚 3,000円
メリーゴーランドランデブー 4回 3枚 1,200円
カイジェット 4回 3枚 1,200円
マーメイドパラダイス 4回 3枚 1,200円
ブラックホールコースター 14回 6枚 8,400円
アンパンマンハッピースカイ 3回 3枚 900円
働く車ドリフトレーシング 8回 3枚 2,400円
フリースタイル 4回 3枚 1,200円
メキシカンハット 4回 3枚 1,200円
ウォーターショット 3回 3枚 900円
ティーカップ 2回 2枚 400円
急流すべり パニックジャングル 10回 5枚 5,000円
インディカート2人乗り 2回 4枚 800円
ウエスタン列車 4回 2枚 800円
大観覧車レインボー 4回 6枚 2,400円
飛ぶゾウくん 2回 2枚 400円
ルクソールマジック 4回 5枚 2,000円
リフト 4回 2枚 800円

※回数は1人1回で1カウント。4人で1回乗れば4回とカウント。

回数券1枚あたり100円換算で、金額にして55,900円分の回数券を使ったことになる。
身長制限もある中で絶叫系のアトラクションにはほとんど乗っていないけど、
寒かったからなのか、人の入りがそんなに多くなく、
どのアトラクションもそんなに待つこともなく乗れたので、かなり得した気分。

待ったと言えば、昼下がりのブラックホールコースターで20分くらい待ったけど、
それくらいのもんで、ここも夕方行ってみたらガラガラだった。

今回乗った中で満足したアトラクションは

1位 ブラックホールコースター 5歳から乗れるジェットコースターということで家族全員楽しめた
2位 急流すべり パニックジャングル 上記と同じで、年齢・身長制限なく4人乗りボートに乗れた
3位 グランパスジェット 110cmから乗れるジェットコースターで、7歳の娘が大興奮。

逆に残念だったのは

1位 サラマンダー伝説 電子銃で的を撃つというアトラクションだったけど、当たらないし地味
2位 ルクソールマジック 1回行ったらもういいかな
3位 デンジャーメイズ ここも1回行ったらもういいかな

開園から閉園まで遊ぶ場合はフリーパスが圧倒的にお得なことがわかった。
近所で年間2回以上行くなら年間フリーパスなんだろうけど・・・・。

CodeIgniterで入力チェックを実装する

CodeIgniterには入力チェックを行うAPIが組み込まれている。

入力チェックのためのライブラリの読み込みを行い・・・・

$this->load->library('form_validation');


入力チェックルールを設定する。

$this->form_validation->set_rules('userId', 'ユーザID', 'required')

setRuleメソッドは3つの引数が必要になる。

第1引数・・・リクエストパラメータ名
第2引数・・・エラーメッセージに埋め込む文字列
第3引数・・・入力チェック

第3引数に入る文字列は以下を参照。
http://codeigniter.jp/user_guide_ja/libraries/form_validation.html#tutorial

1つのパラメータに複数の入力チェックを設定したい場合は、パイプ(|)を用いてチェック文字列を連結する。

ルールの設定を行った後は、

$this->form_validation->run()

で入力チェックを実施できる。
入力チェック結果はBooleanの結果を返却する。
TRUEの場合は検証結果OK、FALSEの場合は検証結果NGを表す。

date(): It is not safe to rely on the system's timezone settings.

PHPでタイトルのような大量のログが出力されていた。
なんじゃらほいということで、調べてみたところ・・・・。

タイムゾーンの設定をしていないせいで出力されているよう。
php.iniを設定することで回避できるらしい。

date.timezoneという項目があるので、コメントの「;」を外してから、

data.timezone = "Asia/Tokyo"

と設定することでエラーが出なくなった。

日本以外に住んでる方は、適宜設定変えてくださいね。

CodeIgniterでログ出力

ログ出力するためには、application/config/config.phpの以下の部分を設定する必要がある。

$config['log_threshold'] = 0;

コメントが書いてあって、説明を見ると以下のようになっている。

0 = Disables logging, Error logging TURNED OFF
1 = Error Messages (including PHP errors)
2 = Debug Messages
3 = Informational Messages
4 = All Messages

0がログ出力無効で、徐々に範囲が広がっていき、4を設定すると全てのメッセージを出力するようだ。

注意すべきは2と3。
2を設定すると、ERRORとDEBUGレベルのメッセージを、
3を設定すると、ERROR、DEBUGに加え、INFOレベルのメッセージを出力することになる。

ん?何か逆じゃない??

ちなみに、ログは以下のようにすることで出力することが可能

log_message(‘debug’, “Hello World”);

第一引数にはログレベルを設定する。
レベルはdebug,info,errorのいずれか。

ログのデフォルトの出力先は、application/logsとなる。
ディレクトリのアクセス権として書き込み権限を付与しておく必要がある。

Androidのtoast(トースト)みたいなやつをブラウザ上で実現するためのライブラリ

ブラウザ上でtoastを実現するJavaScriptライブラリを探してみた。

toastr
https://github.com/CodeSeven/toastr

こんなのを見つけた。
簡単そう。

追加ボタンを押したら・・・
f:id:ats337:20140228001845p:plain

こんなモーダルダイアログを用意して、必要事項を入力後・・・
f:id:ats337:20140228001707p:plain

登録ボタンを押すと、「ユーザを登録しました」みたいなメッセージのtoastを表示する。
f:id:ats337:20140228002112p:plain

そんなコードを書いてみた。

ユーザのテーブルとモーダルダイアログのHTMLコードは以下の通り。
追加ボタンを押すことでUserControllerクラスのopenModal()が呼び出され、モーダルダイアログが開かれる。
モーダルダイアログはテンプレートとして用意してある。

<div class="container" ng-controller="UserController">
    <div class="row">
        <div class="col-lg-12 text-right">
            <button type="button" class="btn btn-default" ng-click="openModal()">
                <span class="glyphicon glyphicon-plus">追加
            </button>
        </div>
    </div>
    <br/>
    <div class="row">
        <table class="table table-striped" ng-init="getUserList()">
            <tr>
                <th>ID</th>
                <th>名前</th>
                <th>メールアドレス</th>
                <th>&nbsp;</th>
            </tr>
            <tr ng-repeat="user in userList">
                <td>{{user.user.id}}</td>
                <td>{{user.user.name}}</td>
                <td>{{user.user.mailAddress}}</td>
                <td>
                    <button type="button" class="btn btn-default">
                        <span class="glyphicon glyphicon-pencil">編集
                    </button>
                    <button type="button" class="btn btn-default">
                        <span class="glyphicon glyphicon-trash">削除
                    </button>
                </td>
            </tr>
        </table>
    </div>
</div>
<script type="text/ng-template" id="useraddModal.html">
    <div class="modal-header">
    <button type="button" class="close" ng-click="closeModal()" aria-hidden="true">&times;</button>
    <h4 class="modal-title" id="modalLabel">ユーザ追加</h4>
    </div>
    <div class="modal-body">
    <form role="form" class="form-horizontal">
    <div class="form-group">
    <label for="userId" class="col-sm-4 control-label">ユーザID</label>
    <div class="col-sm-6">
    <input type="text" id="userId" ng-model="userId" class="form-control" placeholder="ユーザID"/>
    </div>
    </div>
    <div class="form-group">
    <label for="userName" class="col-sm-4 control-label">ユーザ名</label>
    <div class="col-sm-6">
    <input type="text" id="userName" ng-model="userName" class="form-control" placeholder="ユーザ名"/>
    </div>                    
    </div>
    <div class="form-group">
    <label for="mailAddress" class="col-sm-4 control-label">メールアドレス</label>
    <div class="col-sm-6">
    <input type="text" id="mailAddress" ng-model="mailAddress" class="form-control" placeholder="メールアドレス"/>
    </div>
    </div>
    <div class="form-group">
    <label for="password" class="col-sm-4 control-label">パスワード</label>
    <div class="col-sm-6">
    <input type="password" id="password" ng-model="password" class="form-control" placeholder="パスワード"/>
    </div>
    </div>
    <div class="form-group">
    <label for="passwordConfirm" class="col-sm-4 control-label">パスワード(確認)</label>
    <div class="col-sm-6">
    <input type="password" id="passwordConfirm" ng-model="passwordConfirm" class="form-control" placeholder="パスワード(確認)"/>
    </div>
    </div>
    <div class="form-group">
    <div class="col-sm-offset-2 col-sm-8 text-right">
    <button type="submit" class="btn btn-default" id="useradd_add_button" ng-click="addUser()">登録</button>
    </div>
    </div>
    </form>
</script>

次にUserController.js
openModal()ではモーダルダイアログを開く処理を記述している。
この時、UseraddControllerをバインドするようにしている。

var UserController =
        function ($scope, $resource, $modal) {
            $scope.userList = null;


            $scope.getUserList = function() {
                $resource("http://localhost/ProjectsWeb/contents/samplejson/userlist.json").get(
                        function(data) {
                            $scope.userList = data.userList;
                            console.log($scope.userList);
                        });
            };

            $scope.openModal = function() {
                var modalInstance = $modal.open({
                    templateUrl: 'useraddModal.html',
                    controller: UseraddController
                });

                modalInstance.result.then(function() {

                }, function() {

                });
            }
        }


最後にUseraddController.js
モーダルダイアログの登録ボタンが押されたら、addUserが呼び出される。

toastr.success('ユーザを追加しました');
の部分でtoastを表示している。

var UseraddController =
    function ($scope, $modalInstance) {
        /*
         * モーダルを閉じる
         */
        $scope.closeModal = function(ret) {
            $modalInstance.close(ret);
        }
        
        /**
         * ユーザを追加する
         * @returns {undefined}
         */
        $scope.addUser = function() {
            var userId = $scope.userId;
            var userName = $scope.userName;
            var mailAddress = $scope.mailAddress;
            var password = $scope.password;
            var passwordConfirm = $scope.passwordConfirm;
            
            // TODO 入力チェック
            
            // TODO ユーザ追加
            
            $scope.closeModal(true);
            
            toastr.success('ユーザを追加しました');
        }
    }

詳しくは下記を参照すれば、表示を変更する方法が書いてある。
https://github.com/CodeSeven/toastr