Статьи

Распознавание активности Android

Функция распознавания активности дает нашему устройству Android возможность обнаруживать различные виды физической активности, такие как ходьба, езда на велосипеде, вождение автомобиля или простоя. Все это благодаря простому использованию API для доступа к Сервисам Google Play , все более важной части программного обеспечения, доступного для всех версий Android.

Как и в статье о геозоне , мы скачаем образец приложения ( ActivityRecognition.zip ) на сайте разработчика Android и начнем играть с ним, в конечном итоге модифицируя его части в соответствии с нашими целями. Мы покажем здесь только самые важные разделы кода.

Первое, что нужно отметить, это то, что нам нужно специальное разрешение для использования распознавания активности:

1
2
3
<!-- Inside manifest file -->
 <uses-permission
    android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>

Как и в случае с геозонами или обновлениями местоположения, мы используем API для запроса Сервисов Google Play, чтобы проанализировать наши данные и предоставить нам результаты. Цепочка вызовов методов для запроса обновлений аналогична цепочке геозон:

  1. Убедитесь, что Сервисы Google Play доступны
  2. В качестве клиента распознавания активности запросите соединение
  3. После подключения Location Services вызывает метод onConnected () в нашем приложении
  4. Продолжить запрос на обновление через Pending Intent, указывающий на IntentService, который мы написали
  5. Службы определения местоположения Google отправляют свои обновления распознавания активности в качестве объектов Intent, используя предоставленный нами PendingIntent. Получите и обработайте обновления в методе onHandleIntent () нашего IntentService.

Образец приложения записывает все обновления в файл журнала, и это нормально, если нам нравятся подобные вещи… хотя более внимательный взгляд на данные позволяет нам понять, что большая часть этого мусора. Нужно ли нам знать, что у нас есть 27% шансов на управление транспортным средством и 7% шансов на велосипеде, когда мы фактически сидим без дела за столом? На самом деле, нет. Нам нужны наиболее важные данные, и в этом случае это будет наиболее вероятное действие:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//..
import com.google.android.gms.location.ActivityRecognitionResult;
import com.google.android.gms.location.DetectedActivity;
 
/**
 * Service that receives ActivityRecognition updates. It receives updates
 * in the background, even if the main Activity is not visible.
 */
public class ActivityRecognitionIntentService extends IntentService { 
  //..
  /**
     * Called when a new activity detection update is available.
     */
    @Override
    protected void onHandleIntent(Intent intent) {
         //...
          // If the intent contains an update
        if (ActivityRecognitionResult.hasResult(intent)) {
            // Get the update
            ActivityRecognitionResult result =
              ActivityRecognitionResult.extractResult(intent);
 
             DetectedActivity mostProbableActivity
                    = result.getMostProbableActivity();
 
             // Get the confidence % (probability)
            int confidence = mostProbableActivity.getConfidence();
 
            // Get the type
            int activityType = mostProbableActivity.getType();
           /* types:
            * DetectedActivity.IN_VEHICLE
            * DetectedActivity.ON_BICYCLE
            * DetectedActivity.ON_FOOT
            * DetectedActivity.STILL
            * DetectedActivity.UNKNOWN
            * DetectedActivity.TILTING
            */
            // process
        }
    }
}

Вместо того чтобы записывать обновления в файл журнала, проще просто сохранить их в памяти (например, в статическом списке в выделенном классе) и отобразить их пользователю нашего приложения. Одним из способов сделать это было бы использование фрагмента для отображения обновлений поверх карты Google. Как отмечалось в предыдущих статьях, фрагменты были представлены в Honeycomb, но также доступны для более старых версий Android через библиотеку поддержки .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
  android:id="@+id/lay_map"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical">
 
<fragment
 android:id="@+id/map"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 class="com.google.android.gms.maps.SupportMapFragment"/>
 
<!-- activity recognition -->
<fragment
 android:id="@+id/ar_fragment"
 android:name="package.to.our.fragment.ActReconFragment"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"/>
 
</FrameLayout>

Как только мы определим наш собственный XML-макет для ActReconFragment и дадим ему прозрачный фон (оставленный читателю в качестве упражнения), мы получим хороший наложенный экран, подобный этому:

