Кодовая лаборатория API перехода для распознавания действий

1. Введение

Мы повсюду носим с собой телефоны, но до сих пор приложениям было трудно адаптировать свою работу к постоянно меняющейся среде и активности пользователя.

Раньше для этого разработчики тратили ценное инженерное время, комбинируя различные сигналы (местоположение, датчик и т. д.), чтобы определить, когда началась или закончилась такая деятельность, как ходьба или вождение. Хуже того, когда приложения независимо и постоянно проверяют изменения в активности пользователя, время автономной работы страдает.

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

Например, приложение для обмена сообщениями может запросить «Скажите мне, когда пользователь вошел в автомобиль или вышел из него» , чтобы установить статус пользователя как «занят». Аналогично, приложение для обнаружения парковки может спросить: «Скажите мне, когда пользователь вышел из автомобиля и начал идти», чтобы сохранить место парковки пользователя.

В этой лаборатории кода вы узнаете, как использовать API перехода для распознавания действий , чтобы определить, когда пользователь начинает или останавливает какое-либо действие, например ходьбу или бег.

Предварительные условия

Знакомство с разработкой Android и некоторое знакомство с обратными вызовами.

Что вы узнаете

  • Регистрация для перехода активности
  • Обработка этих событий
  • Отмена регистрации для переходов действий, когда они больше не нужны

Что вам понадобится

  • Android-студия Шмель
  • Устройство Android или эмулятор

2. Начало работы

Клонировать репозиторий стартового проекта

Чтобы вы могли начать работу как можно быстрее, мы подготовили для вас стартовый проект. Если у вас установлен git, вы можете просто запустить команду ниже. (Вы можете проверить, набрав git --version в терминале/командной строке и убедиться, что она выполняется правильно.)

 git clone https://github.com/android/codelab-activity_transitionapi

Если у вас нет git, вы можете получить проект в виде zip-файла:

Импортируйте проект

Запустите Android Studio, выберите «Открыть существующий проект Android Studio» на экране приветствия и откройте каталог проекта.

После загрузки проекта вы также можете увидеть предупреждение о том, что Git не отслеживает все ваши локальные изменения. Вы можете нажать « Игнорировать» или « X » в правом верхнем углу. (Вы не будете возвращать какие-либо изменения в репозиторий Git.)

В верхнем левом углу окна проекта вы должны увидеть что-то вроде изображения ниже, если вы находитесь в представлении Android . (Если вы находитесь в представлении «Проект» , вам нужно будет развернуть проект, чтобы увидеть то же самое.)

d2363db913d8e5ad.png

Есть два значка папок ( base и complete ). Каждый из них известен как «модуль».

Обратите внимание, что Android Studio может потребоваться несколько секунд для компиляции проекта в фоновом режиме в первый раз. В это время вы увидите счетчик в строке состояния внизу Android Studio:

c9f23d5336be3cfe.png

Мы рекомендуем дождаться завершения процесса, прежде чем вносить изменения в код. Это позволит Android Studio использовать все необходимые компоненты.

Кроме того, если вы получите сообщение «Перезагрузить, чтобы изменения языка вступили в силу?» или что-то подобное, выберите «Да».

Понять стартовый проект

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

complete модуль можно использовать для проверки вашей работы или для справки, если у вас возникнут какие-либо проблемы.

Обзор ключевых компонентов:

  • MainActivity : содержит весь код, необходимый для распознавания активности.

Настройка эмулятора

Если вам нужна помощь в настройке эмулятора Android, обратитесь к статье «Запуск приложения» .

Запустите стартовый проект

Давайте запустим наше приложение.

  • Подключите Android-устройство к компьютеру или запустите эмулятор.
  • На панели инструментов выберите base конфигурацию из раскрывающегося списка и нажмите кнопку зеленого треугольника (Выполнить) рядом с ней:

a640a291ffaf62ad.png

  • Вы должны увидеть приложение ниже:

f58d4bb92ee77f41.png

  • Приложение больше ничего не делает, кроме печати сообщения. Теперь мы добавим распознавание активности.

Краткое содержание

На этом этапе вы узнали о:

  • Общая настройка кодовой лаборатории.
  • Основы нашего приложения.
  • Как развернуть ваше приложение.

3. Просмотрите библиотеку и добавьте разрешение на манифест.

Чтобы использовать API перехода в своем приложении, вы должны объявить зависимость от API распознавания местоположения и активности Google и указать разрешение com.google.android.gms.permission.ACTIVITY_RECOGNITION в манифесте приложения.

  1. Найдите TODO: просмотрите библиотеку игровых сервисов, необходимую для распознавания активности, в файле build.gradle. На этом шаге (шаг 1) никаких действий не требуется, просто просмотрите требуемую заявленную зависимость. Это должно выглядеть так:
    // TODO: Review play services library required for activity recognition.
    implementation 'com.google.android.gms:play-services-location:19.0.1'
  1. В base модуле найдите TODO: добавьте оба разрешения на распознавание действий в манифест в AndroidManifest.xml и добавьте приведенный ниже код в элемент <manifest> .
