古事連記帖

趣味のこと、技術的なこと、適当につらつら書きます。

Windows Phone 8での位置情報取得とバッテリー関連のおはなし

Windows Phone 8 SDK Advent Calendar の6日目のエントリーです。



Windows Phone 7から8に変わって、7では取得できなかった情報がやっと拾えるようになりました。
そんな数ある情報から、今回は大きく2つ。位置情報の取得とバッテリー関連についておはなしします。


位置情報

Windows Phone 8になって、位置情報の取得が少し変わったというか、WinRTのAPIが入ってきたのでその部分が使えるようになった感じです。もちろん従前の位置情報取得についても残っているので同様に使うことは可能です。でも、少しだけ拾える情報が増えてたりしているので、WP8専用アプリを作る際にはこっちを使うといいのかも。
従前のやり方だと、System.Device.Location.GeoCoordinateWatcherを使って取得していました。

private GeoCoordinateWatcher geoCoordinateWatcher;
private void GeoCoordinateWatcherInit()
{
	this.geoCoordinateWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
	this.geoCoordinateWatcher.Start();
	this.geoCoordinateWatcher.StatusChanged += (s, e) =>
		{
			this.Dispatcher.BeginInvoke(() =>
				{
					this.statusBlock.Text = Enum.GetName(typeof(GeoPositionStatus), e.Status);
				});
		};
	this.geoCoordinateWatcher.PositionChanged += (s, e) =>
		{
			this.Dispatcher.BeginInvoke(() =>
				{
					var position = e.Position.Location;
					this.positionBlock.Text = string.Format(
						"Latitude: {0}\n",
						"Longitude: {1}",
						position.Latitude,
						position.Longitude);
				});
		};
}

そしてWindows Phone 8になって、新しくWindows.Devices.Geolocation.Geolocatorというクラスが追加されました。とはいえ、使い方はほとんどGeoCoordinateWatcherと一緒。少し言い回しが違うくらいだと考えても良いと思います。

private Geolocator geolocator;
private void Init()
{
	this.geolocator = new Geolocator {DesiredAccuracy = PositionAccuracy.High, MovementThreshold = 10};
	this.geolocator.StatusChanged += geolocator_StatusChanged;
	this.geolocator.PositionChanged += geolocator_PositionChanged;
}

void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
{
	this.Dispatcher.BeginInvoke(() =>
		{
			var position = args.Position.Coordinate;

			this.positionBlock.Text = string.Format(
				"Latitude: {0}\n"+
				"Longitude: {1}\n"+
				"Position Source: {2}", position.Latitude, position.Longitude, position.PositionSource);
		});
}

private void geolocator_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
{
	this.Dispatcher.BeginInvoke(() =>
		{
			this.statusBlock.Text =
				"Status: " + args.Status;
		});
}

GeoCoordinateWatcherとの違いは、

  • 位置情報取得に使用している情報(3G基地局からの三角測量 (Cellular)、WiFiの情報 (WiFi)、GPS (Satellite))が取得できること
  • インスタンスを作ってから測位がスタートしている様子

くらいかなと思います。2つめの部分は少しわかんないです。(ドキュメントでは PositionChanged イベントハンドラーが登録されてないと動かないともあります)


ちなみに、どちらも必ず「WMAppManifest.xml」から「ID_CAP_LOCATION」を有効にしておいてください。

バッテリー関連

念願のバッテリー情報が拾えるようになりました! _|\○_ヒャッ ε=\_○ノ ホーウ!!
…といっても、Androidみたいにバッテリーの温度とか容量とかを拾えるわけではなさそうですが('A`)

バッテリーの現在残量を拾う

Windows Phone 8からは、バッテリーの残量と、推定使用可能時間の取得が可能になったようです。
それらを取得するのには、Windows.Phone.Devices.Power.Batteryクラスを使用します。

private Battery battery;
private void BatteryInit()
{
	this.battery = Battery.GetDefault();

	this.battery.RemainingChargePercentChanged += (s, e) =>
		{
			var b = s as Battery;

			this.statusBlock.Text =
				string.Format(
					"残り: {0:000} %\n" +
					"推定使用可能時間: {1}日{2:00}時間{3:00}分{4:00}秒",
					b.RemainingChargePercent,
					b.RemainingDischargeTime.Days,
					b.RemainingDischargeTime.Hours,
					b.RemainingDischargeTime.Minutes,
					b.RemainingDischargeTime.Seconds);
		};
}

RemainingChargePercentChangedイベントは、ドキュメントでは「RemainingChargePercent の値が 1% 減ったときに発生します。」とあり、減ったときしかわからないのかどうかは実機を見ないとわかりません。
ちなみに、エミュレーターでイベント使わずに取得すると、「残り: 100 % 推定使用可能時間: 10675199日02時間48分05秒」と返ってきました。秒単位まで取れるかは知りません。

バッテリーセーバーかどうかを判断する

バックグラウンドタスク系の宿敵・バッテリーセーバーも、Windows Phone 8では移行しているかどうかを判定することができるようになりました。
取得するには、Windows.Phone.System.Power.PowerManager静的クラスを使います。

private void BatterySaver()
{
	this.statusBlock.Text = Enum.GetName(typeof(PowerSavingMode), PowerManager.PowerSavingMode);

	PowerManager.PowerSavingModeChanged += (s, e) =>
		{
			this.statusBlock.Text = Enum.GetName(typeof(PowerSavingMode), PowerManager.PowerSavingMode);
		};
}

PowerSavingModeプロパティを使うと、バッテリーセーバーに移行しているときに「On」が返ってきます。PowerSavingModeChangedイベントで移行した瞬間を取得できます。


ただ、残念ながらどれも実機で試していないので、実際にどう動くのかは未検証です。早く試したい。