Кошелек быстрого доступа, Кошелек быстрого доступа, Кошелек быстрого доступа, Кошелек быстрого доступа

Функция кошелька быстрого доступа, доступная в Android 11, позволяет пользователю получать доступ к платежным картам и соответствующим пропускам непосредственно из меню питания. Основные варианты использования включают выбор соответствующего способа оплаты перед выполнением транзакции в терминале NFC и быстрый доступ к рейсам и другим билетам для предстоящих мероприятий.

В Android 12 или более поздней версии функция кошелька быстрого доступа доступна из тени, как показано на рис. 1 и рис. 2.

Функция быстрого доступа к кошельку скрыта
Рис. 1. Функция кошелька быстрого доступа (устройство заблокировано).
Функция быстрого доступа к кошельку скрыта
Рис. 2. Функция кошелька быстрого доступа (устройство разблокировано).

В Android 11 эта функция доступна из меню питания, как показано на рис. 3.

Функция быстрого доступа к кошельку в меню питания
Рис. 3. Функция быстрого доступа к кошельку в меню питания.

Требования

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

Обзор функций

Кошелек быстрого доступа состоит из двух частей: пользовательского интерфейса кошелька быстрого доступа и поставщика карты кошелька быстрого доступа.

В Android 12 или более поздней версии пользовательский интерфейс кошелька работает в пользовательском интерфейсе системы и находится в frameworks/base/packages/SystemUI/src/com/android/systemui/wallet . В Android 11 необходимо установить и внести в белый список пользовательский интерфейс Wallet, расположенный в platform/packages/apps/QuickAccessWallet .

Поставщик карт Quick Access Wallet является платежным приложением NFC по умолчанию. Пользователи могут одновременно установить несколько платежных приложений NFC, но только платежное приложение NFC по умолчанию может отображать карты в меню питания. Вы можете указать, какое приложение для оплаты NFC изначально установлено по умолчанию , но пользователи могут выбрать другое приложение в настройках. Если установлено только одно платежное приложение NFC, оно автоматически становится приложением по умолчанию (см. CardEmulationManager ).

Выполнение

Чтобы предоставлять карты в пользовательском интерфейсе кошелька быстрого доступа, платежные приложения NFC должны реализовать QuickAccessWalletService . Платежные приложения должны содержать запись манифеста, рекламирующую услугу.

Чтобы только системный пользовательский интерфейс мог связываться с QuickAccessWalletService , платежному приложению NFC необходимо разрешение android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE . Требование этого разрешения гарантирует, что только системный пользовательский интерфейс может привязываться к QuickAccessWalletService .

<service
     android:name=".MyQuickAccessWalletService"
     android:label="@string/my_default_tile_label"
     android:icon="@drawable/my_default_icon_label"
     android:logo="@drawable/my_wallet_logo"
     android:permission="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE">
     <intent-filter>
         <action android:name="android.service.quickaccesswallet.QuickAccessWalletService" />
         <category android:name="android.intent.category.DEFAULT"/>
     </intent-filter>
     <meta-data android:name="android.quickaccesswallet"
          android:resource="@xml/quickaccesswallet_configuration" />
     <meta-data
          android:name="android.quickaccesswallet.tile"
          android:resource="@drawable/my_default_tile_icon"/>
</service>

Дополнительная информация о кошельке включена в связанный файл XML:

<quickaccesswallet-service
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:settingsActivity="com.example.android.SettingsActivity"
   android:shortcutLongLabel="@string/my_wallet_empty_state_text"
   android:shortcutShortLabel="@string/my_wallet_button_text"
   android:targetActivity="com.example.android.WalletActivity"/>

Затем платежное приложение должно реализовать QuickAccessWalletService :

public class MyQuickAccessWalletService extends QuickAccessWalletService {

    @Override
    public void onWalletCardsRequested(
            GetWalletCardsRequest request,
            GetWalletCardsCallback callback) {
        GetWalletCardsResponse response = // generate response
        callback.onSuccess(response);
    }

    @Override
    public void onWalletCardSelected(SelectWalletCardRequest request) {
        // selecting a card should ensure that it is used when making an NFC payment
    }

    @Override
    public void onWalletDismissed() {
        // May un-select card if the wallet app has the concept of a 'default'
        // payment method
    }
}

Если HostApduService начинает обрабатывать транзакцию NFC и, как следствие, начинает действие для отображения хода и результата платежа, он также должен попытаться получить ссылку на связанный QuickAccessWalletService и вызвать QuickAccessWalletService#sendEvent с типом события TYPE_NFC_PAYMENT_STARTED . Это приводит к тому, что пользовательский интерфейс кошелька быстрого доступа закрывается, что позволяет пользователю беспрепятственно просматривать платежную активность.

Дополнительную документацию по реализации QuickAccessWalletService см. в разделе QuickAccessWalletService и тест TestQuickAccessWalletService CTS.

Включение пользовательского интерфейса быстрого доступа к кошельку в Android 11

Чтобы настроить кошелек быстрого доступа, чтобы он был доступен из меню питания в Android 11, включите цель QuickAccessWallet в сборку и включите подключаемый модуль globalactions.wallet , добавив строку, выделенную жирным шрифтом в приведенном ниже примере кода, в overlay/frameworks/base/packages/SystemUI/res/values/config.xml .

<resources>
    ...
    <!-- SystemUI Plugins that can be loaded on user builds. -->
    <string-array name="config_pluginWhitelist" translatable="false">
        <item>com.android.systemui</item>
        <item>com.android.systemui.plugin.globalactions.wallet</item>
    </string-array>
</resources>

Укажите платежное приложение NFC по умолчанию в файле конфигурации настроек, используя def_nfc_payment_component .

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

Сведения о реализации QuickAccessWalletService

QuickAccessWalletService имеет три абстрактных метода, которые необходимо реализовать: onWalletCardsRequested , onWalletCardSelected и onWalletDismissed . На приведенной ниже диаграмме последовательности показана последовательность вызовов, когда кошелек быстрого доступа просматривается непосредственно перед платежом NFC.

Диаграмма последовательности операций с кошельком быстрого доступа

Пример последовательности вызовов при просмотре кошелька быстрого доступа
Рис. 4. Пример последовательности вызовов при просмотре кошелька быстрого доступа.

Не все виды кошелька быстрого доступа сопровождаются платежом NFC, но на рис. 4 выше показаны все возможности QuickAccessWalletService . В этом примере поставщик карты кошелька быстрого доступа реализует элементы, обведенные синим цветом. Предполагается, что платежные карты хранятся на устройстве в базе данных и доступны через интерфейс с именем PaymentCardManager . Кроме того, предполагается, что действие под названием PaymentActivity отображает результат платежа NFC. Поток происходит следующим образом:

  1. Пользователь выполняет жест, чтобы вызвать кошелек быстрого доступа.
  2. Пользовательский интерфейс кошелька быстрого доступа (часть пользовательского интерфейса системы) проверяет диспетчер пакетов, чтобы узнать, экспортирует ли платежное приложение NFC по умолчанию QuickAccessWalletService .

    • Если служба не экспортирована, кошелек быстрого доступа не отображается.
  3. Пользовательский интерфейс кошелька быстрого доступа привязывается к QuickAccessWalletService и вызывает onWalletCardsRequested . Этот метод принимает объект запроса, содержащий данные о количестве и размере карт, которые могут быть предоставлены, и обратный вызов. Обратный вызов можно вызвать из фонового потока.

  4. QuickAccessWalletService вычисляет карты, которые он хочет показать, а затем вызывает метод onSuccess для предоставленного обратного вызова. Рекомендуется, чтобы служба выполняла эти действия в фоновом потоке.

  5. Как только карты отображаются, системный пользовательский интерфейс уведомляет QuickAccessWalletService о том, что первая карта была выбрана, путем вызова onWalletCardSelected .

    • onWalletCardSelected вызывается каждый раз, когда пользователь выбирает новую карту.
    • onWalletCardSelected может быть вызван, даже если текущая выбранная карта не изменилась.
  6. Когда пользователь закрывает кошелек быстрого доступа, системный пользовательский интерфейс уведомляет QuickAccessWalletService , вызывая onWalletDismissed .

В приведенном выше примере пользователь подносит телефон к платежному терминалу NFC во время отображения кошелька. Ключевым компонентом обработки платежей NFC является HostApduService , который должен быть реализован для обработки APDU, предоставляемых считывателем NFC (дополнительную информацию см. в разделе Эмуляция карты на основе хоста ). Предполагается, что платежное приложение запускает действие для отображения прогресса и результата взаимодействия с NFC-терминалом. Однако пользовательский интерфейс кошелька быстрого доступа отображается в верхней части окна приложения, а это означает, что платежная активность скрыта пользовательским интерфейсом кошелька быстрого доступа. Чтобы исправить это, приложение должно уведомить пользовательский интерфейс системы о том, что пользовательский интерфейс кошелька быстрого доступа следует закрыть. Это можно сделать, получив ссылку на привязанный QuickAccessWalletService и вызвав sendWalletServiceEvent с типом события TYPE_NFC_PAYMENT_STARTED .

Пример реализации QuickAccessWalletService

/** Sample implementation of {@link QuickAccessWalletService} */
@RequiresApi(VERSION_CODES.R)
public class MyQuickAccessWalletService extends QuickAccessWalletService {

  private static final String TAG = "QAWalletSvc";
  private ExecutorService executor;
  private PaymentCardManager paymentCardManager;

  @Override
  public void onCreate() {
    super.onCreate();
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      Log.w(TAG, "Should not run on pre-R devices");
      stopSelf();
      return;
    }
    executor = Executors.newSingleThreadExecutor();
    paymentCardManager = new PaymentCardManager();
  }

  @Override
  public void onDestroy() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.shutdownNow();
  }

  @Override
  public void onWalletCardsRequested(
      @NonNull GetWalletCardsRequest request, @NonNull GetWalletCardsCallback callback) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(
        () -> {
          List<PaymentCard> paymentCards = paymentCardManager.getCards();
          int maxCards = Math.min(paymentCards.size(), request.getMaxCards());
          List<WalletCard> walletCards = new ArrayList<>(maxCards);
          int selectedIndex = 0;
          int cardWidthPx = request.getCardWidthPx();
          int cardHeightPx = request.getCardHeightPx();
          for (int index = 0; index < maxCards; index++) {
            PaymentCard paymentCard = paymentCards.get(index);
            WalletCard walletCard =
                new WalletCard.Builder(
                        paymentCard.getCardId(),
                        paymentCard.getCardImage(cardWidthPx, cardHeightPx),
                        paymentCard.getContentDescription(),
                        paymentCard.getPendingIntent())
                    .build();
            walletCards.add(walletCard);
            if (paymentCard.isSelected()) {
              selectedIndex = index;
            }
          }
          GetWalletCardsResponse response =
              new GetWalletCardsResponse(walletCards, selectedIndex);
          callback.onSuccess(response);
        });
  }

  @Override
  public void onWalletCardSelected(@NonNull SelectWalletCardRequest request) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(
        () -> paymentCardManager.selectCardById(request.getCardId()));
  }

  @Override
  public void onWalletDismissed() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(() -> {
      paymentCardManager.removeCardOverrides();
    });
  }
}

Дополнительные сведения о QuickAccessWalletService см. в справочнике по API QuickAccessWalletService .

Разрешения