<!-- TODO: Add both activity recognition permissions to the manifest. -->
<!-- Required for 28 and below. -->
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<!-- Required for 29+. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

Теперь ваш код должен выглядеть примерно так:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.example.myapp">
<!-- TODO: Add both activity recognition permissions to the manifest. -->
<!-- Required for 28 and below. -->
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<!-- Required for 29+. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

  ...
</manifest>

Как видно из комментариев, вам необходимо добавить второе разрешение для Android 10. Это необходимо для разрешения времени выполнения, которое было добавлено в API версии 29.

Вот и все! Теперь ваше приложение может поддерживать распознавание активности, нам просто нужно добавить код, чтобы получить его.

Запустить приложение

Запустите свое приложение из Android Studio. Оно должно выглядеть точно так же. На самом деле мы еще не добавили никакого кода для отслеживания переходов, это будет в следующем разделе.

4. Проверка/запрос разрешений времени выполнения в Android

Несмотря на то, что у нас есть разрешения для API версии 28 и ниже, нам необходимо поддерживать разрешения среды выполнения в API версии 29 и выше:

  • В MainActivity.java мы проверим, использует ли пользователь Android 10 (29) или новее, и если да, мы проверим разрешения на распознавание активности.
  • Если разрешения не предоставлены, мы отправим пользователя на заставку ( PermissionRationalActivity.java ), объясняющую, почему приложению требуется разрешение, и позволим ему утвердить его.

Просмотр кода, проверяющего версию Android

В base модуле найдите TODO: Проверка проверки для устройств с Android 10 (29+) в MainActivity.java . Вы должны увидеть этот фрагмент кода.

Обратите внимание: в этом разделе нет действий.

// TODO: Review check for devices with Android 10 (29+).
private boolean runningQOrLater =
    android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q;

Как уже говорилось ранее, вам необходимо одобрение разрешения времени выполнения android.permission.ACTIVITY_RECOGNITION в Android 10 и более поздних версиях. Мы используем эту простую проверку, чтобы решить, нужно ли нам проверять разрешения во время выполнения.

При необходимости просмотрите проверку разрешений во время выполнения для распознавания активности.

В base модуле найдите TODO: Проверка разрешения на просмотр для 29+ в MainActivity.java . Вы должны увидеть этот фрагмент кода.

Обратите внимание: в этом разделе нет действий.

// TODO: Review permission check for 29+.
if (runningQOrLater) {

   return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(
           this,
           Manifest.permission.ACTIVITY_RECOGNITION
   );
} else {
   return true;
}

Мы используем переменную, созданную на предыдущем шаге, чтобы узнать, нужно ли нам проверять разрешения во время выполнения.

Для Q и выше мы проверяем и возвращаем результат для разрешения времени выполнения. Это часть более крупного метода под названием activityRecognitionPermissionApproved() который позволяет разработчику одним простым вызовом узнать, нужно ли нам запрашивать разрешение или нет.

Запрос разрешений во время выполнения и включение/отключение переходов распознавания действий.

В base модуле найдите TODO: Включить/Отключить отслеживание активности и при необходимости запросите разрешения в MainActivity.java . Добавьте код ниже после комментария.

// TODO: Enable/Disable activity tracking and ask for permissions if needed.
if (activityRecognitionPermissionApproved()) {

   if (activityTrackingEnabled) {
      disableActivityTransitions();

   } else {
      enableActivityTransitions();
   }

} else {  
   // Request permission and start activity for result. If the permission is approved, we
   // want to make sure we start activity recognition tracking.
   Intent startIntent = new Intent(this, PermissionRationalActivity.class);
   startActivityForResult(startIntent, 0);

}

Здесь мы спрашиваем, одобрено ли признание активности. Если да и распознавание активности уже включено, мы отключаем его. В противном случае мы включаем его.

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

Просмотрите код запроса разрешения

В base модуле найдите TODO: просмотр запроса на разрешение для распознавания активности в PermissionRationalActivity.java . Вы должны увидеть этот фрагмент кода.

Обратите внимание: в этом разделе нет действий.

// TODO: Review permission request for activity recognition.
ActivityCompat.requestPermissions(
             this,
             new String[]{Manifest.permission.ACTIVITY_RECOGNITION},
             PERMISSION_REQUEST_ACTIVITY_RECOGNITION)

