1

我编写了一个应用程序来定期(在后台)记录用户的位置。我使用了 ActivityRecognitionClient。当收到活动时,会将其与先前的活动状态进行比较,并根据评估记录(或不记录)。

只要我的手机处于唤醒状态,它就会按预期工作。(日志消息定期出现在 Eclipse 的 LogCat 视图中)每当屏幕关闭并且设备进入待机状态时,它就会停止接收活动识别调用。另一方面,我也在平板电脑上安装了该应用程序,即使设备进入待机状态,它也会不断更新。(顺便说一句,我的手机是 General Mobile Discovery)

我已经在网上搜索了 3 天(包括 stackoverflow 问题),但到目前为止还没有找到任何对我有用的东西。我会很感激任何帮助...谢谢...

以下是我的应用程序相关代码:

AndroidManifest.xml(即使不需要,也有一些权限,它们可能是未成功尝试解决问题的剩余部分)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.o3n.android.familywathcer"
android:installLocation="internalOnly"
android:versionCode="2"
android:versionName="1.0.1" >

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="19" />
<uses-feature
    android:glEsVersion="0x00020000"
    android:required="true"/>

<permission android:name="org.o3n.android.familywathcer.permission.MAPS_RECEIVE" android:protectionLevel="signature"/>
<uses-permission android:name="org.o3n.android.familywathcer.permission.MAPS_RECEIVE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

    <meta-data
        android:name="com.google.android.maps.v2.API_KEY"
        android:value="***maps api key *****"/>
    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />

    <activity
        android:name="org.o3n.android.familywathcer.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:label="Settings" android:name=".SettingsActivity">
        <intent-filter>
            <action android:name="org.o3n.android.familywatcher.SETTINGS" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>

    <service android:enabled="true" android:name=".FamilyWatcherService" />
    <service android:name=".ActivityRecognitionService" />
    <receiver android:name=".StartFamilyWatcherServiceAtBootReceiver"
        android:enabled="true"
        android:exported="true"
        android:label="StartFamilyWatcherServiceAtBootReceiver" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
</application>

StartFamilyWatcherServiceAtBootReceiver.java(此接收器在设备启动时启动 FamilyWatcherService.java,应用程序 MainActivity.java 类也调用 FamilyWatcherService,因此它在首次安装时开始运行。)

public class StartFamilyWatcherServiceAtBootReceiver extends BroadcastReceiver {

private static final String TAG = "o3nWatcherLog";

@Override
public void onReceive(Context context, Intent intent) {
    //Toast.makeText(context, "StartFamilyWatcherServiceAtBootReceiver called", Toast.LENGTH_SHORT).show();
    Log.d(TAG, "StartFamilyWatcherServiceAtBootReceiver onRecieve");

    SettingsRetriever.getInstance(context);

    Intent serviceIntent = new Intent(context, FamilyWatcherService.class);
    context.startService(serviceIntent);
    }
}

FamilyWatcherService.java(此服务连接到 ActivityRecognitionClient 并注册一个待调用的 PendingIntend 活动更新。当它工作时调用 ActivityRecognitionService.onHandleIntend() 方法)

