[Firefox OS][Codezine]Codezineにハードウェア系APIの記事が掲載されました

 藪下@2課のガジェオタです。

 CodezineにFxOSのハードウェア系APIを概説した記事が掲載されました。

Firefox OS搭載スマホ「Fx0」でつくろう! はじめてのFirefox OSアプリ開発 第3回
Firefox OSアプリ開発が楽しくなるハードウェアAPIの概要と、センサーAPIや音声APIを使った楽器アプリの作例
http://codezine.jp/article/detail/8540

 記事では分量の都合上さらっと使用例を流して終わってしまいましたが、本ブログではそれぞれについての使い方を解説した記事も書かれているので是非併せて読んでください。

 まだOrientation APIとか書かれてないものもあるので暇を見て追加していきます。

[Firefox OS][WebAPI]バイブレーションAPIの使い方

 藪下@2課のガジェオタです。環境光センサ、近接センサ、GPSときて今回はバイブレーターを動かします。
 バイブレータは使いどころがわかりやすいですね。何らかの通知を目立たせるため、演出の効果の一つとして、メインの効果ではないかもしれませんがちょくちょく使われている場面に出くわします。

バイブレーション

 バイブレーションAPIは端末のバイブレータを制御するためのAPIです。
 着信音とともにバイブレートする機能や通知の一種に使われます。
 バイレーションAPIは振動させたい時間を与えることで制御します。振動時間と停止時間の配列を渡すことによってパターンも表現することができます。

  • [バイブレータのサンプル](https://github.com/aoitan/C86_samples/tree/master/vibrator バイブレータのサンプル)

バイブレータを振動させる

 バイブレータAPIはnavigator.vibrate()によって制御します。
 引数としてnumberあるいはnumberの配列を取り、引数で指定された時間だけバイブレータを振動させます。単位はミリ秒です。
 引数が配列の場合、奇数番目の要素を振動時間、偶数番目の要素を停止時間としたパターンでバイブレータを振動させます。

navigator.vibrate(200);
// 三三七拍子
navigator.vibrate([200, 100, 200, 100, 200, 200,
                   200, 100, 200, 100, 200, 200,
                   200, 100, 200, 100, 200, 100, 200, 100,
                   200, 100, 200, 100, 200, 200]);

バイブレータを停止させる

 引数として0を渡すとバイブレータが停止します。

navigator.vibrate(0);

リファレンス

 今回の内容は以下のURLが一次リソースになります。W3Cの仕様なので各ブラウザもこの仕様に則ります。

まとめ

 バイブレーションAPIは使い方も簡単でいいですね。
 冒頭でも書いた通り主役の効果ではないもののいろいろな場面で小粋に効いてくれる効果だと思います。
 単に通知する場合だけでなく、ゲームなどでも派手な動きや爆発とともに使えばよい演出になるでしょう。

 ただしバイブレーションAPIはバイブレータを駆動させるため不用意に多用すると電池持ちに影響します。
 デバイスを制御するAPI全般に言えることではありますが、適切な使用を心がけましょう。

[Firefox OS][WebAPI]Geolocation APIの使い方

 藪下@@2課のガジェオタです。

 環境光センサ、近接センサと解説してきましたが、今回はGeolocation APIについての記事です。
 アプリを作る人の観点ではこれまでのセンサ類と比べてよく使うものではないでしょうか。よく使われるだけに使ったことがある人も多いかもしれませんね。

地理位置情報

 地理位置情報APIは位置情報の取得を行うAPIです。現在位置の取得、位置情報の監視を行えます。
 位置情報APIはリクエストメソッドにコールバック関数を渡してレスポンスを待つような使い方になっています。
 また位置情報はプライベートな情報であるためAPIの使用時に許可を求めるプロンプトが表示されます。
 地理位置情報APIはnavigator.geolocationに属します。

パーミッションの設定

 Firefox OSで地理位置情報APIを使用するにはマニフェストへのパーミッションの設定が必要です。
 ”permissions” プロパティに “geolocation” を記述します。

  "permissions": {
    "geolocation": {}
  },

現在位置情報の取得

 現在位置の取得にはgetCurrentを使用します。
 geolocation.getCurrentPositionは2つの引数と1つのオプション引数を取ります。
 返り値はありません。

 第3引数のPositionOptionに高精度の位置情報を要求するフラグを立てない場合、高速なレスポンスのために低精度の位置情報を返します。

  navigator.geolocation.getCurrentPosition(successHandler, errorHandler, [PositionOption])
引数 概要
successHandler 現在位置取得成功コールバック
errorHandler 現在位置取得失敗コールバック
PositionOption 高精度位置情報を取得するか、最大試行回数、待ち時間を表すオブジェクト

現在位置の監視

 現在位置の監視にはgeolocation.watchPositionを使用します。
 geolocation.getCurrentPositionは2つの引数と1つのオプション引数を取ります。引数の意味はgeolocation.getCurrentPositionと同じです。
 geolocation.watchPositionは位置に変化があると第1引数のコールバック関数を呼び出します。
 返り値として監視を区別するための値を返却します(@ {aoitan_watchposition_geoloc})。

  navigator.geolocation.watchPosition(successHandler, errorHandler, [PositionOption])
引数 概要
successHandler 現在位置取得成功コールバック。callback void (Position)
errorHandler 現在位置取得失敗コールバック。callback void (ErrorPosition)
PositionOptions 高精度位置情報の取得や最大試行回数、待ち時間を指定
変数名 概要
enableHighAccuracy true:高精度位置情報を取得する、false:取得しない
timeout タイムアウトまでのミリ秒数
maximumAge 最大試行回数

 監視を終了するにはgeolocation.watchPositionが返却した値を引数としてgeolocation.clearWatchを呼び出します。

  navigator.geolocation.clearWatch(watchId)
引数 概要
watchId watchPositionから返却された監視ID

位置情報

 geolocation.getCurrentPositiongeolocation.watchPositionでの測位が成功すると、成功コールバックで位置情報が取得できます。
 位置情報には座標情報と時刻が含まれます。

変数名 概要
coords 座標情報を表すCoordinates型の値
timestamp coordを取得した時刻を表すDOMTimeStamp型の値
変数名 概要
latitude 地理座標系の緯度
longitude 地理座標系の経度
altitude 高さ。高さが測位できない場合はnull
accuracy 緯度経度についての精度。非負実数
altitudeAccuracy 高さの精度。非負実数。高さが測位できない場合はnull
heading 北に対するデバイスの向き。時計回りに0~360度を取る
speed 水平移動速度

altitude、altitudeAccuracy変数の単位はメートルです。またspeedは秒速メートル単位で取得できます。
heading変数は、向きが提供できない場合にnull、静止状態の時NaNをとります。

サンプル

function startPositioning() {
  var geo = navigator.geolocation;

  // まず現在地を取る
  return this.getCurrentPosition().then((pos) => {
    positionPrint(pos);

    // 精度を上げるために監視を始める
    watchId = geo.watchPosition((position) => {
      positionPrint(pos);
    }, (error) => {
      errorPrint(error);
    }, {enableHighAccuracy: true});
    return watchId;
  }).catch((error) => {
    errorPrint(error);
  });
}

function getCurrentPosition() {
  var geo = navigator.geolocation;

  var getLocation = new Promise((resolve, reject) => {
    geo.getCurrentPosition((position) => {
      resolve(position);
    }, (error) => {
      reject(error);
    });
  });

  return getLocation;
}

 サンプルでは低精度な代わりに素早く位置情報を取得してから高精度で位置情報監視を開始して精度を上げる動作を端的に表しています。
 実際のアプリでは上記サンプルのように文字列を表示するだけでなく、マップAPIを併用して地図上で位置と範囲を表示するような形になるでしょう。

リファレンス

 今回の内容は以下のURLが一時リソースになります。W3Cの仕様なので各ブラウザもこの仕様に則ります。

まとめ

 地理位置情報APIの典型的な使用例は地図との連携でしょう。Firefox OSでもv1.0のころはNokiaのhere mapを搭載していたり、今でも開発ビルドではOpen Street Mapと組み合わせたテストアプリなど、地図との連携の例があります。
 昨今では地図以外での利用も増えていますね。SMSなどの投稿時や写真にジオタグをつける、スタブラやIngressのような位置に基づいたゲームなどですね。

 位置情報はいろいろ使えるところがあるので面白いアプリを作っていきましょう!

[Firefox OS][WebAPI]近接センサの使い方

 藪下@薄い本とか勉強会資料とか書き物ばっかりしてる気がする。です。

 前回は環境光センサについて書きました。今回は近接センサについて見ていきます。
 環境光センサの時に物体からの相対位置を計算できるかもしれないと書きましたが、その意味では今回のAPIが本来の大本命です。後述する通り残念な動きになりますが。。。

近接センサ

 近接センサはデバイスと他の物体がどれほど近づいたかを検知するセンサです。
携帯電話では通話時に顔とデバイスの近さを検出して消灯することで省電力化する用途に使われます。
 Firefox OSでは近接センサの値を取得することもできます。近接センサの値を取得するにはuserproximityあるいはdeviceproximityイベントのハンドラを登録します。

イベントの登録

 近接センサAPIはwindowオブジェクトに属します。なのでイベントハンドラをaddEventListenerで登録する場合はwindow.addEventListenerで、onハンドルプロパティに代入して登録する場合はwindow.on<イベント名>を使用します。

 近接センサAPIには二つのイベントが存在します。同じ近接センサからの値に対して動くイベントですが、それぞれ取得できる値が違います。

userproximity

  • イベント名:userproximity

 addEventListenerでのイベント登録は次の通りです。

  window.addEventListener('userproximity', userHandler);

 onイベントプロパティでのイベント登録は次の通りです。

  window.onuserproximity = userHandler;

イベントハンドラの書式

 userproximityで取得する近接センサの値はevent.nearで取得できます。
 event.nearはすぐ近くに物体があることを検知した場合true、そうでない場合にfalseの値を取ります。

function userHandler(event) {
  var near = event.near;
  (snip)
}

サンプル

var interval;

function startVibrate() {
  interval = setInterval(() => {
    navigator.vibrate([200, 200]);
  }, 400);
}

function userHandler(event) {
  if (event.near) {
    // 近かったらバイブする
    startVibrate();
  } else {
    // 近くなかったらバイブ止める
    navigator.vibrate(0);
    if (interval) {
      clearInterval(interval);
    }
  }
}

 userproximityのサンプルでは近接状態を検知するとバイブレータを振動させています。
 バイブレータAPIの仕様で振動し続けさせることができないのでsetIntervalで振動し続けさせています。バイブレータAPIについてはいずれ記事にします。
 近接状態でなくなったらバイブレータを停止させます。

deviceproximity

  • イベント名:deviceproximity

 deviceproximityのaddEventListenerでのイベント登録は次の通りです。

  window.addEventListener('deviceproximity', deviceHandler);

 deviceproximityのonイベントプロパティでのイベント登録は次の通りです。

  window.ondeviceproximity = deviceHandler;

イベントハンドラの書式

function deviceHandler(event) {
  var min = event.min;
  var max = event.max;
  var value = event.value;
  @<i>{(snip)}
}
  • event.value
    • event.valueの値はセンサで検出した物体とのセンチメートル単位の距離を表します
  • event.min
    • event.minの値は検知できる最小のセンチメートル単位の距離を表します
  • event.max
    • event.maxの値は検知できる最大のセンチメートル単位の距離を表します

サンプル

function deviceHandler(event) {
  var _ = document.getElementById.bind(document);

  var max = _('max_value');
  var min = _('min_value');
  var val = _('val_value');

  max.textContent = event.max;
  min.textContent = event.min;
  val.textContent = event.value;
}

 deviceproximityのサンプルではセンサの値が変化したら画面に表示しています。
 確認に使ったkeonでは10か0しか返りませんでしたが、もっと遠くまで検知できて段階的に値が変化する端末なら値に応じて目のつむりかたが変わるキス顔アプリとか作れそうですね。
 キス顔アプリ好きすぎやねん。。。

まとめ

 今回紹介した近接センサAPIも環境光センサと同様にセンサイベントに対してイベントハンドラを設定して待ち受ける仕組みでした。
 近接センサの使いどころもやっぱり輝度調整とかなんですが、環境光センサの記事で書いた通りcertifiedなのでちょっと面白くないところですね。
 よくプッシュアップとかシットアップのアプリでスマホの画面にタッチさせるものがありますが、タッチまで行くのは結構物理的に大変なことが多い(スマホを置く場所が床とか膝の上とかになる)ので、近接センサで一定の近さになったら成立にするとかに使えるかもしれません。これも面白いことを思いついたらぜひ作って教えてくださいね。

[Firefox OS][WebAPI]環境光センサの使い方

 藪下@ワールドカップでだれてからblog停滞中です。

 個人的な活動でいくつかのAPIを使ってみる機会があったのでしばらくAPIを使ってみたシリーズやります。
 中身を読むのが本来の藪下の興味なので、一通り使い方の記事を書いたら気になるAPIは中身も読んでいきます。

 今回は環境光センサを使ってみます。

環境光センサ

 環境光センサはデバイス周辺の照度を検出するセンサです。
 携帯電話では環境の明るさに応じて液晶パネルの明るさを変えて見やすく省電力にする用途に使われます。
 環境光センサAPIはその名の通り環境光センサの値を取得します。
 環境光センサの値を取得するにはdevicelightイベントにハンドラを登録します。

イベントの登録

 環境光センサAPIはwindowオブジェクトに属します。なので

  • イベントハンドラをaddEventListenerで登録する場合
    • window.addEventListener
    • イベント名:devicelight
  • ondevicelightに代入して登録する場合
    • window.ondevicelightを使用します。

 addEventListenerでのイベント登録は次の通りです。

  window.addEventListener('devicelight', handler);

 ondevicelightのイベント登録は次の通りです。

  window.ondevicelight = handler;

イベントハンドラの書式

 環境光センサAPIはセンサで検出したルクス単位の明るさをunrestrected doubleで返します。
 環境光センサの値はevent.valueで取得できます。

  function handler(event) {
    var light = event.value; // ambient light sensor value
    @<i>{(snip)}
  }

サンプル

  • [https://github.com/aoitan/C86_samples/tree/master/devicelight](https://github.com/aoitan/C86_samples/tree/master/devicelight 環境光センサのサンプル}
window.addEventListener('devicelight', function(event) {
  console.log('環境光センサの値は' + event.value + 'です');
  var brightness = '';
  var l10n = navigator.mozL10n;
  if (event.value > 35000) {
    brightness = l10n.get('SHINE');
  } else if (event.value > 10000) {
    brightness = l10n.get('CLOUDY');
  } else if (event.value > 1000) {
  } else if (event.value > 200) {
    brightness = l10n.get('ROOM');
  } else if (event.value > 100) {
    brightness = l10n.get('NIGHT');
  } else if (event.value > 10) {
    brightness = l10n.get('CANDLE');
  } else {
    brightness = l10n.get('MOONLIGHT');
  }
  var light_value = document.getElementById('light_value');
  light_value.innerHTML = event.value + '(' + brightness + ')';
});

 上記コードでは環境光センサの値に応じてどのぐらい明るいかの文字列を表示しています。
 明るさを表す文字列はl10n.getでロケールに合わせた文字列を取得しています。
 l10n.get('SHINE')の場合英語 (アメリカ) ロケールだと ‘shine’ が、日本語ロケールだと ‘晴天’ が表示される要領です。

まとめ

 環境光センサAPIはFxOSのセンサAPIに多く見られるイベントリスナを登録してデバイスイベントを待つスタイルのAPIでした。
 このAPIの使いどころはやっぱり輝度調整とかになるのかなと思うのですが、ディスプレイの制御がcertifiedなのでそこはいまいち面白味ないです。
 環境光センサAPIである程度物体の近さを計算する補助になるので、やりようによっては物体からの相対位置を計算することができるかもしれません。
 たとえば顔を近づけると目をつぶったりほほを赤らめてくれるようなキス顔アプリとかも頑張れば作れるかもしれませんね。面白いことを思いついたらぜひ作った教えてくださいね。

[Firefox OS][WebAPI] Idle API読んでみた

 藪下@2課のガジェオタです。

 世間がFirefox 29とZTE Open CとFirefox OS v1.3で賑わっているなかどこふく風でAPIの実装を読んでみたお話です。

 前回addIdleObserverが見えないと書いたのですが、geckoのソースコードを覗いてみたら実装されてるっぽいです。

http://wiki.mozilla.org/WebAPI/IdleAPI

 ここにも書いてある通りaddIdleObserverはNavigatorの下にあるのでNavigatorを見てみます。
 まずはwebidlですね。

http://reading.fxos.org/source/xref/B2G/gecko/dom/webidl/Navigator.webidl#167

  /**
   * Navigator requests to add an idle observer to the existing window.
   */
  [Throws, Func="Navigator::HasIdleSupport"]
  void addIdleObserver(MozIdleObserver aIdleObserver);

  /**
   * Navigator requests to remove an idle observer from the existing window.
   */
  [Throws, Func="Navigator::HasIdleSupport"]
  void removeIdleObserver(MozIdleObserver aIdleObserver);

 [Func]属性がついてますね。Navigator::HasIdleSupportがtrueでないと見えないということを示しています。

 webidlについては以下のページに書かれています。全訳されてませんが[Func]属性の部分は訳しておきました。

 HasIdleSupportを見てみます。

http://reading.fxos.org/source/xref/B2G/gecko/dom/base/Navigator.cpp#2049

/* static */
bool
Navigator::HasIdleSupport(JSContext*  /* unused */, JSObject* aGlobal)
{
  if (!nsContentUtils::IsIdleObserverAPIEnabled()) {
    return false;
  }

  nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
  return CheckPermission(win, "idle");
}

 nsContentUtils::IsIdleObserverAPIEnabled()とCheckPermission(win, “idle”)に依存してるのでそれぞれ見ていきます。

http://reading.fxos.org/source/xref/B2G/gecko/content/base/public/nsContentUtils.h#1837

  /**
   * Returns true if the idle observers API is enabled.
   */
  static bool IsIdleObserverAPIEnabled() { return sIsIdleObserverAPIEnabled; }

 sIsIdleObserverAPIEnabledが設定されているところを探します。

http://reading.fxos.org/source/xref/B2G/gecko/content/base/src/nsContentUtils.cpp#434

  sIsIdleObserverAPIEnabled = Preferences::GetBool("dom.idle-observers-api.enabled", true);

 ということで “dom.idle-observers-api.enabled” がtrueかどうかがnsContentUtils::IsIdleObserverAPIEnabled()の結果です。

 次にCheckPermission(win, “idle”)を追います。

http://reading.fxos.org/source/xref/B2G/gecko/dom/base/Navigator.cpp#1789

/* static */
bool
Navigator::CheckPermission(nsPIDOMWindow* aWindow, const char* aType)
{
  if (!aWindow) {
    return false;
  }

  nsCOMPtr<nsIPermissionManager> permMgr =
    services::GetPermissionManager();
  NS_ENSURE_TRUE(permMgr, false);

  uint32_t permission = nsIPermissionManager::DENY_ACTION;
  permMgr->TestPermissionFromWindow(aWindow, aType, &permission);
  return permission == nsIPermissionManager::ALLOW_ACTION;
}

 ということでパーミッションがALLOW_ACTIONかDENY_ACTIONかで見ているようなので設定しているところを探します。

http://reading.fxos.org/source/xref/B2G/gecko/dom/apps/src/PermissionsTable.jsm#209

                           "idle": {
                             app: DENY_ACTION,
                             privileged: DENY_ACTION,
                             certified: ALLOW_ACTION
                           },

 あれ、これなんか見たことあると思ったらMDNとmxrに書いてありました。

https://developer.mozilla.org/ja/docs/Web/Apps/App_permissions

関連情報
Firefox コード内では 許可設定一覧表 にすべての許可設定が定義されています。

https://mxr.mozilla.org/mozilla-central/source/dom/apps/src/PermissionsTable.jsm#36

 というわけでcertifiedのアプリにidleパーミッションをつけないといけないみたいです。
# MDNにもwikimoにも必要って書いてないし! ないし!

 サンプルコードを更新しました。

https://github.com/aoitan/gcg_labo/tree/master/api_reading/20140323_using_Idle_API

 マニフェストにpermissions属性を加えてます。もちろん許可するのはidleです。
 あとCSPに怒られたのでスクリプトをidle_test.jsに抜き出しました。

  "permissions": {
    "idle": {}
  },

 ビルドして動かしてみましょう。

Screenshot_from_2014-05-12 01_22_39

 とまあ動いたのですが、HasIdleSupportを見る限りパーミッションが設定されてないとやっぱりAPIが見えないはずなので、デスクトップとかfor Android的にはおかしいです。
# wikimoにはデスクトップとAndroidはデフォルト有効と書いてます。
https://wiki.mozilla.org/WebAPI
 これビルド対象合わせでパーミッションチェックしないといけない気がするのでちょっとパッチ書いてみようかと思います。

 今回Idle APIを追いかけましたが、実は書いた以上にソースコードを追いかけました。
 パーミッションマネージャを割と掘り下げたので機会があれば記事にします。お楽しみに。

[Firefox OS][WebAPI]Page Visibility APIの使い方 – onResumeの代わりにできること

 藪下@2課のガジェオタです。

 Firefox Developers Conference 2014 in Kyotoの準備とかその間に滞った作業のリカバリでバタバタしていたのでご無沙汰していました。今週から平常運転に戻します。

 FxOSコードリーディングの運営をお手伝いいただいているひらとりさんとノマドワーキングしてたら面白い質問をもらったので調べてみました。

Q&A

Q.Firefox OSのアプリにはAndroidのライフサイクルでいうところのonResumeがないけどアプリから離れて戻ってきた時に動作したい場合どうしたらいいの?

A.Page Visibility APIを使いましょう。

What is Page Visibility API?

 Page Visibility APIはSafari発祥みたいですね。Page Visibility APIではページが見えているかいないかを知ることができます。
 onblurとかonfocus見たいなハックは見たことありますよね。これらはフォーカスが外れたとき、フォーカスを得たときを検知してくれますがページの可視状態と必ずしも一致しません。Page Visibility APIだとちゃんと見えなくなったり見えるようになったときにvisibilitychangeイベントを呼んでくれるので正しい解決だといえます。
 gaiaだとブラウザやSMS、時計、カメラなどいろいろなところで使っています。

How to

 使い方を見ていきます。

visibilitychangeイベント

 visibilitychangeイベントはDOMイベントです。なのでいつものaddEventListenerでイベントハンドラを登録します。

document.addEventListener("visibilitychange", handler);

function handler() {
    // なんかなんか
}

document.hiddenメソッド

 hiddenメソッドはページが見えていない場合trueを、そうでない場合falseを返します。

if (document.hidden) {
    // 不可視状態
} else {
    // 可視状態
}

document.visibilityStateメソッド

 visibilityStateメソッドは可視性の状態を表す文字列を返します。

  • visible
    • ページは見えています。Page Visibility APIでの「見えている」というのは別のタブを表示していない、最小化されていないということなので、デスクトップなどでは別のウィンドウが上に乗っていてもvisibleになることがあります。
  • hidden
    • ページは見えていません。前述の通りタブの状態や最小化の状態のことを言っているのでhiddenであるということは別のタブを表示しているか最小化されているということです。
  • prerender
    • ページは見えていません。ページはまだプリレンダリングされただけでユーザに見えるように表示されていません。
    • 他の状態からprerenderになることはありません。
if (document.visibilityState == "visible") {
    // 可視状態
} else if (document.visibilityState == "hidden") {
    // 不可視状態
} else if (document.visibilityState == "prerender") {
    // プリレンダリング状態
}

Try on Firefox OS

 Firefox OS上でも試してみます。例のごとくサンプルコードは以下のURLです。

  • https://github.com/aoitan/gcg_labo/tree/master/api_reading/20140430_using_Page_visibility_API

 How toのところで示した使い方で画面に何かしら表示するようにしただけです。
 マニフェストは何も特別なことをしていないので省略します。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Using Page Visibility API Sample</title>
    <script src="index.js"></script>
  </head>
  <body>
    <ul id="output"></ul>
  </body>
</html>
init();

function init() {
  document.addEventListener("visibilitychange", handler);
  var output = document.getElementById('output');
  output.appendChild(outputVisibilityState());
}

function handler() {
  var output = document.getElementById('output');
  output.appendChild(outputVisibilityChange());

  var childUl = document.createElement('ul');
  childUl.appendChild(outputHidden());
  childUl.appendChild(outputVisibilityState());

  output.appendChild(childUl);
}

function outputVisibilityChange() {
  var li = document.createElement('li');
  li.innerHTML = 'event: visibilitychange';
  return li;
}

function outputHidden() {
  var li = li = document.createElement('li');
  if (document.hidden) {
    // 不可視状態
    li.innerHTML = 'document.hidden = hidden';
  } else {
    // 可視状態
    li.innerHTML = 'document.hidden = visible';
  }
  return li;
}

function outputVisibilityState() {
  var li = document.createElement('li');
  if (document.visibilityState == "visible") {
    // 可視状態
    li.innerHTML = 'document.visibilityState = visible';
  } else if (document.visibilityState == "hidden") {
    // 不可視状態
    li.innerHTML = 'document.visibilityState = hidden';
  } else if (document.visibilityState == "prerender") {
    // プリレンダリング状態
    li.innerHTML = 'document.visibilityState = prerender';
  }
  return li;
}

 ホーム押したりホーム長押しから戻ったりしてみました。

using_page_visibility_api

 なんだか検知できてますね!

さいごに

 これでAndroidのライフサイクルイベントをすべて賄えるわけではないんですが、既存のAndroidアプリを移植する上で引っかかる部分の一部は解決できるのではないでしょうか。

[Firefox OS][WebAPI] Idle APIの使い方

 藪下@2課のガジェオタです。

 先週の続きでFxOS勉強会のLTネタ解説5回目を書こうと思っていたんですが、思ったより時間がかかりそうなので別のAPIを 解説することにします。
 今回はIdle APIの使い方を見ていきます。

目次

  • Idle APIのインターフェイス
  • 使い方

Idle APIのインターフェイス

 Idle APIの主なメソッドはnavigatorに用意されている以下のメソッドになります。

partial interface Navigator {
  void addIdleObserver(IdleObserver);
  void removeIdleObserver(IdleObserver);
};

 void addIdleObserver(IdleObserver)とvoid removeIdleObserver(IdleObserver)はそれぞれアイドル時とアクティブ時に通知されるハンドラと秒数を表すオブジェクトIdleObserverを受け取ります。

navigator.addIdleObserver(IdleObserver)

 addIdleObserverはIdleObserverオブジェクト受け取ってnavigatorに設定します。
 アイドル状態になってからIdleObserverオブジェクトに設定された秒数を経過した時点でアイドル状態を知らせるハンドラが呼ばれます。またアクティブ状態になった時アクティブ状態を知らせるハンドラが呼ばれます。

navigator.removeIdleObserver(IdleObserver)

 removeIdleObserverはnavigatorからIdleObserverオブジェクトを取り除きます。
 removeIdleObserver後は渡したIdleObserverに設定されているハンドラは呼ばれなくなります。

IdleObserver

 ここまで何度かIdleObserverという名前が出てきていますが、これはaddIdleObserverとremoveIdleObserverに渡す秒数とハンドラをセットにしたオブジェクトです。

[NoInterfaceObject]
interface IdleObserver {
  attribute long time; // seconds
  void onidle();
  void onactive();
};

 timeは非アクティブになってからonidle()が呼び出されるまでの秒数。
 onidleが非アクティブになってからtime秒経過した際に呼ばれるハンドラ。
 onactiveがアクティブになった際に呼ばれるハンドラです。

使い方

 使い方はいつものaddEventListenerと似ています。
 navigator.addIdleObserverでIdleObserverを渡せば無操作になってからIdleObserver.time秒後にIdleObserver.onidleが、アクティブ復帰時にIdleObserver.onactiveが呼ばれます。

 具体的な例で示すと。

navigator.addIdleObserver({ time: 4, onidle: myIdleHandler, onactive: myActiveHandler});

 とした場合ユーザの最後の操作から4秒後にmyIdleHandleerが呼ばれ、ユーザが操作したときにmyActiveHandlerが呼ばれます。

 試しに動かしてみました。
 以下のリポジトリにサンプルコードを置いたので試す環境がある方は試してみてください。

https://github.com/aoitan/gcg_labo/tree/master/api_reading/20140323_using_Idle_API

 Firefox OSで試す場合は、Idle APIがFirefox OSではCertifiedなのでgaiaのビルドが必要になります。
 デスクトップとAndroidでは dom.idle-observers-api.enabled というプリファレンスがtrueならIdle APIを使用可能です。

 とまあまるで動いたかのように書いてるんですが、動きませんでした。
 addIdleObserverがないと怒られます。navigatorのプロパティを覗いてみてもaddIdleObserverがありませんでした。

 ちょっとJSから追ってても原因がわからないので次回はAPIの中に進んでみたいと思います。