Запись манифеста для QuickAccessWalletService должна требовать разрешения android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE , представленного в Android 11. Это разрешение на уровне подписи, удерживаемое пользовательским интерфейсом системы, что означает, что только процесс пользовательского интерфейса системы может связываться с реализациями QuickAccessWalletService . Имейте в виду, что сторонние приложения могут запросить это разрешение и получить полный доступ к данным QuickAccessWalletService на устройствах под управлением Android 10 или более ранней версии. Чтобы этого не произошло, рекомендуется, чтобы служба проверяла версию сборки в onCreate и включала службу только на устройствах под управлением Android 11 и выше. Никаких других разрешений приложения не требуется, кроме тех, которые необходимы для предоставления платежных услуг с эмуляцией хост-карты.

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

Настройки в Android 12

Чтобы включить или отключить кошелек быстрого доступа с экрана блокировки, пользователи могут использовать переключатель « Показать кошелек» в меню « Настройки » > « Экран » > «Экран блокировки ». Чтобы отключить кошелек в тени, пользователи должны вручную отредактировать его в тени быстрых настроек.

Переключите, чтобы включить или отключить кошелек с экрана блокировки

Рисунок 5. Переключатель отображения кошелька на странице блокировки экрана в настройках.

Настройки в Android 11

Пользователи могут отключить функцию быстрого доступа к кошельку в приложении «Настройки». Страница настроек находится в меню « Настройки » > « Система» > « Жесты » > « Карты и пропуска ».

Страница настроек для включения или отключения функции быстрого доступа к кошельку.
Рисунок 6. Страница настроек для включения или отключения функции быстрого доступа к кошельку.

Настройка

Добавление представления кошелька быстрого доступа в другое место в пользовательском интерфейсе системы

Пользовательский интерфейс кошелька быстрого доступа построен как системный плагин . Хотя реализация AOSP использует его в GlobalActionsDialog (показанном при длительном нажатии кнопки питания), вы можете переместить функцию за другим жестом, пока вы поддерживаете контракт, указанный в интерфейсе плагина.

public interface GlobalActionsPanelPlugin extends Plugin {

  /** Invoked when the view is shown */
  PanelViewController onPanelShown(Callbacks callbacks, boolean deviceLocked);

  /** Callbacks for interacting with the view container */
  interface Callbacks {
    /** Dismisses the view */
    void dismissGlobalActionsMenu();

    /** Starts a PendingIntent, dismissing the keyguard if necessary. */
    void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent);
  }

  /** Provides the Quick Access Wallet view */
  interface PanelViewController {

    /** Returns the QuickAccessWallet view, which may take any size */
    View getPanelContent();

    /** Invoked when the view is dismissed */
    void onDismissed();

    /** Invoked when the device is either locked or unlocked. */
    void onDeviceLockStateChanged(boolean locked);
  }
}

Пользовательский интерфейс кошелька быстрого доступа реализует GlobalActionsPanelPlugin и PanelViewController . GlobalActionsDialog получает экземпляр подключаемого модуля кошелька с помощью com.android.systemui.Dependency :

GlobalActionsPanelPlugin mPanelPlugin =
    Dependency.get(ExtensionController.class)
        .newExtension(GlobalActionsPanelPlugin.class)
        .withPlugin(GlobalActionsPanelPlugin.class)
        .build()
        .get();

После проверки того, что подключаемый модуль не является нулевым и что PanelViewController , возвращаемый onPanelShown , не является нулевым, диалоговое окно прикрепляет View , предоставленное getPanelContent , к своему собственному View и предоставляет соответствующие обратные вызовы для системных событий.

// Construct a Wallet PanelViewController.
// `this` implements GlobalActionsPanelPlugin.Callbacks
GlobalActionsPanelPlugin.PanelViewController mPanelController =
    mPanelPlugin.onPanelShown(this, !mKeyguardStateController.isUnlocked());

// Attach the view
FrameLayout panelContainer = findViewById(R.id.my_panel_container);
FrameLayout.LayoutParams panelParams =
    new FrameLayout.LayoutParams(
        FrameLayout.LayoutParams.MATCH_PARENT,
        FrameLayout.LayoutParams.MATCH_PARENT);
panelContainer.addView(mPanelController.getPanelContent(), panelParams);

// Respond to unlock events (if the view can be accessed while the phone is locked)
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
  @Override
  public void onUnlockedChanged() {
    boolean unlocked = keyguardStateController.isUnlocked()
        || keyguardStateController.canDismissLockScreen();
    mPanelController.onDeviceLockStateChanged(unlocked);
  }
});

// Implement GlobalActionsPanelPlugin.Callbacks
@Override
public void dismissGlobalActionsMenu() {
  dismissDialog();
}
@Override
public void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
  mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
}

// Notify the wallet when the container view is dismissed
mPanelController.onDismissed();

Чтобы удалить кошелек быстрого доступа из меню питания, исключите цель QuickAccessWallet из сборки системы. Чтобы удалить кошелек быстрого доступа из меню питания, но добавить его в другое представление системного пользовательского интерфейса, включите цель сборки и удалите ссылки на подключаемый модуль GlobalActionsPanelPlugin из GlobalActionsImpl .

Настройка конфигураций по умолчанию

Андроид 12

В Android 12 или более поздней версии кошелек быстрого доступа всегда виден в тени быстрых настроек. Видимость кошелька быстрого доступа на экране блокировки ограничивается следующей настройкой безопасности: LOCKSCREEN_SHOW_WALLET . Этот параметр определяет, отображается ли значок кошелька быстрого доступа в правом нижнем углу экрана блокировки. По умолчанию для этого параметра установлено значение true , но пользователь может отключить его в меню « Настройки » > « Экран » > «Экран блокировки » > « Показать кошелек» .

Андроид 11

В Android 11 видимость кошелька быстрого доступа определяется двумя параметрами безопасности: GLOBAL_ACTIONS_PANEL_ENABLED и GLOBAL_ACTIONS_PANEL_AVAILABLE . Параметр « AVAILABLE » определяет, можно ли включать и выключать эту функцию в настройках. WalletPluginService устанавливает для этого параметра значение true . Если QuickAccessWallet не включен в сборку, параметр остается false . Для параметра ENABLED установлено значение true по умолчанию в том же месте, но пользователь может отключить его в Настройках. Чтобы изменить поведение по умолчанию, измените WalletPluginService#enableFeatureInSettings .

Проверка

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

CTS-тесты

Запустите тесты CTS, расположенные по адресу cts/tests/quickaccesswallet .

Ручные тесты для Android 12

Для тестирования основных функций кошелька быстрого доступа требуется платежный терминал NFC (настоящий или поддельный) и платежное приложение NFC, реализующее QuickAccessWalletService (приложение кошелька). Основные функции, которые необходимо протестировать, включают: доступность, нулевое состояние, выбор карты и поведение экрана блокировки.

Доступность

  • Если платежное приложение NFC по умолчанию не поддерживает эту функцию, кошелек быстрого доступа недоступен ни в быстрых настройках, ни на экране блокировки.
  • Если платежное приложение NFC по умолчанию поддерживает эту функцию, кошелек быстрого доступа доступен в тени быстрых настроек.
  • Если платежное приложение NFC по умолчанию поддерживает эту функцию и если для параметра LOCKSCREEN_SHOW_WALLET установлено значение true , кошелек быстрого доступа доступен на экране блокировки.
  • Если платежное приложение NFC по умолчанию поддерживает эту функцию, а для параметра LOCKSCREEN_SHOW_WALLET установлено значение false , кошелек быстрого доступа недоступен на экране блокировки.

Нулевое состояние

  • Если QuickAccessWalletService включен и экспортирован, но не предоставляет никаких карт, плитка в тени выглядит так, как показано в примере на рис. 7. При нажатии на плитку открывается платежное приложение NFC по умолчанию.

    Пример плитки в тени, показывающий приложение для оплаты NFC по умолчанию

    Рис. 7. Пример плитки в тени, показывающий приложение для оплаты NFC по умолчанию.

  • При нажатии на пустое представление состояния, как показано на рис. 8, открывается платежное приложение NFC по умолчанию. Это пустое представление состояния отображается только тогда, когда у пользователя осталась одна карта в кошельке, он удаляет карту со страницы сведений о карте, а затем возвращается к представлению кошелька.

  • На экране блокировки отображается значок кошелька.

Пустое представление состояния в кошельке быстрого доступа

Рис. 8. Представление пустого состояния в пользовательском интерфейсе кошелька быстрого доступа.

Ненулевое состояние

  • Если приложение кошелька предоставляет одну или несколько карт, плитка в тени выглядит так, как показано на рис. 9.

    Пример плитки в тени, когда в приложении кошелька есть одна или несколько карт

    Рисунок 9. Пример плитки в тени, когда в приложении кошелька есть одна или несколько карт.

  • При нажатии на плитку отображается карусель карт.

  • На экране блокировки отображается кнопка, которая открывает кошелек быстрого доступа.

    Пользовательский интерфейс кошелька быстрого доступа с отображаемой картой

    Рис. 10. Пользовательский интерфейс кошелька быстрого доступа с отображаемой картой.

  • Если отображаемая карта представляет собой способ оплаты NFC, поднесение телефона к платежному терминалу NFC приводит к тому, что используется этот способ оплаты, и представление кошелька закрывается.

  • Щелкнув отображаемую карточку, вы откроете подробную информацию об этой карточке.

  • Если QuickAccessWalletService предоставляет несколько карт, пользователь может переключаться между картами.

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

Тесты состояния блокировки

  • Если телефон заблокирован, кошелек отображается в панели быстрых настроек с описанием « Добавить карту , если в платежном приложении по умолчанию нет карты», или « Разблокировать для использования , если карты существуют в платежном приложении по умолчанию».
  • Если телефон заблокирован, видимость кошелька на экране блокировки контролируется параметром Secure.LOCKSCREEN_SHOW_WALLET , который управляется в настройках.
  • Если телефон заблокирован, LOCKSCREEN_SHOW_WALLET имеет значение false , а в платежном приложении NFC по умолчанию нет карты, кошелек не отображается на экране блокировки.
  • Если телефон заблокирован, LOCKSCREEN_SHOW_WALLET имеет значение true , а в платежном приложении NFC по умолчанию нет карты, кошелек не отображается на экране блокировки.
  • Если телефон заблокирован, LOCKSCREEN_SHOW_WALLET имеет значение true и карты существуют в платежном приложении NFC по умолчанию, кошелек отображается на экране блокировки.
  • Разблокировка телефона, когда кошелек отображается на экране блокировки, приводит к повторному запросу карт, что может привести к другому содержимому карт.

Тесты доступности

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

Ручные тесты для Android 11

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

Доступность

  • Если для параметра GLOBAL_ACTIONS_PANEL_ENABLED установлено значение true , а платежное приложение NFC по умолчанию поддерживает эту функцию, кошелек быстрого доступа доступен.
  • Если для параметра GLOBAL_ACTIONS_PANEL_ENABLED установлено значение false , а платежное приложение NFC по умолчанию поддерживает эту функцию, кошелек быстрого доступа будет недоступен.
  • Если для параметра GLOBAL_ACTIONS_PANEL_ENABLED установлено значение true , а платежное приложение NFC по умолчанию не поддерживает эту функцию, кошелек быстрого доступа недоступен .
  • Если для параметра GLOBAL_ACTIONS_PANEL_ENABLED установлено значение false , а платежное приложение NFC по умолчанию не поддерживает эту функцию, кошелек быстрого доступа будет недоступен.

