Android 11 で導入されたクイック アクセス ウォレット機能を使用すると、ユーザーは電源ボタンメニューから支払いカードと関連パスに直接アクセスできます。主なユースケースとしては、NFC デバイスで取引を実行する前に該当の支払い方法を選択する場合や、今後のイベントのフライトなどのパスにすばやくアクセスする場合があります。

要件
クイック アクセス ウォレット機能を使用するには、デバイスに NFC が搭載されていることが必要です。この機能は、デフォルトの NFC 支払いアプリの QuickAccessWalletService
にバインドします。つまり、デバイスは NFC ホストベースのカード エミュレーション(HCE)もサポートする必要があります。
機能の概要
クイック アクセス ウォレットには 2 つの部分があります。それは、クイック アクセス ウォレット UI とクイック アクセス ウォレット カード プロバイダです。
ウォレット UI はシステム UI 内で実行され、platform/packages/apps/QuickAccessWallet
に実装されます。ウォレット UI を電源ボタンメニューに表示するには、パッケージを組み込んでホワイトリストに登録し、クイック アクセス ウォレット カード プロバイダをインストールする以外の変更は必要ありません。
クイック アクセス ウォレット カード プロバイダは、デフォルトの NFC 支払いアプリです。ユーザーは複数の NFC 支払いアプリを同時にインストールできますが、電源ボタンメニューにカードを表示できるのはデフォルトの NFC 支払いアプリだけです。デフォルトに設定する NFC 支払いアプリは出荷前に指定できますが、ユーザーは設定ページで別のアプリを選択できます。インストールされた NFC 支払いアプリが 1 つのみである場合は、そのアプリが自動的にデフォルトになります(CardEmulationManager
を参照)。
実装
クイック アクセス ウォレット UI にカードを提供するには、NFC 支払いアプリに QuickAccessWalletService
を実装する必要があります。支払いアプリには、サービスをアドバタイズするマニフェスト エントリを含める必要があります。
システム UI のみが QuickAccessWalletService
にバインドできるようにするには、NFC 支払いアプリが android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE
権限を要求する必要があります。この権限を要求することにより、システム UI のみが 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" />;
</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
への参照を取得し、イベントタイプ TYPE_NFC_PAYMENT_STARTED
を使用して QuickAccessWalletService#sendEvent
を呼び出す必要もあります。それによってクイック アクセス ウォレット UI が閉じられ、ユーザーは UI に遮られずに支払いアクティビティを見ることができます。
QuickAccessWalletService
の実装方法に関するその他のドキュメントとしては、QuickAccessWalletService
および TestQuickAccessWalletService
CTS テストをご覧ください。
クイック アクセス ウォレット UI の有効化
電源ボタンメニューからクイック アクセス ウォレットを利用できるように構成するには、ビルドに QuickAccessWallet
ターゲットを組み込み、下記のコードサンプルの太字の行を overlay/frameworks/base/packages/SystemUI/res/values/config.xml
ファイルに追加して globalactions.wallet
プラグインを有効にします。
<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>
def_nfc_payment_component
を使用して、設定の構成ファイルにデフォルトの NFC 支払いアプリを指定します。
クイック アクセス ウォレットにカードを提供するには、デフォルトの NFC 支払いアプリが QuickAccessWalletService
を公開する必要があります。デフォルトの NFC 支払いアプリがこのサービスをエクスポートしないと、ウォレット UI は表示されません。
QuickAccessWalletService 実装の詳細
QuickAccessWalletService
に、onWalletCardsRequested
、onWalletCardSelected
、onWalletDismissed
の 3 つの抽象メソッドを実装する必要があります。下記のシーケンス図は、クイック アクセス ウォレットが NFC 支払いの直前に表示されるときの呼び出しシーケンスを示しています。