Это самая важная часть Мероприятия и часть, требующая проверки. Код запускает запрос разрешения, когда пользователь его запрашивает.

Помимо этого, класс PermissionRationalActivity.java отображает обоснование того, почему пользователь должен утвердить разрешение на распознавание действий (рекомендуемый метод). Пользователь может либо нажать кнопку «Нет, спасибо» , либо кнопку «Продолжить» (которая запускает приведенный выше код).

Не стесняйтесь просмотреть файл, если хотите узнать больше.

5. Зарегистрировать/отменить регистрацию получателя для переходов активности.

Прежде чем мы настроим код распознавания активности, мы хотим убедиться, что наша активность может обрабатывать действия перехода, вызываемые системой.

Создайте BroadcastReceiver для перехода.

В base модуле найдите TODO: Create BroadcastReceiver для прослушивания переходов активности в MainActivity.java . Вставьте фрагмент ниже.

// TODO: Create a BroadcastReceiver to listen for activity transitions.
// The receiver listens for the PendingIntent above that is triggered by the system when an
// activity transition occurs.
mTransitionsReceiver = new TransitionsReceiver();

Зарегистрируйте BroadcastReceiver для перехода

В base модуле найдите TODO: Register BroadcastReceiver для прослушивания переходов активности в MainActivity.java . (Это в onStart() ). Вставьте фрагмент ниже.

// TODO: Register a BroadcastReceiver to listen for activity transitions.
registerReceiver(mTransitionsReceiver, new IntentFilter(TRANSITIONS_RECEIVER_ACTION));

Теперь у нас есть способ получать обновления при возникновении переходов активности через PendingIntent.

Отменить регистрацию BroadcastReceiver

В base модуле найдите приемник перехода активности Unregister, когда пользователь покидает приложение в MainActivity.java . (Он находится в onStop() ). Вставьте фрагмент ниже.

// TODO: Unregister activity transition receiver when user leaves the app.
unregisterReceiver(mTransitionsReceiver);

Лучше всего отменить регистрацию получателя, когда Activity закрывается.

6. Настройте переходы действий и запросите обновления.

Чтобы начать получать обновления о переходе деятельности, необходимо реализовать:

Создайте список ActivitiyTransitions, которым нужно следовать.

Чтобы создать объект ActivityTransitionRequest , необходимо создать список объектов ActivityTransition , которые представляют переход, который вы хотите отслеживать. Объект ActivityTransition включает в себя следующие данные:

  1. Тип действия, представленный классом DetectedActivity . API перехода поддерживает следующие действия:
  1. Тип перехода, представленный классом ActivityTransition . Типы перехода:

В base модуле найдите TODO: Добавить переходы активности для отслеживания в MainActivity.java . Добавьте код ниже после комментария.

// TODO: Add activity transitions to track.
activityTransitionList.add(new ActivityTransition.Builder()
        .setActivityType(DetectedActivity.WALKING)
        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
        .build());
activityTransitionList.add(new ActivityTransition.Builder()
        .setActivityType(DetectedActivity.WALKING)
        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
        .build());
activityTransitionList.add(new ActivityTransition.Builder()
        .setActivityType(DetectedActivity.STILL)
        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
        .build());
activityTransitionList.add(new ActivityTransition.Builder()
        .setActivityType(DetectedActivity.STILL)
        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
        .build());

Этот код добавляет переходы, которые мы хотим отслеживать, в ранее пустой список.

Создайте ожидающее намерение

Как упоминалось ранее, нам нужен PendingIntent если мы хотим получать оповещения о любых изменениях в нашем ActivityTransitionRequest , поэтому, прежде чем мы настроим наш ActivityTransitionRequest , нам нужно создать PendingIntent .

В base модуле найдите TODO: Initialize PendingIntent, который будет запускаться при переходе активности в MainActivity.java . Добавьте код ниже после комментария.

// TODO: Initialize PendingIntent that will be triggered when a activity transition occurs.
Intent intent = new Intent(TRANSITIONS_RECEIVER_ACTION);
mActivityTransitionsPendingIntent =
        PendingIntent.getBroadcast(MainActivity.this, 0, intent, 0);

Теперь у нас есть PendingIntent, который мы можем активировать при возникновении одного из ActivityTransition .

Создайте ActivityTransitionRequest и запросите обновления.

Вы можете создать объект ActivityTransitionRequest , передав список ActivityTransitions классу ActivityTransitionRequest.

В base модуле найдите запрос Create и прослушайте изменения активности в MainActivity.java . Добавьте код ниже после комментария.

// TODO: Create request and listen for activity changes.
ActivityTransitionRequest request = new ActivityTransitionRequest(activityTransitionList);

// Register for Transitions Updates.
Task<Void> task =
        ActivityRecognition.getClient(this)
                .requestActivityTransitionUpdates(request, mActivityTransitionsPendingIntent);