Нулевое состояние

  • Если QuickAccessWalletService включена и экспортирована, но не предоставляет никаких карточек, пользовательский интерфейс кошелька быстрого доступа отображает пустое представление состояния.
  • При нажатии на пустое представление состояния открывается приложение кошелька.

    Пустое представление состояния в пользовательском интерфейсе кошелька быстрого доступа
    Рис. 11. Представление пустого состояния в пользовательском интерфейсе кошелька быстрого доступа.

Ненулевое состояние

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

    Пользовательский интерфейс кошелька быстрого доступа с отображаемой картой
    Рис. 12. Пользовательский интерфейс кошелька быстрого доступа с отображаемой картой.
  • Если отображаемая карта представляет собой способ оплаты NFC, поднесение телефона к платежному терминалу NFC приводит к тому, что используется этот способ оплаты, и представление кошелька закрывается.

  • Щелкнув отображаемую карту, вы закроете представление кошелька и откроете подробную информацию о действиях для этой карты.

  • Если QuickAccessWalletService предоставляет несколько карт, пользователь может переключаться между картами.

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

Тесты состояния блокировки

  • Если телефон заблокирован, видимость кошелька контролируется Settings.Secure.POWER_MENU_LOCK_SHOW_CONTENT , которым можно управлять в настройках.
  • Если телефон заблокирован и POWER_MENU_LOCK_SHOW_CONTENT имеет значение false , бумажник не отображается.
  • Если телефон заблокирован и POWER_MENU_LOCK_SHOW_CONTENT установлено значение true , кошелек отображается.
  • Разблокировка телефона, когда кошелек отображается на экране блокировки, приводит к повторному запросу карт, что может привести к другому содержимому карт.

Тесты доступности

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

Функция кошелька быстрого доступа, доступная в Android 11, позволяет пользователю получать доступ к платежным картам и соответствующим пропускам непосредственно из меню питания. Основные варианты использования включают выбор соответствующего способа оплаты перед выполнением транзакции в терминале NFC и быстрый доступ к рейсам и другим билетам для предстоящих мероприятий.

В Android 12 или более поздней версии функция кошелька быстрого доступа доступна из тени, как показано на рис. 1 и рис. 2.

Функция быстрого доступа к кошельку скрыта
Рис. 1. Функция кошелька быстрого доступа (устройство заблокировано).
Функция быстрого доступа к кошельку скрыта
Рис. 2. Функция кошелька быстрого доступа (устройство разблокировано).

В Android 11 эта функция доступна из меню питания, как показано на рис. 3.

Функция быстрого доступа к кошельку в меню питания
Рис. 3. Функция быстрого доступа к кошельку в меню питания.

Требования

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

Обзор функций

Кошелек быстрого доступа состоит из двух частей: пользовательского интерфейса кошелька быстрого доступа и поставщика карты кошелька быстрого доступа.

В Android 12 или более поздней версии пользовательский интерфейс кошелька работает в пользовательском интерфейсе системы и находится в frameworks/base/packages/SystemUI/src/com/android/systemui/wallet . В Android 11 необходимо установить и внести в белый список пользовательский интерфейс Wallet, расположенный в platform/packages/apps/QuickAccessWallet .

Поставщик карт Quick Access Wallet является платежным приложением NFC по умолчанию. Пользователи могут одновременно установить несколько платежных приложений NFC, но только платежное приложение NFC по умолчанию может отображать карты в меню питания. Вы можете указать, какое приложение для оплаты NFC изначально установлено по умолчанию , но пользователи могут выбрать другое приложение в настройках. Если установлено только одно платежное приложение NFC, оно автоматически становится приложением по умолчанию (см. CardEmulationManager ).

Выполнение

Чтобы предоставлять карты в пользовательском интерфейсе кошелька быстрого доступа, платежные приложения NFC должны реализовать QuickAccessWalletService . Платежные приложения должны содержать запись манифеста, рекламирующую услугу.

Чтобы только системный пользовательский интерфейс мог связываться с QuickAccessWalletService , платежному приложению NFC необходимо разрешение android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE . Требование этого разрешения гарантирует, что только системный пользовательский интерфейс может привязываться к QuickAccessWalletService .

<service
     android:name=".MyQuickAccessWalletService"
     android:label="@string/my_default_tile_label"
     android:icon="@drawable/my_default_icon_label"
     android:logo="@drawable/my_wallet_logo"
     android:permission="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE">
     <intent-filter>
         <action android:name="android.service.quickaccesswallet.QuickAccessWalletService" />
         <category android:name="android.intent.category.DEFAULT"/>
     </intent-filter>
     <meta-data android:name="android.quickaccesswallet"
          android:resource="@xml/quickaccesswallet_configuration" />
     <meta-data
          android:name="android.quickaccesswallet.tile"
          android:resource="@drawable/my_default_tile_icon"/>
</service>

Дополнительная информация о кошельке включена в связанный файл XML:

<quickaccesswallet-service
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:settingsActivity="com.example.android.SettingsActivity"
   android:shortcutLongLabel="@string/my_wallet_empty_state_text"
   android:shortcutShortLabel="@string/my_wallet_button_text"
   android:targetActivity="com.example.android.WalletActivity"/>

Затем платежное приложение должно реализовать QuickAccessWalletService :

public class MyQuickAccessWalletService extends QuickAccessWalletService {

    @Override
    public void onWalletCardsRequested(
            GetWalletCardsRequest request,
            GetWalletCardsCallback callback) {
        GetWalletCardsResponse response = // generate response
        callback.onSuccess(response);
    }

    @Override
    public void onWalletCardSelected(SelectWalletCardRequest request) {
        // selecting a card should ensure that it is used when making an NFC payment
    }

    @Override
    public void onWalletDismissed() {
        // May un-select card if the wallet app has the concept of a 'default'
        // payment method
    }
}

Если HostApduService начинает обрабатывать транзакцию NFC и, как следствие, начинает действие для отображения хода и результата платежа, он также должен попытаться получить ссылку на связанный QuickAccessWalletService и вызвать QuickAccessWalletService#sendEvent с типом события TYPE_NFC_PAYMENT_STARTED . Это приводит к тому, что пользовательский интерфейс кошелька быстрого доступа закрывается, что позволяет пользователю беспрепятственно просматривать платежную активность.

Дополнительную документацию по реализации QuickAccessWalletService см. в разделе QuickAccessWalletService и тест TestQuickAccessWalletService CTS.

Включение пользовательского интерфейса быстрого доступа к кошельку в Android 11

Чтобы настроить кошелек быстрого доступа, чтобы он был доступен из меню питания в Android 11, включите цель QuickAccessWallet в сборку и включите подключаемый модуль globalactions.wallet , добавив строку, выделенную жирным шрифтом в приведенном ниже примере кода, в overlay/frameworks/base/packages/SystemUI/res/values/config.xml .

<resources>
    ...
    <!-- SystemUI Plugins that can be loaded on user builds. -->
    <string-array name="config_pluginWhitelist" translatable="false">
        <item>com.android.systemui</item>
        <item>com.android.systemui.plugin.globalactions.wallet</item>
    </string-array>
</resources>

Укажите платежное приложение NFC по умолчанию в файле конфигурации настроек, используя def_nfc_payment_component .

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

Сведения о реализации QuickAccessWalletService

QuickAccessWalletService имеет три абстрактных метода, которые необходимо реализовать: onWalletCardsRequested , onWalletCardSelected и onWalletDismissed . На приведенной ниже диаграмме последовательности показана последовательность вызовов, когда кошелек быстрого доступа просматривается непосредственно перед платежом NFC.

Диаграмма последовательности операций с кошельком быстрого доступа

Пример последовательности вызовов при просмотре кошелька быстрого доступа
Рис. 4. Пример последовательности вызовов при просмотре кошелька быстрого доступа.

Не все виды кошелька быстрого доступа сопровождаются платежом NFC, но на рис. 4 выше показаны все возможности QuickAccessWalletService . В этом примере поставщик карты кошелька быстрого доступа реализует элементы, обведенные синим цветом. Предполагается, что платежные карты хранятся на устройстве в базе данных и доступны через интерфейс с именем PaymentCardManager . Кроме того, предполагается, что действие под названием PaymentActivity отображает результат платежа NFC. Поток происходит следующим образом:

  1. Пользователь выполняет жест, чтобы вызвать кошелек быстрого доступа.
  2. Пользовательский интерфейс кошелька быстрого доступа (часть пользовательского интерфейса системы) проверяет диспетчер пакетов, чтобы узнать, экспортирует ли платежное приложение NFC по умолчанию QuickAccessWalletService .

    • Если служба не экспортирована, кошелек быстрого доступа не отображается.
  3. Пользовательский интерфейс кошелька быстрого доступа привязывается к QuickAccessWalletService и вызывает onWalletCardsRequested . Этот метод принимает объект запроса, содержащий данные о количестве и размере карт, которые могут быть предоставлены, и обратный вызов. Обратный вызов можно вызвать из фонового потока.

  4. QuickAccessWalletService вычисляет карты, которые он хочет показать, а затем вызывает метод onSuccess для предоставленного обратного вызова. Рекомендуется, чтобы служба выполняла эти действия в фоновом потоке.

  5. Как только карты отображаются, системный пользовательский интерфейс уведомляет QuickAccessWalletService о том, что первая карта была выбрана, путем вызова onWalletCardSelected .

    • onWalletCardSelected вызывается каждый раз, когда пользователь выбирает новую карту.
    • onWalletCardSelected может быть вызван, даже если текущая выбранная карта не изменилась.
  6. Когда пользователь закрывает кошелек быстрого доступа, системный пользовательский интерфейс уведомляет QuickAccessWalletService , вызывая onWalletDismissed .

В приведенном выше примере пользователь подносит телефон к платежному терминалу NFC во время отображения кошелька. Ключевым компонентом обработки платежей NFC является HostApduService , который должен быть реализован для обработки APDU, предоставляемых считывателем NFC (дополнительную информацию см. в разделе Эмуляция карты на основе хоста ). Предполагается, что платежное приложение запускает действие для отображения прогресса и результата взаимодействия с NFC-терминалом. Однако пользовательский интерфейс кошелька быстрого доступа отображается в верхней части окна приложения, а это означает, что платежная активность скрыта пользовательским интерфейсом кошелька быстрого доступа. Чтобы исправить это, приложение должно уведомить пользовательский интерфейс системы о том, что пользовательский интерфейс кошелька быстрого доступа следует закрыть. Это можно сделать, получив ссылку на привязанный QuickAccessWalletService и вызвав sendWalletServiceEvent с типом события TYPE_NFC_PAYMENT_STARTED .

Пример реализации QuickAccessWalletService

/** Sample implementation of {@link QuickAccessWalletService} */
@RequiresApi(VERSION_CODES.R)
public class MyQuickAccessWalletService extends QuickAccessWalletService {

  private static final String TAG = "QAWalletSvc";
  private ExecutorService executor;
  private PaymentCardManager paymentCardManager;

