安価な子供の位置情報確認方法

昨年から子供が習い事を始めたのでスマホを使った位置情報の共有方法を模索してきました。最善策は、iOS にデフォルトで組み込まれている「友達を探す」アプリの利用(実際夫婦間ではこれ)なのですが iPhone 端末が高価なので、開発時に検証用に使っている「Huawei SIMフリースマートフォン P8 lite」に、月間通信量500MB未満は無料の「0 SIM」を挿して渡すことにしました。そしてこの頃、Google の位置情報共有サービスは Google+ を使った複雑な設置が必要だったので Glympse をインストールしました。

iPhone と比較して Android 端末は GPS の性能が貧相な(位置情報ゲームではこのブレを悪用する場合もあるとかないとか…)ので、少しでも改善すべく GPS Locker をインストールしました。

また10秒以上電源ボタンを押すと強制再起動するというハードウェアのユーザインタフェースの難癖があり鞄の中での置き方を教えるという事もありました。さらに Glympse は最大で4時間までしか共有の設定ができず、Gps Tracker を使った自作システムなどを試しましたが、端末のスリープ時に位置情報を更新できない Android 特有の問題を解決できず悶々としていたところ、遂に Google マップがサービスに対応したので移行しました。

子供用の Google アカウントを取得し Google マップの共有設定は問題なく Wi-Fi 環境下で検証できましたが、端末の「設定>データ通信量の管理>ネットワーク通信を行うアプリ>システムアプリ」の設定はどれを選ぶべきか説明がなく一つずつチェックを入れて試してみたところ、次の3つを有効にする必要がありました。

  • マップ
  • Google Backup Transport
  • Android OS

Google マップアプリは常時起動しておく必要がなく、位置情報共有も停止にチェックを入れるまで事実上恒久的に設定しておく(急に遊びに行く場合に手渡すだけ)ことができ、ブラウザ上のマップでも問題なく位置情報が確認が可能です。一つ問題が残るのは、友達を探すアプリのような出発/到着の通知機能がないので FB Messenger アプリをインストールしました。前述のように GPS の性能上、ごく稀に1Km以上ブレたりすることがあるので、その場合メッセージを送って確認するようにしています。

最後に気になるデータ通信量について、設定>Googleから全てのデータの自動同期をオフに設定し、1日3時間ほどの利用で(メッセ通信などが)多い時でも10MB程度で、もちろん毎月の運用費は掛かりません。

以上、携帯端末を公共の場所で利用する場合のルールとマナーについて子供に教える良い機会にもなっている、お勧めの利用方法の紹介でした。お年寄りにも是非どうぞ。

P.S. バッテリ容量を考慮すると今から端末を用意する場合、アマゾンでベストセラー1位の P9 lite が良いかと思います。

参考:

WebViewのフォーム入力でImmersiveモードを維持する

前回、Javascript の alertconfirm 関数を使って WebView から AlertDialog を呼び出した際に全画面表示を止めてしまう問題について取り組んでいた時に、入力フィールドへフォーカスした際に Immersive モードが解除されるのは仕方がないとしても、その扱いについて考えていたところ、こちらも一癖ある挙動だったので紹介します。

通常 Immersive モードではない場合、WebView にキーボードが被るという問題を解決すべく、AndroidManifest.xml の activity ノード属性として android:windowSoftInputMode="adjustResize" と書くのですが、Immersive モードの場合はこの方法がうまくいきません。そこで試してみたのが、入力フィールドがフォーカスした時に Immersive モードを解除する、という方法です。

まず、MainActivity クラスの中に次のような JavaScript インターフェースを用意し、

public class WebViewJavaScriptInterface{
  private Context context;
  public WebViewJavaScriptInterface(Context context){
    this.context = context;
  }
  @JavascriptInterface
  public void disableFullScreen() {
    getWindow().getDecorView().setSystemUiVisibility(0);
  }
}

WebView について色々と書いてある onCreate の中で JavaScript から呼び出せるように設定しました。

webView.addJavascriptInterface(new WebViewJavaScriptInterface(this), "app");

そしてテキスト入力フィールドを1つ持っている HTML ではこのように JavaScript から Immersive モードを解除するようにしました。

document.querySelector('input[type=text]').ontouchend = function(){
  app.disableFullScreen();
};

ところが、Logcat に “Uncaught Error: Java exception was raised during method invocation” というエラーを出力しうまく動かなかったので、MainActivity で Handler を呼び出し、JavaScript インターフェース内の関数を次のようにすると期待通りの動作をエミュレータで確認しました。

