ユーザーがボタンをクリックすると、メインアクティビティがブロードキャストレシーバーを呼び出し、次にサービスを呼び出して、ユーザーの GPS 位置を特定の間隔で電子メールアドレスに送信するこのアプリケーションが既にあります。アプリは問題なく動作します。
ただし、私がやりたいことは、ユーザーがデバイスの電源ボタンをアクティブにすると、ブロードキャスト レシーバーがアクティブになることです。これまでのところ、この質問を見て、それを使用したので、マニフェスト ファイルは次のようになります。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.angelo.serviceexample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.angelo.serviceexample.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.permission.PREVENT_POWER_KEY" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.angelo.serviceexample.GPSLoggerService" />
<receiver android:name="com.angelo.serviceexample.AlarmReceiver">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"></action>
<action android:name="android.intent.action.SCREEN_ON"></action>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"> </action>
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"></action>
<action android:name="android.intent.action.ACTION_SHUTDOWN"></action>
</intent-filter>
</receiver>
</application>
</manifest>
また、Broadcast Receiver クラスには、アクティブ化されたときに呼び出すためのインテント フィルターがあります。これまでのところ、AlarmReceiver.java ファイルは次のようになっています。
package com.angelo.serviceexample;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context,GPSLoggerService.class));
//Toast.makeText(, "power button clicked",Toast.LENGTH_LONG).show();
Log.v("Tag", "AlarmReceiver called.");
}
}
ただし、LogCat をチェックしていたときは、ユーザーがメイン アクティビティのボタンを押すたびに、次のようにログがアクティブになります。
public class MainActivity extends Activity {
private int currentIntervalChoice = 0;
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
setAppInfo();
addButtonListeners();
enableControls();
return true;
}
return super.dispatchKeyEvent(event);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setAppInfo();
addButtonListeners();
enableControls();
}
private void setAppInfo() {
TextView txtInfo = (TextView)findViewById(R.id.app_info);
txtInfo.setText(Html.fromHtml(getString(R.string.app_info)));
Linkify.addLinks(txtInfo, Linkify.ALL);
}
private void addButtonListeners() {
((Button)findViewById(R.id.start_logging)).setOnClickListener(btnClick);
((Button)findViewById(R.id.logging_interval)).setOnClickListener(btnClick);
}
private void enableControls(){
boolean isServiceRunning = AppSettings.getServiceRunning(this);
String buttonText = getString(R.string.start_logging);
if(isServiceRunning){
buttonText = getString(R.string.stop_logging);
((Button)findViewById(R.id.logging_interval)).setEnabled(false);
}
else{
((Button)findViewById(R.id.logging_interval)).setEnabled(true);
}
((Button)findViewById(R.id.start_logging)).setText(buttonText);
}
private void changeLoggingIntercal(){
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
final String loggingIntervals[] = { "1 minute", "3 minute", "5 minutes", "10 minutes" };
builder.setTitle(getString(R.string.logging_interval));
builder.setSingleChoiceItems(loggingIntervals, currentIntervalChoice, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
currentIntervalChoice = which;
setLoggingInterval(currentIntervalChoice);
dialog.dismiss();
}
});
builder.show();
}
private void setLoggingInterval(int intervalChoice){
int interval = 1;
switch(intervalChoice){
case 0: interval = 1; break;
case 1: interval = 3; break;
case 2: interval = 5; break;
case 3: interval = 10; break;
default: interval = 1; break;
}
AppSettings.setLoggingInterval(this, interval);
}
public void setLogFileName(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = sdf.format(new Date());
String filename = "GPSLog." + dateString + ".kml";
AppSettings.setLogFileName(this, filename);
}
private View.OnClickListener btnClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.start_logging:{
toggleLogging(AppSettings.getServiceRunning(MainActivity.this),
AppSettings.getLoggingInterval(MainActivity.this));
enableControls();
break;
}
case R.id.logging_interval:{
changeLoggingIntercal();
break;
}
}
}
};
private void toggleLogging(boolean isStart, int interval){
AlarmManager manager = (AlarmManager)getSystemService(Service.ALARM_SERVICE);
PendingIntent loggerIntent = PendingIntent.getBroadcast(this, 0,new Intent(this,AlarmReceiver.class), 0);
if(isStart){
manager.cancel(loggerIntent);
AppSettings.setServiceRunning(this, false);
AppLog.logString("Service Stopped.");
}
else{
setLogFileName();
long duration = interval * 60 * 1000;
manager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), duration, loggerIntent);
AppSettings.setServiceRunning(this, true);
Toast.makeText(getApplicationContext(), "Service Started with interval " + interval
+ ", Logfile name: " + AppSettings.getLogFileName(this), Toast.LENGTH_LONG).show();
AppLog.logString("Service Started with interval " + interval
+ ", Logfile name: " + AppSettings.getLogFileName(this));
}
}
}
また、これは問題のサービス クラスです。
public class GPSLoggerService extends Service implements LocationListener{
private static final int gpsMinTime = 500;
private static final int gpsMinDistance = 0;
private static final int TIMER_DELAY = 1000;
private LocationManager manager = null;
private double latitude = 0.0;
private double longitude = 0.0;
private Timer monitoringTimer = null;
public GPSLoggerService() {
AppLog.logString("GPSLoggerService.GPSLoggerService().");
}
@Override
public IBinder onBind(Intent arg0) {
AppLog.logString("GPSLoggerService.onBind().");
return null;
}
@Override
public void onCreate() {
AppLog.logString("GPSLoggerService.onCreate().");
super.onCreate();
}
public int onStartCommand(Intent intent, int flags, int startId) {
AppLog.logString("GPSLoggerService.onStartCommand().");
startLoggingService();
startMonitoringTimer();
return Service.START_STICKY;
}
@Override
public void onLocationChanged(Location location) {
AppLog.logString("GPSLoggerService.onLocationChanged().");
latitude = location.getLatitude();
longitude = location.getLongitude();
}
@Override
public void onProviderDisabled(String provider) {
AppLog.logString("GPSLoggerService.onProviderDisabled().");
}
@Override
public void onProviderEnabled(String provider) {
AppLog.logString("GPSLoggerService.onProviderEnabled().");
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
AppLog.logString("GPSLoggerService.onStatusChanged().");
}
private void startLoggingService(){
if (manager == null){
manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
final Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_LOW);
final String bestProvider = manager.getBestProvider(criteria, true);
if (bestProvider != null && bestProvider.length() > 0){
manager.requestLocationUpdates(bestProvider, gpsMinTime,gpsMinDistance, this);
}
else{
final List<String> providers = manager.getProviders(true);
for (final String provider : providers){
manager.requestLocationUpdates(provider, gpsMinTime, gpsMinDistance, this);
}
}
}
private void stopLoggingService(){
stopSelf();
}
private void startMonitoringTimer(){
monitoringTimer = new Timer();
monitoringTimer.scheduleAtFixedRate(
new TimerTask(){
@Override
public void run(){
if (longitude != 0.0 && latitude != 0.0){
monitoringTimer.cancel();
monitoringTimer = null;
manager.removeUpdates(GPSLoggerService.this);
sendCoordinates(latitude, longitude);
stopLoggingService();
}
}
},
GPSLoggerService.TIMER_DELAY,
GPSLoggerService.TIMER_DELAY);
}
private void sendCoordinates(double latitude, double longitude){
Looper.prepare();
GMailSender sender = new GMailSender("sender@gmail.com", "password");
//Subject, Body, Sender, Recipient
try {
sender.sendMail("Sample GPS Location",
"This should go to my yahoo account. My Location is at is - Lat: " + latitude + " Long: " + longitude,
"sender@gmail.com",
"receiver@yahoo.com");
Toast.makeText(getApplicationContext(), "Mail Sent", Toast.LENGTH_SHORT).show();
}
catch (Exception e) {
Log.e("SendMail", e.getMessage(), e);
}
}
}
これまでのところ、サービスを呼び出す電話イベントを介してブロードキャストレシーバーを呼び出す方法についてオンラインで読んでいます。よくわかりませんが、設定したバインドオーバーライドが原因で問題が発生していると思います。