クイック アクセス ウォレットの表示後に常に NFC 支払いが行われるわけではありませんが、上記の図 2 は QuickAccessWalletService
のすべての機能を示しています。この例では、クイック アクセス ウォレット カード プロバイダは青い枠で囲まれた要素を実装しています。支払いカードはデバイス内のデータベースに保存され、PaymentCardManager
という名前のインターフェースを介してアクセスされると想定しています。さらに、PaymentActivity
という名前のアクティビティによって NFC 支払いの結果が表示されると想定しています。フローは次のように進行します。
- ユーザーがクイック アクセス ウォレットを表示するジェスチャーを行います。
クイック アクセス ウォレット UI(システム UI の一部)がパッケージ マネージャーをチェックし、デフォルトの NFC 支払いアプリが
QuickAccessWalletService
をエクスポートするかどうかを確認します。- サービスがエクスポートされなければ、クイック アクセス ウォレットは表示されません。
クイック アクセス ウォレット UI が
QuickAccessWalletService
にバインドしてonWalletCardsRequested
を呼び出します。このメソッドは、提供可能なカードの数とサイズに関するデータと、コールバックを含むリクエスト オブジェクトを受け取ります。コールバックはバックグラウンド スレッドから呼び出すことができます。QuickAccessWalletService
は表示するカードを計算し、渡されたコールバックでonSuccess
メソッドを呼び出します。サービスはこれらのアクションをバックグラウンド スレッドで実行することが推奨されます。カードが表示されるとすぐにシステム UI は
onWalletCardSelected
を呼び出し、最初のカードが選択されたことをQuickAccessWalletService
に通知します。onWalletCardSelected
は、ユーザーが新しいカードを選択するたびに呼び出されます。- 現在選択されているカードが変更されなくても、
onWalletCardSelected
が呼び出されることがあります。
ユーザーがクイック アクセス ウォレットを閉じると、システム UI が
onWalletDismissed
を呼び出してQuickAccessWalletService
に通知します。
上記の例では、ユーザーはウォレットが表示されている間に、スマートフォンを NFC 支払いデバイスにかざします。NFC 支払いを処理するための重要なコンポーネントは HostApduService
です。これは、NFC リーダーによって提供される APDU を処理するために実装する必要があります(詳しくは、ホストベースのカード エミュレーションをご覧ください)。ここでは、支払いアプリによって NFC デバイスとの通信の進行状況と結果を表示するアクティビティが開始されると想定しています。しかし、クイック アクセス ウォレット UI はアプリ ウィンドウの上に表示されます。つまり、支払いアクティビティがクイック アクセス ウォレット UI によって隠されてしまいます。これを修正するため、アプリはクイック アクセス ウォレット UI を閉じる必要があることをシステム UI に通知しなければなりません。そのためには、バインドされた QuickAccessWalletService
への参照を取得し、イベントタイプ TYPE_NFC_PAYMENT_STARTED
を使用して sendWalletServiceEvent
を呼び出します。
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
の詳細については、QuickAccessWalletService
API リファレンスをご覧ください。
権限
QuickAccessWalletService
のマニフェスト エントリには、Android 11 で導入された android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE
権限が必要です。これはシステム UI が保持する署名レベルの権限です。つまり、システム UI プロセスのみが QuickAccessWalletService
の実装にバインドできることを意味します。サイドロードされたアプリは、この権限を要求することにより、Android 10 以下を実行しているデバイスで QuickAccessWalletService
データへの完全なアクセス権を取得できます。これを防ぐには、サービスが onCreate
でビルド バージョンをチェックし、Android 11 以上を実行しているデバイスでのみサービスを有効にすることが推奨されます。ホストカード エミュレーション支払いサービスを提供するために必要な権限以外のアプリ権限は必要ありません。
デフォルトの NFC 支払いアプリが QuickAccessWalletService
を実装していない場合またはエクスポートしない場合、クイック アクセス ウォレット UI は表示されません。
設定
ユーザーは、設定アプリからクイック アクセス ウォレット機能をオフにできます。設定ページは、[設定] > [システム] > [ジェスチャー] > [カードとパス] にあります。