  @Override
  public void onCreate() {
    super.onCreate();
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      Log.w(TAG, "Should not run on pre-R devices");
      stopSelf();
      return;
    }
    executor = Executors.newSingleThreadExecutor();
    paymentCardManager = new PaymentCardManager();
  }

  @Override
  public void onDestroy() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.shutdownNow();
  }

  @Override
  public void onWalletCardsRequested(
      @NonNull GetWalletCardsRequest request, @NonNull GetWalletCardsCallback callback) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(
        () -> {
          List<PaymentCard> paymentCards = paymentCardManager.getCards();
          int maxCards = Math.min(paymentCards.size(), request.getMaxCards());
          List<WalletCard> walletCards = new ArrayList<>(maxCards);
          int selectedIndex = 0;
          int cardWidthPx = request.getCardWidthPx();
          int cardHeightPx = request.getCardHeightPx();
          for (int index = 0; index < maxCards; index++) {
            PaymentCard paymentCard = paymentCards.get(index);
            WalletCard walletCard =
                new WalletCard.Builder(
                        paymentCard.getCardId(),
                        paymentCard.getCardImage(cardWidthPx, cardHeightPx),
                        paymentCard.getContentDescription(),
                        paymentCard.getPendingIntent())
                    .build();
            walletCards.add(walletCard);
            if (paymentCard.isSelected()) {
              selectedIndex = index;
            }
          }
          GetWalletCardsResponse response =
              new GetWalletCardsResponse(walletCards, selectedIndex);
          callback.onSuccess(response);
        });
  }

  @Override
  public void onWalletCardSelected(@NonNull SelectWalletCardRequest request) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(
        () -> paymentCardManager.selectCardById(request.getCardId()));
  }

  @Override
  public void onWalletDismissed() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(() -> {
      paymentCardManager.removeCardOverrides();
    });
  }
}

Дополнительные сведения о QuickAccessWalletService см. в справочнике по API QuickAccessWalletService .

Разрешения

Запись манифеста для QuickAccessWalletService должна требовать разрешения android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE , представленного в Android 11. Это разрешение на уровне подписи, удерживаемое пользовательским интерфейсом системы, что означает, что только процесс пользовательского интерфейса системы может связываться с реализациями QuickAccessWalletService . Имейте в виду, что сторонние приложения могут запросить это разрешение и получить полный доступ к данным QuickAccessWalletService на устройствах под управлением Android 10 или более ранней версии. Чтобы этого не произошло, рекомендуется, чтобы служба проверяла версию сборки в onCreate и включала службу только на устройствах под управлением Android 11 и выше. Никаких других разрешений приложения не требуется, кроме тех, которые необходимы для предоставления платежных услуг с эмуляцией хост-карты.

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

Настройки в Android 12

Чтобы включить или отключить кошелек быстрого доступа с экрана блокировки, пользователи могут использовать переключатель « Показать кошелек» в меню « Настройки » > « Экран » > «Экран блокировки ». Чтобы отключить кошелек в тени, пользователи должны вручную отредактировать его в тени быстрых настроек.

Переключите, чтобы включить или отключить кошелек с экрана блокировки

Рисунок 5. Переключатель отображения кошелька на странице блокировки экрана в настройках.

Настройки в Android 11

Пользователи могут отключить функцию быстрого доступа к кошельку в приложении «Настройки». Страница настроек находится в меню « Настройки » > « Система» > « Жесты » > « Карты и пропуска ».

Страница настроек для включения или отключения функции быстрого доступа к кошельку.
Рисунок 6. Страница настроек для включения или отключения функции быстрого доступа к кошельку.

Настройка

Добавление представления кошелька быстрого доступа в другое место в пользовательском интерфейсе системы

Пользовательский интерфейс кошелька быстрого доступа построен как системный плагин . Хотя реализация AOSP использует его в GlobalActionsDialog (показанном при длительном нажатии кнопки питания), вы можете переместить функцию за другим жестом, пока вы поддерживаете контракт, указанный в интерфейсе плагина.

public interface GlobalActionsPanelPlugin extends Plugin {

  /** Invoked when the view is shown */
  PanelViewController onPanelShown(Callbacks callbacks, boolean deviceLocked);

  /** Callbacks for interacting with the view container */
  interface Callbacks {
    /** Dismisses the view */
    void dismissGlobalActionsMenu();

    /** Starts a PendingIntent, dismissing the keyguard if necessary. */
    void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent);
  }

  /** Provides the Quick Access Wallet view */
  interface PanelViewController {

    /** Returns the QuickAccessWallet view, which may take any size */
    View getPanelContent();

    /** Invoked when the view is dismissed */
    void onDismissed();

    /** Invoked when the device is either locked or unlocked. */
    void onDeviceLockStateChanged(boolean locked);
  }
}

Пользовательский интерфейс кошелька быстрого доступа реализует GlobalActionsPanelPlugin и PanelViewController . GlobalActionsDialog получает экземпляр подключаемого модуля кошелька с помощью com.android.systemui.Dependency :

GlobalActionsPanelPlugin mPanelPlugin =
    Dependency.get(ExtensionController.class)
        .newExtension(GlobalActionsPanelPlugin.class)
        .withPlugin(GlobalActionsPanelPlugin.class)
        .build()
        .get();

После проверки того, что подключаемый модуль не является нулевым и что PanelViewController , возвращаемый onPanelShown , не является нулевым, диалоговое окно прикрепляет View , предоставленное getPanelContent , к своему собственному View и предоставляет соответствующие обратные вызовы для системных событий.

// Construct a Wallet PanelViewController.
// `this` implements GlobalActionsPanelPlugin.Callbacks
GlobalActionsPanelPlugin.PanelViewController mPanelController =
    mPanelPlugin.onPanelShown(this, !mKeyguardStateController.isUnlocked());

// Attach the view
FrameLayout panelContainer = findViewById(R.id.my_panel_container);
FrameLayout.LayoutParams panelParams =
    new FrameLayout.LayoutParams(
        FrameLayout.LayoutParams.MATCH_PARENT,
        FrameLayout.LayoutParams.MATCH_PARENT);
panelContainer.addView(mPanelController.getPanelContent(), panelParams);

// Respond to unlock events (if the view can be accessed while the phone is locked)
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
  @Override
  public void onUnlockedChanged() {
    boolean unlocked = keyguardStateController.isUnlocked()
        || keyguardStateController.canDismissLockScreen();
    mPanelController.onDeviceLockStateChanged(unlocked);
  }
});

// Implement GlobalActionsPanelPlugin.Callbacks
@Override
public void dismissGlobalActionsMenu() {
  dismissDialog();
}
@Override
public void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
  mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
}

// Notify the wallet when the container view is dismissed
mPanelController.onDismissed();

Чтобы удалить кошелек быстрого доступа из меню питания, исключите цель QuickAccessWallet из сборки системы. Чтобы удалить кошелек быстрого доступа из меню питания, но добавить его в другое представление системного пользовательского интерфейса, включите цель сборки и удалите ссылки на подключаемый модуль GlobalActionsPanelPlugin из GlobalActionsImpl .

Настройка конфигураций по умолчанию

Андроид 12

В Android 12 или более поздней версии кошелек быстрого доступа всегда виден в тени быстрых настроек. Видимость кошелька быстрого доступа на экране блокировки ограничивается следующей настройкой безопасности: LOCKSCREEN_SHOW_WALLET . Этот параметр определяет, отображается ли значок кошелька быстрого доступа в правом нижнем углу экрана блокировки. По умолчанию для этого параметра установлено значение true , но пользователь может отключить его в меню « Настройки » > « Экран » > «Экран блокировки » > « Показать кошелек» .

Андроид 11

В Android 11 видимость кошелька быстрого доступа определяется двумя параметрами безопасности: GLOBAL_ACTIONS_PANEL_ENABLED и GLOBAL_ACTIONS_PANEL_AVAILABLE . Параметр « AVAILABLE » определяет, можно ли включать и выключать эту функцию в настройках. WalletPluginService устанавливает для этого параметра значение true . Если QuickAccessWallet не включен в сборку, параметр остается false . Для параметра ENABLED установлено значение true по умолчанию в том же месте, но пользователь может отключить его в Настройках. Чтобы изменить поведение по умолчанию, измените WalletPluginService#enableFeatureInSettings .

Проверка

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

CTS-тесты

Запустите тесты CTS, расположенные по адресу cts/tests/quickaccesswallet .

Ручные тесты для Android 12

Для тестирования основных функций кошелька быстрого доступа требуется платежный терминал NFC (настоящий или поддельный) и платежное приложение NFC, реализующее QuickAccessWalletService (приложение кошелька). Основные функции, которые необходимо протестировать, включают: доступность, нулевое состояние, выбор карты и поведение экрана блокировки.

Доступность

  • Если платежное приложение NFC по умолчанию не поддерживает эту функцию, кошелек быстрого доступа недоступен ни в быстрых настройках, ни на экране блокировки.
  • Если платежное приложение NFC по умолчанию поддерживает эту функцию, кошелек быстрого доступа доступен в тени быстрых настроек.
  • Если платежное приложение NFC по умолчанию поддерживает эту функцию и если для параметра LOCKSCREEN_SHOW_WALLET установлено значение true , кошелек быстрого доступа доступен на экране блокировки.
  • Если платежное приложение NFC по умолчанию поддерживает эту функцию, а для параметра LOCKSCREEN_SHOW_WALLET установлено значение false , кошелек быстрого доступа недоступен на экране блокировки.

Нулевое состояние

  • Если QuickAccessWalletService включен и экспортирован, но не предоставляет никаких карт, плитка в тени выглядит так, как показано в примере на рис. 7. При нажатии на плитку открывается платежное приложение NFC по умолчанию.

    Пример плитки в тени, показывающий приложение для оплаты NFC по умолчанию

    Рис. 7. Пример плитки в тени, показывающий приложение для оплаты NFC по умолчанию.

  • При нажатии на пустое представление состояния, как показано на рис. 8, открывается платежное приложение NFC по умолчанию. Это пустое представление состояния отображается только тогда, когда у пользователя осталась одна карта в кошельке, он удаляет карту со страницы сведений о карте, а затем возвращается к представлению кошелька.

  • На экране блокировки отображается значок кошелька.

Пустое представление состояния в кошельке быстрого доступа

Рис. 8. Представление пустого состояния в пользовательском интерфейсе кошелька быстрого доступа.

Ненулевое состояние

  • Если приложение кошелька предоставляет одну или несколько карт, плитка в тени выглядит так, как показано на рис. 9.

    Пример плитки в тени, когда в приложении кошелька есть одна или несколько карт

    Рисунок 9. Пример плитки в тени, когда в приложении кошелька есть одна или несколько карт.

  • При нажатии на плитку отображается карусель карт.

  • На экране блокировки отображается кнопка, которая открывает кошелек быстрого доступа.

    Пользовательский интерфейс кошелька быстрого доступа с отображаемой картой

    Рис. 10. Пользовательский интерфейс кошелька быстрого доступа с отображаемой картой.

  • If the displayed card represents an NFC payment method, holding the phone to an NFC payment terminal results in that payment method being used and the wallet view is dismissed.

  • Clicking on a displayed card opens the detailed activity for that card.

  • If multiple cards are provided by QuickAccessWalletService , the user is able to swipe between cards.

  • The overflow menu contains one entry: open the lock screen settings so that the user can change the Show wallet option.

