0

我編寫了一個應用程序來定期(在後臺)記錄用戶的位置。我使用了ActivityRecognitionClient。當收到活動時,它將與之前的活動狀態進行比較,並根據評估記錄(或不記錄)。ActivityRecognitionClient requestActivityUpdates()方法不會在電話狀態爲空時觸發給定的PendingIntent

只要我的手機保持清醒狀態,它就可以按預期工作。 (日誌消息定期出現在eclipse上的LogCat視圖中)每當屏幕熄滅且設備進入待機狀態時,它將停止接收活動識別呼叫。另一方面,我也在平板電腦上安裝了應用程序,即使設備進入待機狀態,它也會持續更新。 (我的手機是通用移動發現btw)

我一直在尋找網絡(包括stackoverflow問題)3天,一直沒能找到任何適合我的東西。我想感謝所有幫助...謝謝...

以下是我的應用程序相關的代碼:

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所以它開始此服務連接到ActivityRecognitionClient並註冊PendingIntend第一次安裝時正在競選。)

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(與活動更新調用。當它工作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()方法是通過行爲識別更新稱呼)

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); 
} 

} 

回答

0

我想你需要設置即使在「睡眠」模式下,某些電源喚醒鎖也可讓手機處理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權限。

+0

我在某個時候試過。這就是爲什麼在清單文件中有WAKE_LOCK權限。我認爲活動的認可應該會喚醒電話。引用「通過定期喚醒設備並讀取短的突發傳感器數據來檢測活動,它只使用低功率傳感器,以便將功耗保持在最低水平。」來自http://developer.android.com/reference/com/google/android/gms/location/ActivityRecognitionClient.html – umutozkan

+0

看起來像一個AOS的困境:需要防止快速的電池耗盡,但也必須做一些工作在BG(我你確定你明白GPS會「吃」電池,這就是爲什麼它在睡眠中被禁用)......所以,也許你需要一個顯示地圖或somethig的活動,以便當你想跟蹤GPS時保持手機與我的代碼類似的狀態,或者在電話睡眠時同意GPS關機。至少試一試。 – Stan

+0

好的谷歌位置服務應該是一個低功耗的GPS替代品。(它從網絡信息創建一個「融合」的位置)這就是爲什麼我不直接訪問GPS。 (此應用的以前版本就是這樣做的)無論如何,即使用戶沒有與手機進行交互,我也需要定期記錄用戶的位置。所以它需要在後臺,因此我需要解決這個睡眠問題。 – umutozkan

相關問題