カスタマイズ
クイック アクセス ウォレットのビューをシステム UI の別の場所に追加する
クイック アクセス ウォレット UI は、システム プラグインとして構築されています。AOSP 実装では GlobalActionsDialog
(長押しで表示されます)でこの UI を使用しますが、プラグイン インターフェースで指定されたコントラクトを維持する限り、この機能を別のジェスチャーに移動できます。
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);
}
}
クイック アクセス ウォレット UI は、GlobalActionsPanelPlugin
と PanelViewController
を実装します。GlobalActionsDialog
は、com.android.systemui.Dependency
を使用してウォレット プラグインのインスタンスを取得します。
GlobalActionsPanelPlugin mPanelPlugin =
Dependency.get(ExtensionController.class)
.newExtension(GlobalActionsPanelPlugin.class)
.withPlugin(GlobalActionsPanelPlugin.class)
.build()
.get();
プラグインが null でないことと、onPanelShown
によって返された PanelViewController
が null ではないことを確認した後、ダイアログはgetPanelContent
によって提供された View
を自身の 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
ターゲットを取り除きます。電源ボタンメニューからクイック アクセス ウォレットを削除してシステム UI が提供する別のビューに追加するには、ビルド ターゲットを組み込んで、GlobalActionsPanelPlugin
への参照を GlobalActionsImpl
から削除します。
デフォルト構成の設定
クイック アクセス ウォレットの可視性は、GLOBAL_ACTIONS_PANEL_ENABLED
と GLOBAL_ACTIONS_PANEL_AVAILABLE
という 2 つの安全な設定によって制御されます。AVAILABLE
設定は、この機能を設定ページでオンまたはオフにできるかどうかを制御します。この設定は、WalletPluginService
によって true
に設定されています。QuickAccessWallet
がビルドに含まれない場合、設定は false
のままです。同じ場所で、ENABLED
設定はデフォルトで true
に設定されていますが、ユーザーは設定ページでオフにできます。デフォルトの動作を変更するには、WalletPluginService#enableFeatureInSettings
を変更します。
検証
クイック アクセス ウォレットの実装を検証するには、CTS テストと手動テストを実施します。プラグインを変更した場合は、付属の robolectric テストも実施する必要があります。
CTS テスト
cts/tests/quickaccesswallet
にある CTS テストを実施します。
手動テスト
クイック アクセス ウォレットのコア機能をテストするには、NFC 支払いデバイス(本物または偽物)と、QuickAccessWalletService
を実装した NFC 支払いアプリ(ウォレット アプリ)が必要です。テストが必要なコア機能には、可用性、ゼロ状態、カード選択、ロック画面の動作などがあります。
可用性
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
が有効になっていてエクスポートされているがカードを提供していない場合、クイック アクセス ウォレット UI は空の状態のビューを表示します。空の状態のビューをクリックすると、ウォレット アプリが開きます。
図 4. クイック アクセス ウォレット UI の空の状態のビュー
ゼロでない状態
ウォレット アプリが 1 つ以上のカードを提供している場合、クイック アクセス ウォレット UI にカードが表示されます。
図 5. カードが表示されたクイック アクセス ウォレット UI 表示されたカードが NFC 支払い方法を表している場合、スマートフォンを NFC 支払いデバイスにかざすと、その支払い方法が使用され、ウォレット ビューが閉じます。
表示されたカードをクリックすると、ウォレット ビューが閉じて、そのカードの詳細アクティビティが開きます。
QuickAccessWalletService
によって複数のカードが提供されている場合、ユーザーはカード間をスワイプできます。オーバーフロー メニューには 2 つのエントリが表示されます。1 つはウォレット アプリを開くエントリで、もう 1 つは設定ページの [カードとパスの表示] 画面を開くエントリです。
ロック状態のテスト
- スマートフォンがロックされている場合、ウォレットの可視性は
Settings.Secure.POWER_MENU_LOCK_SHOW_CONTENT
設定によって制御されます。これは設定ページで管理できます。 - スマートフォンがロックされていて
POWER_MENU_LOCK_SHOW_CONTENT
がfalse
の場合、ウォレットは表示されません。 - スマートフォンがロックされていて、
POWER_MENU_LOCK_SHOW_CONTENT
がtrue
の場合、ウォレットは表示されます。 - ウォレットがロック画面に表示されているときにスマートフォンのロックを解除すると、カードが再度クエリされ、異なるカード コンテンツが作成されることがあります。
ユーザー補助機能のテスト
- TalkBack のユーザーは、左右のスワイプを行い、カードの内容説明を聞くことにより、ウォレット ビューを操作できます。
- TalkBack を有効にして左右にスワイプすると、各カードが順番に選択されます。TalkBack のユーザーは、NFC 支払いデバイスで NFC 支払い方法を選択して使用できます。