Lock state tests

  • If the phone is locked, the wallet is visible on the quick settings shade, with a description of Add a card if no card exists in the default payment app, or unlock to use if cards exist in the default payment app.
  • If the phone is locked, wallet visibility on the lock screen is controlled by the Secure.LOCKSCREEN_SHOW_WALLET setting, which is controlled in Settings.
  • If the phone is locked, LOCKSCREEN_SHOW_WALLET is false , and no card exists in the default NFC payment app, the wallet isn't displayed on the lock screen.
  • If the phone is locked, LOCKSCREEN_SHOW_WALLET is true , and no card exists in the default NFC payment app, the wallet isn't displayed on the lock screen.
  • If the phone is locked, LOCKSCREEN_SHOW_WALLET is true , and cards exist in the default NFC payment app, the wallet is displayed on the lock screen.
  • Unlocking the phone while the wallet is being displayed on the lock screen results in the cards being requeried, which might result in different card content.

Accessibility tests

  • Talkback users can navigate the wallet view by swiping left and right and by listening to the content descriptions of the cards.
  • Swiping left and right with Talkback enabled selects each card in turn. Talkback users can select and use an NFC payment method at an NFC payment terminal.

Manual tests for Android 11

Testing the core features of the Quick Access Wallet requires an NFC payment terminal (real or fake) and an NFC payment app that implements QuickAccessWalletService (wallet app). Core features that must be tested include availability, zero state, card selection, and lock screen behavior.

Availability

  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is true and the default NFC payment app supports the feature, the Quick Access Wallet is accessible.
  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is false and the default NFC payment app supports the feature, the Quick Access Wallet isn't accessible.
  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is true and the default NFC payment app doesn't support the feature, the Quick Access Wallet isn't accessible.
  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is false and the default NFC payment app doesn't support the feature, the Quick Access Wallet isn't accessible.

Zero state

  • If QuickAccessWalletService is enabled and exported but doesn't provide any cards, the Quick Access Wallet UI displays the empty state view.
  • Clicking the empty state view opens the wallet app.

    Empty state view in the Quick Access Wallet UI
    Figure 11. Empty state view in the Quick Access Wallet UI.

Non-zero state

  • If the wallet app provides one or more cards, the cards are displayed in the Quick Access Wallet UI.

    Quick Access Wallet UI with a card displayed
    Figure 12. Quick Access Wallet UI with a card displayed.
  • If the displayed card represents an NFC payment method, holding the phone to an NFC payment terminal results in that payment method being used and the wallet view is dismissed.

  • Clicking a displayed card dismisses the wallet view and opens the detailed activity for that card.

  • If multiple cards are provided by QuickAccessWalletService , the user is able to swipe between cards.

  • The overflow menu contains two entries: one that opens the wallet app and one that opens the Show cards & passes screen in Settings.

Lock state tests

  • If the phone is locked, wallet visibility is controlled by the Settings.Secure.POWER_MENU_LOCK_SHOW_CONTENT setting, which can be controlled in Settings.
  • If the phone is locked and POWER_MENU_LOCK_SHOW_CONTENT is false , the wallet isn't displayed.
  • If the phone is locked and POWER_MENU_LOCK_SHOW_CONTENT is true , the wallet is displayed.
  • Unlocking the phone while the wallet is being displayed on the lock screen results in the cards being re-queried, which might result in different card content.

Accessibility tests

  • TalkBack users can navigate the wallet view by swiping left and right and by listening to the content descriptions of the cards.
  • Swiping left and right with TalkBack enabled selects each card in turn. TalkBack users can select and use an NFC payment method at an NFC payment terminal.
,

The Quick Access Wallet feature, available from Android 11, allows the user to access payment cards and relevant passes directly from the power menu. Major use cases include selecting the appropriate payment method before performing a transaction at an NFC terminal and quickly accessing flights and other passes for upcoming events.

In Android 12 or higher, the Quick Access Wallet feature is available from the shade as shown in Figure 1 and Figure 2.

Quick Access Wallet feature in shade
Figure 1. Quick Access Wallet feature (device locked).
Quick Access Wallet feature in shade
Figure 2. Quick Access Wallet feature (device unlocked).

In Android 11, the feature is available from the power menu as shown in Figure 3.

Quick Access Wallet feature in power menu
Figure 3. Quick Access Wallet feature in power menu.

Requirements

Your device must have NFC to use the Quick Access Wallet feature. The feature binds to QuickAccessWalletService of the default NFC payment app, which means that the device must also support NFC host-based card emulation (HCE) .

Feature overview

There are two parts to the Quick Access Wallet: the Quick Access Wallet UI and the Quick Access Wallet card provider.

In Android 12 or higher, the Wallet UI runs in System UI and is located in frameworks/base/packages/SystemUI/src/com/android/systemui/wallet . In Android 11, the Wallet UI, which is located in platform/packages/apps/QuickAccessWallet , must be installed and whitelisted.

The Quick Access Wallet card provider is the default NFC payment app. Users can have multiple NFC payment apps installed simultaneously, but only the default NFC payment app can show cards on the power menu. You can specify which NFC payment app is set as the default initially, but users can select a different app in Settings. If only one NFC payment app is installed, it becomes the default automatically (see CardEmulationManager ).

Выполнение

To provide cards to the Quick Access Wallet UI, NFC payment apps must implement QuickAccessWalletService . Payment apps must include a manifest entry advertising the service.

To ensure that only the System UI can bind to QuickAccessWalletService , the NFC payment app must require the android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE permission. Requiring this permission ensures that only the System UI can bind to QuickAccessWalletService .

<service
     android:name=".MyQuickAccessWalletService"
     android:label="@string/my_default_tile_label"
     android:icon="@drawable/my_default_icon_label"
     android:logo="@drawable/my_wallet_logo"
     android:permission="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE">
     <intent-filter>
         <action android:name="android.service.quickaccesswallet.QuickAccessWalletService" />
         <category android:name="android.intent.category.DEFAULT"/>
     </intent-filter>
     <meta-data android:name="android.quickaccesswallet"
          android:resource="@xml/quickaccesswallet_configuration" />
     <meta-data
          android:name="android.quickaccesswallet.tile"
          android:resource="@drawable/my_default_tile_icon"/>
</service>

Additional information about the wallet is included in the linked XML file:

<quickaccesswallet-service
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:settingsActivity="com.example.android.SettingsActivity"
   android:shortcutLongLabel="@string/my_wallet_empty_state_text"
   android:shortcutShortLabel="@string/my_wallet_button_text"
   android:targetActivity="com.example.android.WalletActivity"/>

Next, the payment app must implement QuickAccessWalletService :

public class MyQuickAccessWalletService extends QuickAccessWalletService {

    @Override
    public void onWalletCardsRequested(
            GetWalletCardsRequest request,
            GetWalletCardsCallback callback) {
        GetWalletCardsResponse response = // generate response
        callback.onSuccess(response);
    }

    @Override
    public void onWalletCardSelected(SelectWalletCardRequest request) {
        // selecting a card should ensure that it is used when making an NFC payment
    }

    @Override
    public void onWalletDismissed() {
        // May un-select card if the wallet app has the concept of a 'default'
        // payment method
    }
}

If HostApduService starts to handle an NFC transaction and, as a consequence, starts an activity to display the progress and outcome of the payment, it should also try to get a reference to the bound QuickAccessWalletService and call QuickAccessWalletService#sendEvent with an event type of TYPE_NFC_PAYMENT_STARTED . This causes the Quick Access Wallet UI to be dismissed, thus allowing the user an unobstructed view of the payment activity.

For additional documentation on implementing QuickAccessWalletService , see QuickAccessWalletService and the TestQuickAccessWalletService CTS test.

Enabling Quick Access Wallet UI in Android 11

To configure the Quick Access Wallet to be available from the power menu in Android 11, include the QuickAccessWallet target in the build and enable the globalactions.wallet plugin by adding the line in bold in the code sample below to the overlay/frameworks/base/packages/SystemUI/res/values/config.xml file.

<resources>
    ...
    <!-- SystemUI Plugins that can be loaded on user builds. -->
    <string-array name="config_pluginWhitelist" translatable="false">
        <item>com.android.systemui</item>
        <item>com.android.systemui.plugin.globalactions.wallet</item>
    </string-array>
</resources>

Specify the default NFC payment app in the settings configuration file using def_nfc_payment_component .

The default NFC payment app must expose QuickAccessWalletService to provide cards to the Quick Access Wallet. If the default NFC payment app doesn't export this service, the wallet UI is hidden.

QuickAccessWalletService implementation details

QuickAccessWalletService has three abstract methods that must be implemented: onWalletCardsRequested , onWalletCardSelected , and onWalletDismissed . The sequence diagram below illustrates a call sequence when the Quick Access Wallet is viewed immediately preceding an NFC payment.

Quick Access Wallet sequence diagram

Example call sequence when Quick Access Wallet is viewed
Figure 4. Example call sequence when Quick Access Wallet is viewed.

Not all views of the Quick Access Wallet are followed by an NFC payment, but Figure 4 above illustrates all of the capabilities of QuickAccessWalletService . In this example, the Quick Access Wallet card provider implements the elements outlined in blue. It's assumed that payment cards are stored on the device in a database and are accessed through an interface named PaymentCardManager . It's further assumed that an activity called PaymentActivity displays the result of an NFC payment. The flow proceeds as follows:

  1. The user performs a gesture to bring up the Quick Access Wallet.
  2. The Quick Access Wallet UI (part of System UI) checks the package manager to see if the default NFC payment app exports QuickAccessWalletService .

    • If the service isn't exported, the Quick Access Wallet isn't displayed.
  3. The Quick Access Wallet UI binds to the QuickAccessWalletService and calls onWalletCardsRequested . This method takes a request object containing data about the number and size of the cards that can be provided and a callback. The callback can be called from a background thread.

  4. QuickAccessWalletService computes the cards that it wants to show, then calls the onSuccess method on the provided callback. It's recommended that the service perform these actions on a background thread.

  5. As soon as the cards are displayed, the System UI notifies QuickAccessWalletService that the first card has been selected by calling onWalletCardSelected .

    • onWalletCardSelected is called every time the user selects a new card.
    • onWalletCardSelected might be called even if the currently selected card hasn't changed.
  6. When the user dismisses the Quick Access Wallet, the System UI notifies QuickAccessWalletService by calling onWalletDismissed .

In the above example, the user brings the phone into range of an NFC payment terminal while the wallet is being displayed. A key component of handling NFC payments is HostApduService , which must be implemented to process APDUs provided by the NFC reader (for more information, see Host-based card emulation ). It's assumed that the payment app starts an activity to display the progress and result of the interaction with the NFC terminal. However, the Quick Access Wallet UI is displayed on top of the app window, meaning that the payment activity is obscured by the Quick Access Wallet UI. To rectify this, the app must notify the System UI that the Quick Access Wallet UI should be dismissed. It can do so by getting a reference to the bound QuickAccessWalletService and calling sendWalletServiceEvent with the event type TYPE_NFC_PAYMENT_STARTED .

QuickAccessWalletService sample implementation

/** Sample implementation of {@link QuickAccessWalletService} */
@RequiresApi(VERSION_CODES.R)
public class MyQuickAccessWalletService extends QuickAccessWalletService {

  private static final String TAG = "QAWalletSvc";
  private ExecutorService executor;
  private PaymentCardManager paymentCardManager;

