Androidのウィジェットアプリを作成してみた

あけましておめでとうございます。 モバイルアプリエンジニアの工藤です。   僕は普段Androidス…

あけましておめでとうございます。

モバイルアプリエンジニアの工藤です。

 

僕は普段Androidスマホを使用しているのですが、

iPhoneではなくAndroidを利用しているのはウィジェットの存在が大きいのかなと思っています。

まだウィジェットを作ったことが無かったので、ホーム画面上に現在地を表示するアプリを作ってみました。

 

ウィジェットとは

ホーム画面に常に表示することができるアプリをウィジェットと呼びます。

アプリを起動せずに情報を表示することができるため、

ビューアーとして活躍します。

 

アプリの内容

・ウィジェット以外に画面を持たない

・位置情報を取得している間、緯度と経度を表示し続ける

 

準備

1.プロジェクト作成

プロジェクト名:MyWigetApp

最初に追加するActivityは「Add No Activity」にしておきます

2.Wiget用class作成

スクリーンショット 2016-01-08 10.47.53

スクリーンショット 2016-01-08 10.49.43

 

処理実装

NewAppWidget.java

サービスの起動のみ行うメインクラスです


package com.example.kudo.mywigetapp;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;

/**
* Implementation of App Widget functionality.
*/
public class NewAppWidget extends AppWidgetProvider {

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them

// サービスの起動
Intent intent = new Intent(context, ServiceSample.class);
context.startService(intent);
}

@Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}

@Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
}

ServiceSample.java

ボタンイベントを受け取り、GPSを使って位置情報の取得開始・終了を制御します。

GPS情報が更新されたら、都度画面を更新します。


package com.example.kudo.mywigetapp;

import android.Manifest;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.RemoteViews;

public class ServiceSample extends Service implements LocationListener {
private static final String TAG = ServiceSample.class.getSimpleName();
private final ServiceSample self = this;

private final String START_ACTION = "START_ACTION";
private final String FINISH_ACTION = "FINISH_ACTION";

private LocationManager mLocationManager;

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

// ボタンが押された時に発行されるインテントを準備する
Intent startIntent = new Intent(START_ACTION);
Intent finishIntent = new Intent(FINISH_ACTION);

PendingIntent startPendingIntent = PendingIntent.getService(this, 0, startIntent, 0);
PendingIntent finishPendingIntent = PendingIntent.getService(this, 0, finishIntent, 0);

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.new_app_widget);
remoteViews.setOnClickPendingIntent(R.id.startGetLocation, startPendingIntent);
remoteViews.setOnClickPendingIntent(R.id.finishGetLocation, finishPendingIntent);

if (START_ACTION.equals(intent.getAction())) {

Log.d(TAG, "位置情報取得開始");

getMyLocation();

remoteViews.setTextViewText(R.id.latitude, "位置情報取得中...");
remoteViews.setTextViewText(R.id.longitude, "位置情報取得中...");

} else if (FINISH_ACTION.equals(intent.getAction())) {
if (checkPermission()) {

Log.d(TAG, "位置情報取得完了");

//位置情報の取得終了
mLocationManager.removeUpdates(this);

remoteViews.setTextViewText(R.id.latitude, null);
remoteViews.setTextViewText(R.id.longitude, null);

}
}

// AppWidgetの画面更新
ComponentName thisWidget = new ComponentName(this, NewAppWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, remoteViews);

return START_NOT_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
return null;
}

private void getMyLocation() {

mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

// Criteriaオブジェクトを生成
Criteria criteria = new Criteria();

criteria.setAccuracy(Criteria.ACCURACY_LOW); //位置情報の精度
criteria.setPowerRequirement(Criteria.POWER_HIGH); //消費電力
criteria.setAltitudeRequired(false); //高度情報取得の有無
criteria.setSpeedRequired(false); //速度情報取得の有無
criteria.setBearingRequired(false); //方向情報取得の有無
criteria.setCostAllowed(false); //費用を許可するか

String provider = mLocationManager.getBestProvider(criteria, true);

if (checkPermission()) {
// LocationListenerを登録
mLocationManager.requestLocationUpdates(provider, 0, 0, this);
} else {
Log.d(TAG, "位置情報取得不可");

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.new_app_widget);
remoteViews.setTextViewText(R.id.latitude, "権限不足のため、位置情報取得に失敗しました");
remoteViews.setTextViewText(R.id.longitude, "権限不足のため、位置情報取得に失敗しました");

// AppWidgetの画面更新
ComponentName thisWidget = new ComponentName(this, NewAppWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, remoteViews);
}
}

private boolean checkPermission() {

boolean ret = true;
if (getPackageManager().checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, getPackageName())
== PackageManager.PERMISSION_GRANTED
&& getPackageManager().checkPermission(Manifest.permission.ACCESS_FINE_LOCATION, getPackageName())
== PackageManager.PERMISSION_GRANTED
) {
//パーミッションあり
} else {
ret = false;
}
return ret;
}

@Override
public void onLocationChanged(Location location) {

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.new_app_widget);
remoteViews.setTextViewText(R.id.latitude, Double.toString(location.getLatitude()));
remoteViews.setTextViewText(R.id.longitude, Double.toString(location.getLongitude()));

// AppWidgetの画面更新
ComponentName thisWidget = new ComponentName(this, NewAppWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, remoteViews);

}

@Override
public void onProviderDisabled(String provider) {
}

@Override
public void onProviderEnabled(String provider) {
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}


AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.kudo.mywigetapp">

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

<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver android:name=".NewAppWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>

<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/new_app_widget_info" />
</receiver>

<service android:name="ServiceSample">
<intent-filter>
<action android:name="START_ACTION" />
<action android:name="FINISH_ACTION" />
</intent-filter>
</service>
</application>

</manifest>

new_app_widget_info.xml

</p>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#09C"
android:orientation="vertical"
android:padding="@dimen/widget_margin">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="緯度 : "
android:textColor="#ffffffff"
android:textSize="16dp" />

<TextView
android:id="@+id/latitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffffff"
android:textSize="16dp" />

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="経度 : "
android:textColor="#ffffffff"
android:textSize="16dp" />

<TextView
android:id="@+id/longitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffffff"
android:textSize="16dp" />

</LinearLayout>

<Button
android:id="@+id/startGetLocation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="位置情報取得開始"
android:textColor="#FF222222" />

<Button
android:id="@+id/finishGetLocation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="位置情報取得終了"
android:textColor="#FF222222" />
</LinearLayout>
<p style="text-align: left;">

 

表示結果

位置情報取得前

Screenshot_2016-01-08-18-24-11

 

取得中…

Screenshot_2016-01-08-18-24-16

 

取得完了後

Screenshot_2016-01-08-18-02-37

 

表示できました!