pic1

Поскольку мы решили показывать наиболее вероятные действия пользователям нашего приложения, нам нужно, чтобы отображение было динамичным, как прямая трансляция . Для этого мы можем добавить локальную трансляцию в наш сервис:

01
02
03
04
05
06
07
08
09
10
//inside ActivityRecognitionIntentService 's onHandleIntent
Intent broadcastIntent = new Intent();
 
// Give it the category for all intents sent by the Intent Service
broadcastIntent.addCategory(ActivityUtils.CATEGORY_LOCATION_SERVICES);
// Set the action and content for the broadcast intent
broadcastIntent.setAction(ActivityUtils.ACTION_REFRESH_STATUS_LIST);
 
// Broadcast *locally* to other components in this app
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);

Мы используем LocalBroadcastManager (включен в Android 3.0 и выше и в библиотеке поддержки v4 для ранних выпусков). Помимо предоставления собственного макета для размещения панели «Обнаружение активности» поверх карты, единственным новым фрагментом кода, который мы написали, является приведенная выше локальная трансляция. В остальном ниже мы просто переместили код примера приложения во фрагмент и используем хранилище обновлений активности в памяти вместо использования файла журнала. Получатель этой локальной трансляции находится в нашем фрагменте:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//...
public class ActReconFragment extends Fragment{
 
 // Intent filter for incoming broadcasts from the IntentService
 IntentFilter mBroadcastFilter;
 
 // Instance of a local broadcast manager
 private LocalBroadcastManager mBroadcastManager;
 
//...
/**
 * Called when the corresponding Map Activity's
 * onCreate() method has completed.
 */
 @Override
public void onActivityCreated(Bundle savedInstanceState) {
   super.onActivityCreated(savedInstanceState);     
 
  // Set the broadcast receiver intent filer
  mBroadcastManager = LocalBroadcastManager.getInstance(getActivity());
 
  // Create a new Intent filter for the broadcast receiver
  mBroadcastFilter = new IntentFilter(ActivityUtils.ACTION_REFRESH_STATUS_LIST);
  mBroadcastFilter.addCategory(ActivityUtils.CATEGORY_LOCATION_SERVICES);
 
  //...     
}
 
/**
* Broadcast receiver that receives activity update intents
* This receiver is local only. It can't read broadcast Intents from other apps.
*/
BroadcastReceiver updateListReceiver = new BroadcastReceiver() {
   @Override
   public void onReceive(Context context, Intent intent) {
     // When an Intent is received from the update listener IntentService,
     // update the display.
     updateActivityHistory();
   }
};
//...
}

Живые кормовые кадры:
pic2

После того, как мы позаботились о дисплее, нам нужно перейти к другим важным аспектам, например, что делать с этими обновлениями активности. Пример приложения дает нам один пример этого в ActivityRecognitionIntentService :

01
02
03
04
05
06
07
08
09
10
11
if(
   // If the current type is "moving" i.e on foot, bicycle or vehicle
   isMoving(activityType)
   &&
  // The activity has changed from the previous activity
  activityChanged(activityType)
  // The confidence level for the current activity is >= 50%
  && (confidence >= 50)) {
 
  // do something useful
}

Простое получение наиболее вероятного действия может быть приемлемым для отображения целей, но может оказаться недостаточным для того, чтобы приложение действовало на него и делало что-то полезное. Мы должны убедиться, что тип деятельности и соответствующий уровень доверия (то есть вероятность) соответствуют нашим целям. В то время как обнаруженный тип активности «Неизвестно» с уровнем достоверности 52% практически бесполезен, может быть полезно использовать знание о том, что пользователь движется в транспортном средстве, а не ходить пешком: увеличить частоту обновлений местоположения, увеличить карта области доступных достопримечательностей и т. д.

Распознавание активности было добавлено в качестве экспериментальной функции в это приложение геозон . Проверьте это и не стесняйтесь оставлять любые отзывы.

Ссылка: признание активности Android от нашего партнера по JCG Тони Сицилиана в блоге Tony’s Blog .