  @Override
  public void onCreate() {
    super.onCreate();
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      Log.w(TAG, "Should not run on pre-R devices");
      stopSelf();
      return;
    }
    executor = Executors.newSingleThreadExecutor();
    paymentCardManager = new PaymentCardManager();
  }

  @Override
  public void onDestroy() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.shutdownNow();
  }

  @Override
  public void onWalletCardsRequested(
      @NonNull GetWalletCardsRequest request, @NonNull GetWalletCardsCallback callback) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(
        () -> {
          List<PaymentCard> paymentCards = paymentCardManager.getCards();
          int maxCards = Math.min(paymentCards.size(), request.getMaxCards());
          List<WalletCard> walletCards = new ArrayList<>(maxCards);
          int selectedIndex = 0;
          int cardWidthPx = request.getCardWidthPx();
          int cardHeightPx = request.getCardHeightPx();
          for (int index = 0; index < maxCards; index++) {
            PaymentCard paymentCard = paymentCards.get(index);
            WalletCard walletCard =
                new WalletCard.Builder(
                        paymentCard.getCardId(),
                        paymentCard.getCardImage(cardWidthPx, cardHeightPx),
                        paymentCard.getContentDescription(),
                        paymentCard.getPendingIntent())
                    .build();
            walletCards.add(walletCard);
            if (paymentCard.isSelected()) {
              selectedIndex = index;
            }
          }
          GetWalletCardsResponse response =
              new GetWalletCardsResponse(walletCards, selectedIndex);
          callback.onSuccess(response);
        });
  }

  @Override
  public void onWalletCardSelected(@NonNull SelectWalletCardRequest request) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(
        () -> paymentCardManager.selectCardById(request.getCardId()));
  }

  @Override
  public void onWalletDismissed() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(() -> {
      paymentCardManager.removeCardOverrides();
    });
  }
}

For further details about QuickAccessWalletService , see QuickAccessWalletService API reference .

Permissions

The manifest entry for QuickAccessWalletService must require the android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE permission introduced in Android 11. This is a signature-level permission held by the System UI, which means that only the System UI process can bind to implementations of QuickAccessWalletService . Be aware that side-loaded apps can claim this permission and get full access to QuickAccessWalletService data on devices running Android 10 or lower. To prevent this, it's recommended that the service check the build version in onCreate and enable the service only on devices running Android 11 and higher. No other app permissions are required beyond those necessary to provide host card emulation payment services.

If the default NFC payment app doesn't implement or export QuickAccessWalletService , the Quick Access Wallet UI isn't displayed.

Settings in Android 12

To enable or disable the Quick Access Wallet from the lock screen, users can use the Show wallet toggle in Settings > Display > Lock screen . To disable the wallet in the shade, users must manually edit it in the quick settings shade.

Toggle to enable or disable wallet from lock screen

Figure 5. Show wallet toggle in the Lock screen page in Settings.

Settings in Android 11

Users can turn off the Quick Access Wallet feature from the Settings app. The settings page is found in Settings > System > Gestures > Cards & passes .

Settings page to enable or disable the Quick Access Wallet feature
Figure 6. Settings page to enable or disable the Quick Access Wallet feature.

Customization

Adding Quick Access Wallet view to another location in System UI

The Quick Access Wallet UI is built as a system plugin . Although the AOSP implementation makes use of it in GlobalActionsDialog (shown on long power press), you can move the feature behind a different gesture as long as you maintain the contract specified by the plugin interface.

public interface GlobalActionsPanelPlugin extends Plugin {

  /** Invoked when the view is shown */
  PanelViewController onPanelShown(Callbacks callbacks, boolean deviceLocked);

  /** Callbacks for interacting with the view container */
  interface Callbacks {
    /** Dismisses the view */
    void dismissGlobalActionsMenu();

    /** Starts a PendingIntent, dismissing the keyguard if necessary. */
    void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent);
  }

  /** Provides the Quick Access Wallet view */
  interface PanelViewController {

    /** Returns the QuickAccessWallet view, which may take any size */
    View getPanelContent();

    /** Invoked when the view is dismissed */
    void onDismissed();

    /** Invoked when the device is either locked or unlocked. */
    void onDeviceLockStateChanged(boolean locked);
  }
}

The Quick Access Wallet UI implements GlobalActionsPanelPlugin and PanelViewController . GlobalActionsDialog gets an instance of the wallet plugin by using com.android.systemui.Dependency :

GlobalActionsPanelPlugin mPanelPlugin =
    Dependency.get(ExtensionController.class)
        .newExtension(GlobalActionsPanelPlugin.class)
        .withPlugin(GlobalActionsPanelPlugin.class)
        .build()
        .get();

After checking that the plugin is non-null and that the PanelViewController returned by onPanelShown is non-null, the dialog attaches the View provided by getPanelContent to its own View and provides appropriate callbacks for system events.

// Construct a Wallet PanelViewController.
// `this` implements GlobalActionsPanelPlugin.Callbacks
GlobalActionsPanelPlugin.PanelViewController mPanelController =
    mPanelPlugin.onPanelShown(this, !mKeyguardStateController.isUnlocked());

// Attach the view
FrameLayout panelContainer = findViewById(R.id.my_panel_container);
FrameLayout.LayoutParams panelParams =
    new FrameLayout.LayoutParams(
        FrameLayout.LayoutParams.MATCH_PARENT,
        FrameLayout.LayoutParams.MATCH_PARENT);
panelContainer.addView(mPanelController.getPanelContent(), panelParams);

// Respond to unlock events (if the view can be accessed while the phone is locked)
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
  @Override
  public void onUnlockedChanged() {
    boolean unlocked = keyguardStateController.isUnlocked()
        || keyguardStateController.canDismissLockScreen();
    mPanelController.onDeviceLockStateChanged(unlocked);
  }
});

// Implement GlobalActionsPanelPlugin.Callbacks
@Override
public void dismissGlobalActionsMenu() {
  dismissDialog();
}
@Override
public void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
  mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
}

// Notify the wallet when the container view is dismissed
mPanelController.onDismissed();

To remove the Quick Access Wallet from the power menu, omit the QuickAccessWallet target from the system build. To remove the Quick Access Wallet from the power menu but add it to a different System UI provided view, include the build target and remove references to the GlobalActionsPanelPlugin from GlobalActionsImpl .

Setting default configurations

Android 12

In Android 12 or higher, the Quick Access Wallet is always visible in the quick settings shade. Visibility of the Quick Access Wallet in the lock screen is gated by the following secure setting: LOCKSCREEN_SHOW_WALLET . This setting controls whether the Quick Access Wallet icon is shown on the bottom right of the lock screen. This setting is set to true by default, but can be turned off by the user in Settings > Display > Lock screen > Show wallet .

Android 11

In Android 11, Quick Access Wallet visibility is gated by two secure settings: GLOBAL_ACTIONS_PANEL_ENABLED and GLOBAL_ACTIONS_PANEL_AVAILABLE . The AVAILABLE setting controls whether the feature can be turned on and off in Settings. This setting is set to true by WalletPluginService . If QuickAccessWallet isn't included in the build, then the setting remains false . The ENABLED setting is set to true by default in the same place, but can be turned off by the user in Settings. To change the default behavior, modify WalletPluginService#enableFeatureInSettings .

Проверка

To validate your implementation of the Quick Access Wallet, run CTS and manual tests. Changes to the plugin should also exercise the included robolectric tests .

CTS tests

Run the CTS tests located at cts/tests/quickaccesswallet .

Manual tests for Android 12

Testing the core features of the Quick Access Wallet requires an NFC payment terminal (real or fake) and an NFC payment app that implements QuickAccessWalletService (wallet app). Core features that must be tested include: availability, zero state, card selection, and lock screen behavior.

Availability

  • If the default NFC payment app doesn't support the feature, the Quick Access Wallet isn't accessible in neither the quick settings nor the lock screen.
  • If the default NFC payment app supports the feature, the Quick Access Wallet is accessible in the quick settings shade.
  • If the default NFC payment app supports the feature and if the LOCKSCREEN_SHOW_WALLET setting is true , the Quick Access Wallet is accessible on the lock screen.
  • If the default NFC payment app supports the feature and if the LOCKSCREEN_SHOW_WALLET setting is false , the Quick Access Wallet isn't accessible on the lock screen.

Zero state

  • If QuickAccessWalletService is enabled and exported but doesn't provide any cards, the tile in the Shade appears as shown in the example in Figure 7. Clicking on the tile opens the default NFC payment app.

    Example tile in the shade showing default NFC payment app

    Figure 7. Example tile in the shade showing default NFC payment app.

  • Clicking on the empty state view as shown in Figure 8 opens the default NFC payment app. This empty state view is displayed only when the user has one card left in the wallet, removes the card from the card detail page, and then goes back to the wallet view.

  • The lock screen shows the wallet icon.

Empty state view in the Quick Access Wallet

Figure 8. Empty state view in the Quick Access Wallet UI.

Non-zero state

  • If the wallet app provides one or more cards, the tile in the shade appears as shown in Figure 9.

    Example tile in the shade when wallet app has one or more cards

    Figure 9. Example tile in the shade when wallet app has one or more cards.

  • Clicking on the tile shows a card carousel.

  • The lock screen shows a button that opens the Quick Access Wallet.

    Quick Access Wallet UI with a card displayed

    Figure 10. Quick Access Wallet UI with a card displayed.

  • If the displayed card represents an NFC payment method, holding the phone to an NFC payment terminal results in that payment method being used and the wallet view is dismissed.

  • Clicking on a displayed card opens the detailed activity for that card.

  • If multiple cards are provided by QuickAccessWalletService , the user is able to swipe between cards.

  • The overflow menu contains one entry: open the lock screen settings so that the user can change the Show wallet option.

Lock state tests

  • If the phone is locked, the wallet is visible on the quick settings shade, with a description of Add a card if no card exists in the default payment app, or unlock to use if cards exist in the default payment app.
  • If the phone is locked, wallet visibility on the lock screen is controlled by the Secure.LOCKSCREEN_SHOW_WALLET setting, which is controlled in Settings.
  • If the phone is locked, LOCKSCREEN_SHOW_WALLET is false , and no card exists in the default NFC payment app, the wallet isn't displayed on the lock screen.
  • If the phone is locked, LOCKSCREEN_SHOW_WALLET is true , and no card exists in the default NFC payment app, the wallet isn't displayed on the lock screen.
  • If the phone is locked, LOCKSCREEN_SHOW_WALLET is true , and cards exist in the default NFC payment app, the wallet is displayed on the lock screen.
  • Unlocking the phone while the wallet is being displayed on the lock screen results in the cards being requeried, which might result in different card content.

Accessibility tests

  • Talkback users can navigate the wallet view by swiping left and right and by listening to the content descriptions of the cards.
  • Swiping left and right with Talkback enabled selects each card in turn. Talkback users can select and use an NFC payment method at an NFC payment terminal.

Manual tests for Android 11

Testing the core features of the Quick Access Wallet requires an NFC payment terminal (real or fake) and an NFC payment app that implements QuickAccessWalletService (wallet app). Core features that must be tested include availability, zero state, card selection, and lock screen behavior.

Availability

  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is true and the default NFC payment app supports the feature, the Quick Access Wallet is accessible.
  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is false and the default NFC payment app supports the feature, the Quick Access Wallet isn't accessible.
  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is true and the default NFC payment app doesn't support the feature, the Quick Access Wallet isn't accessible.
  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is false and the default NFC payment app doesn't support the feature, the Quick Access Wallet isn't accessible.

Zero state

  • If QuickAccessWalletService is enabled and exported but doesn't provide any cards, the Quick Access Wallet UI displays the empty state view.
  • Clicking the empty state view opens the wallet app.

    Empty state view in the Quick Access Wallet UI
    Figure 11. Empty state view in the Quick Access Wallet UI.