public class FamilyWatcherService extends Service implements ConnectionCallbacks, OnConnectionFailedListener {

private int period;

private static ActivityRecognitionClient arclient;
private static PendingIntent pIntent;

private static AlarmManager alarmManager; 
private static PendingIntent alarmPI;


private static final String TAG = "o3nWatcherLog";

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

@Override
public void onCreate() {
    Log.d(TAG, "FamilyWatcherService onCreate");
    period = SettingsRetriever.getInstance().getPeriod() * 60 * 1000;
}

@Override
public void onDestroy() {
    Log.d(TAG, "FamilyWatcherService onDestroy");
    if(arclient!=null){
        arclient.removeActivityUpdates(pIntent);
        arclient.disconnect();
    }
}

@Override
public void onStart(Intent intent, int startid) {
    Log.d(TAG, "FamilyWatcherService onStart");
    processStart();
}

@Override  
public int onStartCommand(Intent intent, int flags, int startId) {  
    Log.d(TAG, "FamilyWatcherService onStartCommand");
    processStart();
    return Service.START_STICKY;  
} 

public void processStart() {
    int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
    if (result != ConnectionResult.SUCCESS) {
        Log.d("o3nWatcherLog", "Google Play service is not available (status=" + result + ")");
    }
    else{
        arclient = new ActivityRecognitionClient(getApplicationContext(), this, this);
        arclient.connect();
    }
}

@Override
public void onConnectionFailed(ConnectionResult arg0) {
    Log.d("o3nWatcherLog","Google activity recognition services connection failed");
}

@Override
public void onConnected(Bundle arg0) {
    Log.d("o3nWatcherLog", "FamilyWathcerService onConnected method called...");
    Intent intent = new Intent(this, ActivityRecognitionService.class);
    pIntent = PendingIntent.getService(getApplicationContext(), 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
    arclient.requestActivityUpdates(period, pIntent);
}

@Override
public void onDisconnected() {
    Log.d("o3nWatcherLog", "Google activity recognition services disconnected");
}

}

ActivityRecognitionService.java(该服务的 onHandleIntent() 方法被 Activity Recognition 更新调用)

package org.o3n.android.familywathcer;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import org.json.JSONException;
import org.json.JSONObject;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.location.ActivityRecognitionResult;
import com.google.android.gms.location.DetectedActivity;
import com.google.android.gms.location.LocationClient;

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;

public class ActivityRecognitionService extends IntentService implements ConnectionCallbacks, OnConnectionFailedListener {

private String TAG = "o3nWatcherLog";

private Context context;

private static int activityEvaluation = 0;

//TODO MAKE THESE PREFERENCES
private static final int MIN_RECORD_DISTANCE = 750;
private static final int MIN_RECORD_INTERVAL = 10 * 1000 * 60;
private static final int MIN_POST_INTERVAL = 2 * 1000 * 60;
//END MAKE THESE PREFERENCES

private LocationClient locationClient;

private static Location lastRecordedLocation;

private static int previousActivityCode = DetectedActivity.UNKNOWN;
private int activityCode = -1000;
private int activityConfidence = -1000;


public ActivityRecognitionService() {
    super("My Activity Recognition Service");
}

@Override
protected void onHandleIntent(Intent intent) {
    if(ActivityRecognitionResult.hasResult(intent)){
        ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
        Log.i(TAG, getType(result.getMostProbableActivity().getType()) +"t" + result.getMostProbableActivity().getConfidence());

        this.context = getApplicationContext();
        Log.d("o3nWatcherLog", "ActivityRecognitionService onHandleIntent called...");

        activityConfidence = result.getMostProbableActivity().getConfidence();
        activityCode = result.getMostProbableActivity().getType();

        Log.d("o3nWatcherLog", " ACTIVITY CODE : " + activityCode + " ACTIVITY CONFIDENCE : " + activityConfidence);

        // Evaluate the avtivity recognition result
        evaluateActivityResult();

        // Get current location
        // check Google Play service APK is available and up to date.
        final int googlePlayServiceAvailable = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
        if (googlePlayServiceAvailable != ConnectionResult.SUCCESS) {
            Log.d("o3nWatcherLog", "Google Play service is not available (status=" + result + ")");
        }
        else {
            locationClient = new LocationClient(context, this, this);
            locationClient.connect();
        }
    }
}

    // This method is only used in a log line to have readable status in logs
private String getType(int type){
    if(type == DetectedActivity.UNKNOWN)
        return "UNKNOWN";
    else if(type == DetectedActivity.IN_VEHICLE)
        return "IN_VEHICLE";
    else if(type == DetectedActivity.ON_BICYCLE)
        return "ON_BICYCLE";
    else if(type == DetectedActivity.ON_FOOT)
        return "ON_FOOT";
    else if(type == DetectedActivity.STILL)
        return "STILL";
    else if(type == DetectedActivity.TILTING)
        return "TILTING";
    else
        return "";
}


private void evaluateActivityResult() {
    // (Based on previousActivityCode and current activityCode 
            // assign a value to activityEvaluation)
    // compare activityCode to previousActivityCode
    activityEvaluation = ...;

    previousActivityCode = activityCode;
}

private void actOnEvaluation(Location loc) {

    // Based on activityEvaluation decide to post or not

    if ( activityEvaluation ....) 
        prepareTheLocationJsonAndRecord(loc);
}

private void prepareTheLocationJsonAndRecord(Location loc) {
    // Record the location
}

@Override
public void onConnectionFailed(ConnectionResult arg0) {
    //Toast.makeText(context, "Google location services connection failed", Toast.LENGTH_LONG).show();
    Log.d("o3nWatcherLog","Google location services connection failed");
}

@Override
public void onDisconnected() {
    //Toast.makeText(context, "Google location services disconnected", Toast.LENGTH_LONG).show();
    Log.d("o3nWatcherLog", "Google location services disconnected");
}

@Override
public void onConnected(Bundle arg0) {
    //Toast.makeText(context, "Google location services connected", Toast.LENGTH_LONG).show();
    Log.d("o3nWatcherLog", "Google location services connected");

    Location loc = locationClient.getLastLocation();
    Log.d("o3nWatcherLog", "location= " + loc.toString());

    if (loc!=null)
        actOnEvaluation(loc);
}

}
4

1 回答 1

0

我假设您需要设置一些 Power Wake 锁定以使手机即使在“睡眠”模式下也能处理 GPS 位置。像 WiFi 锁等。当我做类似的事情时,我使用:

    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    if (pm!=null){
        pmWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK+PowerManager.ON_AFTER_RELEASE, APP_TAG);
        pmWakeLock.acquire();
    }

但那是在 GPS 跟踪活动中。您需要根据需要更改 newWakeLock 的参数。也许您正在使用的服务有一些关于它的代码,所以您只需要首先在 Manifest 中声明使用 WakeLock 权限。

于 2014-04-12T19:28:07.713 回答