task.addOnSuccessListener(
        new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void result) {
                activityTrackingEnabled = true;
                printToScreen("Transitions Api was successfully registered.");

            }
        });
task.addOnFailureListener(
        new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                printToScreen("Transitions Api could NOT be registered: " + e);
                Log.e(TAG, "Transitions Api could NOT be registered: " + e);

            }
        });

Давайте рассмотрим код. Сначала мы создаем ActivityTransitionRequest из нашего списка переходов активности.

ActivityTransitionRequest request = new ActivityTransitionRequest(activityTransitionList);

Затем мы регистрируемся для получения обновлений перехода активности, передавая ваш экземпляр ActivityTransitionRequest и наш объект PendingIntent, который мы создали на последнем шаге, методу requestActivityTransitionUpdates() . Метод requestActivityTransitionUpdates() возвращает объект Task , успех или неудачу которого можно проверить, как показано в следующем блоке кода:

// Register for Transitions Updates.
Task<Void> task =
        ActivityRecognition.getClient(this)
                .requestActivityTransitionUpdates(request, mActivityTransitionsPendingIntent);


task.addOnSuccessListener(
        new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void result) {
                activityTrackingEnabled = true;
                printToScreen("Transitions Api was successfully registered.");

            }
        });
task.addOnFailureListener(
        new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                printToScreen("Transitions Api could NOT be registered: " + e);
                Log.e(TAG, "Transitions Api could NOT be registered: " + e);

            }
        });

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

Удалить обновления при закрытии приложения

Важно удалять обновления перехода при закрытии приложения.

В base модуле найдите «Остановить прослушивание изменений активности» в файле MainActivity.java . Добавьте код ниже после комментария.

// TODO: Stop listening for activity changes.
ActivityRecognition.getClient(this).removeActivityTransitionUpdates(mActivityTransitionsPendingIntent)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                activityTrackingEnabled = false;
                printToScreen("Transitions successfully unregistered.");
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                printToScreen("Transitions could not be unregistered: " + e);
                Log.e(TAG,"Transitions could not be unregistered: " + e);
            }
        });

Теперь нам нужно вызвать метод, содержащий приведенный выше код, когда приложение закрывается.

В base модуле найдите TODO: отключить переходы действий, когда пользователь покидает приложение в MainActivity.java в onPause() . Добавьте код ниже после комментария.

// TODO: Disable activity transitions when user leaves the app.
if (activityTrackingEnabled) {
    disableActivityTransitions();
}

Вот и все, что касается отслеживания изменений в переходах активности. Теперь нам просто нужно обработать обновления.

7. Обработка событий

Когда происходит запрошенный переход активности, ваше приложение получает обратный вызов Intent . Объект ActivityTransitionResult можно извлечь из намерения, которое включает в себя список объектов ActivityTransitionEvent . События упорядочиваются в хронологическом порядке, например, если приложение запрашивает тип действия IN_VEHICLE при переходах ACTIVITY_TRANSITION_ENTER и ACTIVITY_TRANSITION_EXIT , оно получает объект ActivityTransitionEvent, когда пользователь начинает движение, и еще один объект, когда пользователь переходит к любому другому действию.

Давайте добавим код для обработки этих событий.

В base модуле найдите TODO: Извлечь информацию о переходе активности из прослушивателя в MainActivity.java в onReceive() BroadcastReceiver, который мы создали ранее. Добавьте код ниже после комментария.

// TODO: Extract activity transition information from listener.
if (ActivityTransitionResult.hasResult(intent)) {

    ActivityTransitionResult result = ActivityTransitionResult.extractResult(intent);

    for (ActivityTransitionEvent event : result.getTransitionEvents()) {

        String info = "Transition: " + toActivityString(event.getActivityType()) +
                " (" + toTransitionType(event.getTransitionType()) + ")" + "   " +
                new SimpleDateFormat("HH:mm:ss", Locale.US).format(new Date());

        printToScreen(info);
    }
}

Это преобразует информацию в String и выводит ее на экран.

Вот и все, вы закончили! Попробуйте запустить приложение.

ВАЖНОЕ ПРИМЕЧАНИЕ. Воспроизвести изменения активности на эмуляторе сложно, поэтому мы рекомендуем использовать физическое устройство.

Вы должны иметь возможность отслеживать изменения активности.

Для достижения наилучших результатов установите приложение на физическое устройство и прогуляйтесь. :)

8. Просмотрите код

Вы создали простое приложение, которое отслеживает переходы активности и отображает их на экране.

Не стесняйтесь прочитать код целиком, чтобы просмотреть то, что вы сделали, и получить лучшее представление о том, как он работает вместе.