Non-zero state

  • If the wallet app provides one or more cards, the cards are displayed in the Quick Access Wallet UI.

    Quick Access Wallet UI with a card displayed
    Figure 12. Quick Access Wallet UI with a card displayed.
  • If the displayed card represents an NFC payment method, holding the phone to an NFC payment terminal results in that payment method being used and the wallet view is dismissed.

  • Clicking a displayed card dismisses the wallet view and opens the detailed activity for that card.

  • If multiple cards are provided by QuickAccessWalletService , the user is able to swipe between cards.

  • The overflow menu contains two entries: one that opens the wallet app and one that opens the Show cards & passes screen in Settings.

Lock state tests

  • If the phone is locked, wallet visibility is controlled by the Settings.Secure.POWER_MENU_LOCK_SHOW_CONTENT setting, which can be controlled in Settings.
  • If the phone is locked and POWER_MENU_LOCK_SHOW_CONTENT is false , the wallet isn't displayed.
  • If the phone is locked and POWER_MENU_LOCK_SHOW_CONTENT is true , the wallet is displayed.
  • Unlocking the phone while the wallet is being displayed on the lock screen results in the cards being re-queried, which might result in different card content.

Accessibility tests

  • TalkBack users can navigate the wallet view by swiping left and right and by listening to the content descriptions of the cards.
  • Swiping left and right with TalkBack enabled selects each card in turn. TalkBack users can select and use an NFC payment method at an NFC payment terminal.
,

The Quick Access Wallet feature, available from Android 11, allows the user to access payment cards and relevant passes directly from the power menu. Major use cases include selecting the appropriate payment method before performing a transaction at an NFC terminal and quickly accessing flights and other passes for upcoming events.

In Android 12 or higher, the Quick Access Wallet feature is available from the shade as shown in Figure 1 and Figure 2.

Quick Access Wallet feature in shade
Figure 1. Quick Access Wallet feature (device locked).
Quick Access Wallet feature in shade
Figure 2. Quick Access Wallet feature (device unlocked).

In Android 11, the feature is available from the power menu as shown in Figure 3.

Quick Access Wallet feature in power menu
Figure 3. Quick Access Wallet feature in power menu.

Requirements

Your device must have NFC to use the Quick Access Wallet feature. The feature binds to QuickAccessWalletService of the default NFC payment app, which means that the device must also support NFC host-based card emulation (HCE) .

Feature overview

There are two parts to the Quick Access Wallet: the Quick Access Wallet UI and the Quick Access Wallet card provider.

In Android 12 or higher, the Wallet UI runs in System UI and is located in frameworks/base/packages/SystemUI/src/com/android/systemui/wallet . In Android 11, the Wallet UI, which is located in platform/packages/apps/QuickAccessWallet , must be installed and whitelisted.

The Quick Access Wallet card provider is the default NFC payment app. Users can have multiple NFC payment apps installed simultaneously, but only the default NFC payment app can show cards on the power menu. You can specify which NFC payment app is set as the default initially, but users can select a different app in Settings. If only one NFC payment app is installed, it becomes the default automatically (see CardEmulationManager ).

Выполнение

To provide cards to the Quick Access Wallet UI, NFC payment apps must implement QuickAccessWalletService . Payment apps must include a manifest entry advertising the service.

To ensure that only the System UI can bind to QuickAccessWalletService , the NFC payment app must require the android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE permission. Requiring this permission ensures that only the System UI can bind to QuickAccessWalletService .

<service
     android:name=".MyQuickAccessWalletService"
     android:label="@string/my_default_tile_label"
     android:icon="@drawable/my_default_icon_label"
     android:logo="@drawable/my_wallet_logo"
     android:permission="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE">
     <intent-filter>
         <action android:name="android.service.quickaccesswallet.QuickAccessWalletService" />
         <category android:name="android.intent.category.DEFAULT"/>
     </intent-filter>
     <meta-data android:name="android.quickaccesswallet"
          android:resource="@xml/quickaccesswallet_configuration" />
     <meta-data
          android:name="android.quickaccesswallet.tile"
          android:resource="@drawable/my_default_tile_icon"/>
</service>

Additional information about the wallet is included in the linked XML file:

<quickaccesswallet-service
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:settingsActivity="com.example.android.SettingsActivity"
   android:shortcutLongLabel="@string/my_wallet_empty_state_text"
   android:shortcutShortLabel="@string/my_wallet_button_text"
   android:targetActivity="com.example.android.WalletActivity"/>

Next, the payment app must implement QuickAccessWalletService :

public class MyQuickAccessWalletService extends QuickAccessWalletService {

    @Override
    public void onWalletCardsRequested(
            GetWalletCardsRequest request,
            GetWalletCardsCallback callback) {
        GetWalletCardsResponse response = // generate response
        callback.onSuccess(response);
    }

    @Override
    public void onWalletCardSelected(SelectWalletCardRequest request) {
        // selecting a card should ensure that it is used when making an NFC payment
    }

    @Override
    public void onWalletDismissed() {
        // May un-select card if the wallet app has the concept of a 'default'
        // payment method
    }
}

If HostApduService starts to handle an NFC transaction and, as a consequence, starts an activity to display the progress and outcome of the payment, it should also try to get a reference to the bound QuickAccessWalletService and call QuickAccessWalletService#sendEvent with an event type of TYPE_NFC_PAYMENT_STARTED . This causes the Quick Access Wallet UI to be dismissed, thus allowing the user an unobstructed view of the payment activity.

For additional documentation on implementing QuickAccessWalletService , see QuickAccessWalletService and the TestQuickAccessWalletService CTS test.

Enabling Quick Access Wallet UI in Android 11

To configure the Quick Access Wallet to be available from the power menu in Android 11, include the QuickAccessWallet target in the build and enable the globalactions.wallet plugin by adding the line in bold in the code sample below to the overlay/frameworks/base/packages/SystemUI/res/values/config.xml file.

<resources>
    ...
    <!-- SystemUI Plugins that can be loaded on user builds. -->
    <string-array name="config_pluginWhitelist" translatable="false">
        <item>com.android.systemui</item>
        <item>com.android.systemui.plugin.globalactions.wallet</item>
    </string-array>
</resources>

Specify the default NFC payment app in the settings configuration file using def_nfc_payment_component .

The default NFC payment app must expose QuickAccessWalletService to provide cards to the Quick Access Wallet. If the default NFC payment app doesn't export this service, the wallet UI is hidden.

QuickAccessWalletService implementation details

QuickAccessWalletService has three abstract methods that must be implemented: onWalletCardsRequested , onWalletCardSelected , and onWalletDismissed . The sequence diagram below illustrates a call sequence when the Quick Access Wallet is viewed immediately preceding an NFC payment.

Quick Access Wallet sequence diagram

Example call sequence when Quick Access Wallet is viewed
Figure 4. Example call sequence when Quick Access Wallet is viewed.

Not all views of the Quick Access Wallet are followed by an NFC payment, but Figure 4 above illustrates all of the capabilities of QuickAccessWalletService . In this example, the Quick Access Wallet card provider implements the elements outlined in blue. It's assumed that payment cards are stored on the device in a database and are accessed through an interface named PaymentCardManager . It's further assumed that an activity called PaymentActivity displays the result of an NFC payment. The flow proceeds as follows:

  1. The user performs a gesture to bring up the Quick Access Wallet.
  2. The Quick Access Wallet UI (part of System UI) checks the package manager to see if the default NFC payment app exports QuickAccessWalletService .

    • If the service isn't exported, the Quick Access Wallet isn't displayed.
  3. The Quick Access Wallet UI binds to the QuickAccessWalletService and calls onWalletCardsRequested . This method takes a request object containing data about the number and size of the cards that can be provided and a callback. The callback can be called from a background thread.

  4. QuickAccessWalletService computes the cards that it wants to show, then calls the onSuccess method on the provided callback. It's recommended that the service perform these actions on a background thread.

  5. As soon as the cards are displayed, the System UI notifies QuickAccessWalletService that the first card has been selected by calling onWalletCardSelected .

    • onWalletCardSelected is called every time the user selects a new card.
    • onWalletCardSelected might be called even if the currently selected card hasn't changed.
  6. When the user dismisses the Quick Access Wallet, the System UI notifies QuickAccessWalletService by calling onWalletDismissed .

In the above example, the user brings the phone into range of an NFC payment terminal while the wallet is being displayed. A key component of handling NFC payments is HostApduService , which must be implemented to process APDUs provided by the NFC reader (for more information, see Host-based card emulation ). It's assumed that the payment app starts an activity to display the progress and result of the interaction with the NFC terminal. However, the Quick Access Wallet UI is displayed on top of the app window, meaning that the payment activity is obscured by the Quick Access Wallet UI. To rectify this, the app must notify the System UI that the Quick Access Wallet UI should be dismissed. It can do so by getting a reference to the bound QuickAccessWalletService and calling sendWalletServiceEvent with the event type TYPE_NFC_PAYMENT_STARTED .

QuickAccessWalletService sample implementation

/** Sample implementation of {@link QuickAccessWalletService} */
@RequiresApi(VERSION_CODES.R)
public class MyQuickAccessWalletService extends QuickAccessWalletService {

  private static final String TAG = "QAWalletSvc";
  private ExecutorService executor;
  private PaymentCardManager paymentCardManager;

  @Override
  public void onCreate() {
    super.onCreate();
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      Log.w(TAG, "Should not run on pre-R devices");
      stopSelf();
      return;
    }
    executor = Executors.newSingleThreadExecutor();
    paymentCardManager = new PaymentCardManager();
  }

  @Override
  public void onDestroy() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.shutdownNow();
  }

  @Override
  public void onWalletCardsRequested(
      @NonNull GetWalletCardsRequest request, @NonNull GetWalletCardsCallback callback) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(
        () -> {
          List<PaymentCard> paymentCards = paymentCardManager.getCards();
          int maxCards = Math.min(paymentCards.size(), request.getMaxCards());
          List<WalletCard> walletCards = new ArrayList<>(maxCards);
          int selectedIndex = 0;
          int cardWidthPx = request.getCardWidthPx();
          int cardHeightPx = request.getCardHeightPx();
          for (int index = 0; index < maxCards; index++) {
            PaymentCard paymentCard = paymentCards.get(index);
            WalletCard walletCard =
                new WalletCard.Builder(
                        paymentCard.getCardId(),
                        paymentCard.getCardImage(cardWidthPx, cardHeightPx),
                        paymentCard.getContentDescription(),
                        paymentCard.getPendingIntent())
                    .build();
            walletCards.add(walletCard);
            if (paymentCard.isSelected()) {
              selectedIndex = index;
            }
          }
          GetWalletCardsResponse response =
              new GetWalletCardsResponse(walletCards, selectedIndex);
          callback.onSuccess(response);
        });
  }

  @Override
  public void onWalletCardSelected(@NonNull SelectWalletCardRequest request) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(
        () -> paymentCardManager.selectCardById(request.getCardId()));
  }

  @Override
  public void onWalletDismissed() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
      return;
    }
    executor.submit(() -> {
      paymentCardManager.removeCardOverrides();
    });
  }
}

For further details about QuickAccessWalletService , see QuickAccessWalletService API reference .

Permissions