@JavascriptInterface
public void disableFullScreen() {
  handler.postDelayed(new Runnable() {
    @Override
    public void run() {
      getWindow().getDecorView().setSystemUiVisibility(0);
    }
  }, 0);
}

また、JavaScript インターフェース内にもう一つ次のようなものを用意して(前回不要だと思った enableImmersiveMode 関数を再度用意)、

@JavascriptInterface
public void enableFullScreen() {
  handler.postDelayed(new Runnable() {
    @Override
    public void run() {
      enableImmersiveMode();
    }
  }, 0);
}

送信ボタンを押した時に Immersive モードとなるようにしました。

document.querySelector('#submit').ontouchend = function(){
  app.enableFullScreen();
};

実際にこのような挙動で動くようになったのですが、

ソフトウェアキーボード以外の場所で画面を押すと入力フィールドからフォーカスが外れてキーボードが隠れるという OS の設計上、このように加えておくと更に安心です。

document.querySelector('input[type=text]').onblur = function(){
  app.disableFullScreen();
};

実機で検証してみると、処理能力が劣る古い機種ではフルスクリーンになる際にステータスバーが途中で止まってしまったりということが確認できたので、postDelayed で遅延を750〜1000と与えると(動作的にはギクシャクする感は否めないのですが)解決しました。そして、最初に書いていた android:windowSoftInputMode="adjustResize" を外してみると…なんと入力フィールドが隠れずにキーボードに合わせて移動するという世にも奇妙な…。

参考:

WebViewのAlertDialogでImmersiveモードを維持する

Android の上部にあるツールバーと下部にあるナビゲーションバーを隠しフルスクリーンで表示する「Immersive モード」を使ってハイブリッドアプリを開発している際に、WebView 内の JavaScript で confirm を呼び出すと、全画面表示が解除されてツールバー及びナビゲーションバーが再び表示されてしまうという問題に直面したので調べました。

元々は confirm のボタンラベル名を拡張すべく WebChromeClient 内でこのようなコードを使っていました。

@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result)  {
  new AlertDialog.Builder(MainActivity.this)
    .setMessage(message)
    .setPositiveButton("確認",
      new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
          result.confirm();
        }
      })
    .setNegativeButton("消去",
      new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
          result.cancel();
        }
      })
    .setCancelable(false).create().show();
  return true;
};

この問題の根本にある原因はダイアログがフォーカスを持ってしまうことにあるようなので、参考にした文献のコードを利用し(ワンライナーフェチとしては少し残念な) AlertDialog を一旦 alertToShow に入れるようにして addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) を追加しました。

@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result)  {
  AlertDialog alertToShow = new AlertDialog.Builder(MainActivity.this)
(中略)
  alertToShow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
  alertToShow.show();
  return true;
};

今回の失敗談を一つ紹介すると、MainActivity に次のような全画面設定関数を用意して setPositiveButtonsetNegativeButton のそれぞれの onClick で呼び出したのですが、案の定ボタンを押した後に Immersive モードを再開するという間抜けな結果になり、上述したコードで不要になりました汗。

@SuppressLint("NewApi")
private void enableImmersiveMode() {
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
    getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
  }
}

この例は JavaScript の confirm でしたが、もちろん alert でも同じような処理で解決できると思います。更に調べているとテキストフォーム入力時の input にフォーカスした際に下部からニュッと現れるソフトキーボードと共に Immersive モードが解除されるという問題について Stackoverflow で多く議論されていることが分かりました。こちらも原因は同様なのですが WebView と連携した場合にどうなるのか、別投稿で紹介したいと思います。

参考:

Android StudioでAPIレベルを変更する

Android アプリ案件では社内向けのような限られた端末を対象とした形で野良アプリを配布することが多く、雛形として複製したプロジェクトで API レベルを変更しなければいけない(特に Lollipop から Jelly Bean や KitKat へ)という状況が多いのですが、今回は Android Studio で簡単に処理する方法を Stack Overflow で見つけたので紹介します。

具体的には、build.gradle ファイルに記述されている minSdkVersiontargetSdkVersion の値を目的の API レベルに変更するとエディタの上部右肩に表示される “Sync Now” リンクをクリックしてからメニューコマンド「Build>Rebuild Project」を選択するだけです。

スクリーンショット 2016-02-04 17.10.46

