Функция распознавания активности дает нашему устройству 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, чтобы проанализировать наши данные и предоставить нам результаты. Цепочка вызовов методов для запроса обновлений аналогична цепочке геозон:
- Убедитесь, что Сервисы Google Play доступны
- В качестве клиента распознавания активности запросите соединение
- После подключения Location Services вызывает метод onConnected () в нашем приложении
- Продолжить запрос на обновление через Pending Intent, указывающий на IntentService, который мы написали
- Службы определения местоположения 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 и дадим ему прозрачный фон (оставленный читателю в качестве упражнения), мы получим хороший наложенный экран, подобный этому:
Поскольку мы решили показывать наиболее вероятные действия пользователям нашего приложения, нам нужно, чтобы отображение было динамичным, как прямая трансляция . Для этого мы можем добавить локальную трансляцию в наш сервис:
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(); } }; //... } |
После того, как мы позаботились о дисплее, нам нужно перейти к другим важным аспектам, например, что делать с этими обновлениями активности. Пример приложения дает нам один пример этого в 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% практически бесполезен, может быть полезно использовать знание о том, что пользователь движется в транспортном средстве, а не ходить пешком: увеличить частоту обновлений местоположения, увеличить карта области доступных достопримечательностей и т. д.
Распознавание активности было добавлено в качестве экспериментальной функции в это приложение геозон . Проверьте это и не стесняйтесь оставлять любые отзывы.