The manifest entry for QuickAccessWalletService must require the android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE permission introduced in Android 11. This is a signature-level permission held by the System UI, which means that only the System UI process can bind to implementations of QuickAccessWalletService . Be aware that side-loaded apps can claim this permission and get full access to QuickAccessWalletService data on devices running Android 10 or lower. To prevent this, it's recommended that the service check the build version in onCreate and enable the service only on devices running Android 11 and higher. No other app permissions are required beyond those necessary to provide host card emulation payment services.

If the default NFC payment app doesn't implement or export QuickAccessWalletService , the Quick Access Wallet UI isn't displayed.

Settings in Android 12

To enable or disable the Quick Access Wallet from the lock screen, users can use the Show wallet toggle in Settings > Display > Lock screen . To disable the wallet in the shade, users must manually edit it in the quick settings shade.

Toggle to enable or disable wallet from lock screen

Figure 5. Show wallet toggle in the Lock screen page in Settings.

Settings in Android 11

Users can turn off the Quick Access Wallet feature from the Settings app. The settings page is found in Settings > System > Gestures > Cards & passes .

Settings page to enable or disable the Quick Access Wallet feature
Figure 6. Settings page to enable or disable the Quick Access Wallet feature.

Customization

Adding Quick Access Wallet view to another location in System UI

The Quick Access Wallet UI is built as a system plugin . Although the AOSP implementation makes use of it in GlobalActionsDialog (shown on long power press), you can move the feature behind a different gesture as long as you maintain the contract specified by the plugin interface.

public interface GlobalActionsPanelPlugin extends Plugin {

  /** Invoked when the view is shown */
  PanelViewController onPanelShown(Callbacks callbacks, boolean deviceLocked);

  /** Callbacks for interacting with the view container */
  interface Callbacks {
    /** Dismisses the view */
    void dismissGlobalActionsMenu();

    /** Starts a PendingIntent, dismissing the keyguard if necessary. */
    void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent);
  }

  /** Provides the Quick Access Wallet view */
  interface PanelViewController {

    /** Returns the QuickAccessWallet view, which may take any size */
    View getPanelContent();

    /** Invoked when the view is dismissed */
    void onDismissed();

    /** Invoked when the device is either locked or unlocked. */
    void onDeviceLockStateChanged(boolean locked);
  }
}

The Quick Access Wallet UI implements GlobalActionsPanelPlugin and PanelViewController . GlobalActionsDialog gets an instance of the wallet plugin by using com.android.systemui.Dependency :

GlobalActionsPanelPlugin mPanelPlugin =
    Dependency.get(ExtensionController.class)
        .newExtension(GlobalActionsPanelPlugin.class)
        .withPlugin(GlobalActionsPanelPlugin.class)
        .build()
        .get();

After checking that the plugin is non-null and that the PanelViewController returned by onPanelShown is non-null, the dialog attaches the View provided by getPanelContent to its own View and provides appropriate callbacks for system events.

// Construct a Wallet PanelViewController.
// `this` implements GlobalActionsPanelPlugin.Callbacks
GlobalActionsPanelPlugin.PanelViewController mPanelController =
    mPanelPlugin.onPanelShown(this, !mKeyguardStateController.isUnlocked());

// Attach the view
FrameLayout panelContainer = findViewById(R.id.my_panel_container);
FrameLayout.LayoutParams panelParams =
    new FrameLayout.LayoutParams(
        FrameLayout.LayoutParams.MATCH_PARENT,
        FrameLayout.LayoutParams.MATCH_PARENT);
panelContainer.addView(mPanelController.getPanelContent(), panelParams);

// Respond to unlock events (if the view can be accessed while the phone is locked)
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
  @Override
  public void onUnlockedChanged() {
    boolean unlocked = keyguardStateController.isUnlocked()
        || keyguardStateController.canDismissLockScreen();
    mPanelController.onDeviceLockStateChanged(unlocked);
  }
});

// Implement GlobalActionsPanelPlugin.Callbacks
@Override
public void dismissGlobalActionsMenu() {
  dismissDialog();
}
@Override
public void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
  mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
}

// Notify the wallet when the container view is dismissed
mPanelController.onDismissed();

To remove the Quick Access Wallet from the power menu, omit the QuickAccessWallet target from the system build. To remove the Quick Access Wallet from the power menu but add it to a different System UI provided view, include the build target and remove references to the GlobalActionsPanelPlugin from GlobalActionsImpl .

Setting default configurations

Android 12

In Android 12 or higher, the Quick Access Wallet is always visible in the quick settings shade. Visibility of the Quick Access Wallet in the lock screen is gated by the following secure setting: LOCKSCREEN_SHOW_WALLET . This setting controls whether the Quick Access Wallet icon is shown on the bottom right of the lock screen. This setting is set to true by default, but can be turned off by the user in Settings > Display > Lock screen > Show wallet .

Android 11

In Android 11, Quick Access Wallet visibility is gated by two secure settings: GLOBAL_ACTIONS_PANEL_ENABLED and GLOBAL_ACTIONS_PANEL_AVAILABLE . The AVAILABLE setting controls whether the feature can be turned on and off in Settings. This setting is set to true by WalletPluginService . If QuickAccessWallet isn't included in the build, then the setting remains false . The ENABLED setting is set to true by default in the same place, but can be turned off by the user in Settings. To change the default behavior, modify WalletPluginService#enableFeatureInSettings .

Проверка

To validate your implementation of the Quick Access Wallet, run CTS and manual tests. Changes to the plugin should also exercise the included robolectric tests .

CTS tests

Run the CTS tests located at cts/tests/quickaccesswallet .

Manual tests for Android 12

Testing the core features of the Quick Access Wallet requires an NFC payment terminal (real or fake) and an NFC payment app that implements QuickAccessWalletService (wallet app). Core features that must be tested include: availability, zero state, card selection, and lock screen behavior.

Availability

  • If the default NFC payment app doesn't support the feature, the Quick Access Wallet isn't accessible in neither the quick settings nor the lock screen.
  • If the default NFC payment app supports the feature, the Quick Access Wallet is accessible in the quick settings shade.
  • If the default NFC payment app supports the feature and if the LOCKSCREEN_SHOW_WALLET setting is true , the Quick Access Wallet is accessible on the lock screen.
  • If the default NFC payment app supports the feature and if the LOCKSCREEN_SHOW_WALLET setting is false , the Quick Access Wallet isn't accessible on the lock screen.

Zero state

  • If QuickAccessWalletService is enabled and exported but doesn't provide any cards, the tile in the Shade appears as shown in the example in Figure 7. Clicking on the tile opens the default NFC payment app.

    Example tile in the shade showing default NFC payment app

    Figure 7. Example tile in the shade showing default NFC payment app.

  • Clicking on the empty state view as shown in Figure 8 opens the default NFC payment app. This empty state view is displayed only when the user has one card left in the wallet, removes the card from the card detail page, and then goes back to the wallet view.

  • The lock screen shows the wallet icon.

Empty state view in the Quick Access Wallet

Figure 8. Empty state view in the Quick Access Wallet UI.

Non-zero state

  • If the wallet app provides one or more cards, the tile in the shade appears as shown in Figure 9.

    Example tile in the shade when wallet app has one or more cards

    Figure 9. Example tile in the shade when wallet app has one or more cards.

  • Clicking on the tile shows a card carousel.

  • The lock screen shows a button that opens the Quick Access Wallet.

    Quick Access Wallet UI with a card displayed

    Figure 10. Quick Access Wallet UI with a card displayed.

  • If the displayed card represents an NFC payment method, holding the phone to an NFC payment terminal results in that payment method being used and the wallet view is dismissed.

  • Clicking on a displayed card opens the detailed activity for that card.

  • If multiple cards are provided by QuickAccessWalletService , the user is able to swipe between cards.

  • The overflow menu contains one entry: open the lock screen settings so that the user can change the Show wallet option.

Lock state tests

  • If the phone is locked, the wallet is visible on the quick settings shade, with a description of Add a card if no card exists in the default payment app, or unlock to use if cards exist in the default payment app.
  • If the phone is locked, wallet visibility on the lock screen is controlled by the Secure.LOCKSCREEN_SHOW_WALLET setting, which is controlled in Settings.
  • If the phone is locked, LOCKSCREEN_SHOW_WALLET is false , and no card exists in the default NFC payment app, the wallet isn't displayed on the lock screen.
  • If the phone is locked, LOCKSCREEN_SHOW_WALLET is true , and no card exists in the default NFC payment app, the wallet isn't displayed on the lock screen.
  • If the phone is locked, LOCKSCREEN_SHOW_WALLET is true , and cards exist in the default NFC payment app, the wallet is displayed on the lock screen.
  • Unlocking the phone while the wallet is being displayed on the lock screen results in the cards being requeried, which might result in different card content.

Accessibility tests

  • Talkback users can navigate the wallet view by swiping left and right and by listening to the content descriptions of the cards.
  • Swiping left and right with Talkback enabled selects each card in turn. Talkback users can select and use an NFC payment method at an NFC payment terminal.

Manual tests for Android 11

Testing the core features of the Quick Access Wallet requires an NFC payment terminal (real or fake) and an NFC payment app that implements QuickAccessWalletService (wallet app). Core features that must be tested include availability, zero state, card selection, and lock screen behavior.

Availability

  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is true and the default NFC payment app supports the feature, the Quick Access Wallet is accessible.
  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is false and the default NFC payment app supports the feature, the Quick Access Wallet isn't accessible.
  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is true and the default NFC payment app doesn't support the feature, the Quick Access Wallet isn't accessible.
  • If the GLOBAL_ACTIONS_PANEL_ENABLED setting is false and the default NFC payment app doesn't support the feature, the Quick Access Wallet isn't accessible.

Zero state

  • If QuickAccessWalletService is enabled and exported but doesn't provide any cards, the Quick Access Wallet UI displays the empty state view.
  • Clicking the empty state view opens the wallet app.

    Empty state view in the Quick Access Wallet UI
    Figure 11. Empty state view in the Quick Access Wallet UI.

Non-zero state

  • If the wallet app provides one or more cards, the cards are displayed in the Quick Access Wallet UI.

    Quick Access Wallet UI with a card displayed
    Figure 12. Quick Access Wallet UI with a card displayed.
  • If the displayed card represents an NFC payment method, holding the phone to an NFC payment terminal results in that payment method being used and the wallet view is dismissed.

  • Clicking a displayed card dismisses the wallet view and opens the detailed activity for that card.

  • If multiple cards are provided by QuickAccessWalletService , the user is able to swipe between cards.

  • The overflow menu contains two entries: one that opens the wallet app and one that opens the Show cards & passes screen in Settings.

Lock state tests

  • If the phone is locked, wallet visibility is controlled by the Settings.Secure.POWER_MENU_LOCK_SHOW_CONTENT setting, which can be controlled in Settings.
  • If the phone is locked and POWER_MENU_LOCK_SHOW_CONTENT is false , the wallet isn't displayed.
  • If the phone is locked and POWER_MENU_LOCK_SHOW_CONTENT is true , the wallet is displayed.
  • Unlocking the phone while the wallet is being displayed on the lock screen results in the cards being re-queried, which might result in different card content.

Accessibility tests

  • TalkBack users can navigate the wallet view by swiping left and right and by listening to the content descriptions of the cards.
  • Swiping left and right with TalkBack enabled selects each card in turn. TalkBack users can select and use an NFC payment method at an NFC payment terminal.