build.gradle ファイルの場所は src/build.gradle と書かれていますが、こちらの環境では Android Studio 1.5 内の遷移で Project/app/build.gradle にありましたので、参考リンクにある内容を照らしながら環境に応じて編集すべき該当ファイルを検討されると良いかと思います。

参考:

Nexus7でシステムアップデートを削除する

ここ最近モバイルアプリの受託案件がほぼ Android 端末用になっているということもあり、ロリポップに更新してからもっさりと動作が重たくなって放置していた Nexus7 2012版を引っ張り出してきてファクトリーイメージでキットカット4.4.4にダウングレードし実機検証に使っているのだけど、どうしても消えない「システムアップデートをダウンロードしました」という通知をうっかり押してしまいそうなので、ステータスバーの通知の削除方法と「設定>システム>タブレット情報>システムアップデート」にあるインストール画面を表示しないようにすべくファイルの削除方法について調べてみました。

まず一つ目に参考したリンクでルート化しているか否かで方法が違うことが分かりました。こちらの環境ではルート化していない条件なので「設定>アプリ>(右へスワイプして)すべて」と進み「Google プレイストア>通知を表示」チェックボックスをオフにする…と思いきや2つ目の参考リンクでは「設定>アプリ>すべて>ConfigUpdater>無効にする」を押せ!とあるのでもう少し調べることにしました。

更に3つ目の参考リンクで判明した面白い方法は、通知を長押しすることで「アプリ情報」というコンテクストメニューが表示されるということでした。そうすることで該当する「Googleサービスフレームワーク」の設定へ誘導してくれました。

Screenshot_2016-02-01-14-08-02

その画面で「通知を表示」のチェックボックスを切り「データを消去」ボタンを押すと、ステータスバーの通知が消え、システムアップデート設定画面で「お使いのシステムは最新の状態です。」と表示されるようになりました。(最終確認日が1970年となっているのはご愛嬌)

http://hkitago.tumblr.com/post/138460676496

Screenshot_2016-02-01-14-09-26

やれやれこれで〜と思った矢先に再度通知が…。開発者登録に関係するお話は別投稿で。

参考:

  1. [Q] How to delete downloaded system update a… | Nexus 7 (2013)
  2. How do I delete the lollipop update ? | Android Forums
  3. Nexus 7 how to disable android updates? | Android Forums
  4. NEXUS7 2012 のOTAアップデートを切るには、どうしたらいいのでしょうか。… – Yahoo!知恵袋

アンドロイドでダウンロードフォルダを見る

意外に知らなかった Android でダウンロードフォルダを参照する方法について、基本的には Download アプリを使えば全く問題ないのですが、端末によってはダウンロードフォルダを参照させないようにこのアプリが無いものもあり、そういった場合はファイルブラウザアプリをストアから落としてくることになります。適当な検索語で調べてみると、次の3つくらいの無料アプリが有名なようです。

というのは、通称野良アプリを納品する必要に迫られてサポートに少し時間を要したことがあります。参考サイトではダウンロードフォルダに触れず、すぐにファイルブラウザアプリの話になっているので、ひょっとしたら国産 Android 端末にダウンロードアプリはないのかも…ゴクリ

P.S. 野良アプリ流通が Android の自由度だ!という人もいますが、現在では配布方法に若干の違いがあるだけで iOS のアプリもストアを通さずに簡単に流通させることが可能です。

更に余談

http://hkitago.tumblr.com/post/129050429649

参考:

Nexus7で通知の履歴を見る

iOS と比較して使いやすいのが Android の上部メニューバーにある通知の表示機能だと思うのだけど、利用頻度が然程高くないような場合にアイコンが並び過ぎるのが気になって大量の通知を削除した後に「あれ、今のは!?」ということがあって、Nexus7 で通知の履歴を見る方法について調べました。

  1. ホーム画面でアプリアイコン(下部中央ホームボタンの直上)を押す。
  2. ウィジェットタブに移動(登録アプリの数によりけりで数回右へスワイプ)する。Screenshot_2014-07-14-08-47-28
  3. 「設定をショートカットとする」をタップし続けホーム画面に配置する。
  4. 配置後指を離すと、どの設定をショートカットにするか選択する画面になるので「通知」を選択する。Screenshot_2014-07-14-08-35-16

OS や機種を問わず通知設定は携帯なソーシャル時代に巧く利用したいところ、国産の Android 機種は独自設定があるようなので共通にできるのかは不明です。

参考: