Add QuickAccessWallet API
Adds a new API that allows applications to provide payment cards and other relevant passes to SysUI which are then shown in the Quick Access Wallet (long press on Pixel). See go/aospqaw-dd for details. Bug: 144342153 Test: manual - started device, didn't blow up Test: atest - run from frameworks/base dir Change-Id: I8fef3116e6e4bd1f8a4f5a907892ea8993b49b0e
This commit is contained in:
@@ -39,6 +39,7 @@ package android {
|
||||
field public static final String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
|
||||
field public static final String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
|
||||
field public static final String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
|
||||
field public static final String BIND_QUICK_ACCESS_WALLET_SERVICE = "android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE";
|
||||
field public static final String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
|
||||
field public static final String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
|
||||
field public static final String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
|
||||
@@ -39903,6 +39904,7 @@ package android.provider {
|
||||
field public static final String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
|
||||
field public static final String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
|
||||
field public static final String ACTION_PROCESS_WIFI_EASY_CONNECT_URI = "android.settings.PROCESS_WIFI_EASY_CONNECT_URI";
|
||||
field public static final String ACTION_QUICK_ACCESS_WALLET_SETTINGS = "android.settings.QUICK_ACCESS_WALLET_SETTINGS";
|
||||
field public static final String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
|
||||
field public static final String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
|
||||
field public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
|
||||
@@ -42946,6 +42948,94 @@ package android.service.notification {
|
||||
|
||||
}
|
||||
|
||||
package android.service.quickaccesswallet {
|
||||
|
||||
public final class GetWalletCardsCallback {
|
||||
method public void onFailure(@NonNull android.service.quickaccesswallet.GetWalletCardsError);
|
||||
method public void onSuccess(@NonNull android.service.quickaccesswallet.GetWalletCardsResponse);
|
||||
}
|
||||
|
||||
public final class GetWalletCardsError implements android.os.Parcelable {
|
||||
ctor public GetWalletCardsError(@Nullable android.graphics.drawable.Icon, @Nullable CharSequence);
|
||||
method public int describeContents();
|
||||
method @Nullable public android.graphics.drawable.Icon getIcon();
|
||||
method @Nullable public CharSequence getMessage();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.service.quickaccesswallet.GetWalletCardsError> CREATOR;
|
||||
}
|
||||
|
||||
public final class GetWalletCardsRequest implements android.os.Parcelable {
|
||||
ctor public GetWalletCardsRequest(int, int, int, int);
|
||||
method public int describeContents();
|
||||
method public int getCardHeightPx();
|
||||
method public int getCardWidthPx();
|
||||
method public int getIconSizePx();
|
||||
method public int getMaxCards();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.service.quickaccesswallet.GetWalletCardsRequest> CREATOR;
|
||||
}
|
||||
|
||||
public final class GetWalletCardsResponse implements android.os.Parcelable {
|
||||
ctor public GetWalletCardsResponse(@NonNull java.util.List<android.service.quickaccesswallet.WalletCard>, int);
|
||||
method public int describeContents();
|
||||
method public int getSelectedIndex();
|
||||
method @NonNull public java.util.List<android.service.quickaccesswallet.WalletCard> getWalletCards();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.service.quickaccesswallet.GetWalletCardsResponse> CREATOR;
|
||||
}
|
||||
|
||||
public abstract class QuickAccessWalletService extends android.app.Service {
|
||||
ctor public QuickAccessWalletService();
|
||||
method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
|
||||
method public abstract void onWalletCardSelected(@NonNull android.service.quickaccesswallet.SelectWalletCardRequest);
|
||||
method public abstract void onWalletCardsRequested(@NonNull android.service.quickaccesswallet.GetWalletCardsRequest, @NonNull android.service.quickaccesswallet.GetWalletCardsCallback);
|
||||
method public abstract void onWalletDismissed();
|
||||
method public final void sendWalletServiceEvent(@NonNull android.service.quickaccesswallet.WalletServiceEvent);
|
||||
field public static final String ACTION_DISMISS_WALLET = "android.service.quickaccesswallet.action.DISMISS_WALLET";
|
||||
field public static final String ACTION_VIEW_WALLET = "android.service.quickaccesswallet.action.VIEW_WALLET";
|
||||
field public static final String ACTION_VIEW_WALLET_SETTINGS = "android.service.quickaccesswallet.action.VIEW_WALLET_SETTINGS";
|
||||
field public static final String SERVICE_INTERFACE = "android.service.quickaccesswallet.QuickAccessWalletService";
|
||||
field public static final String SERVICE_META_DATA = "android.quickaccesswallet";
|
||||
}
|
||||
|
||||
public final class SelectWalletCardRequest implements android.os.Parcelable {
|
||||
ctor public SelectWalletCardRequest(@NonNull String);
|
||||
method public int describeContents();
|
||||
method @NonNull public String getCardId();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.service.quickaccesswallet.SelectWalletCardRequest> CREATOR;
|
||||
}
|
||||
|
||||
public final class WalletCard implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @Nullable public android.graphics.drawable.Icon getCardIcon();
|
||||
method @NonNull public String getCardId();
|
||||
method @NonNull public android.graphics.drawable.Icon getCardImage();
|
||||
method @Nullable public CharSequence getCardLabel();
|
||||
method @NonNull public CharSequence getContentDescription();
|
||||
method @NonNull public android.app.PendingIntent getPendingIntent();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.service.quickaccesswallet.WalletCard> CREATOR;
|
||||
}
|
||||
|
||||
public static final class WalletCard.Builder {
|
||||
ctor public WalletCard.Builder(@NonNull String, @NonNull android.graphics.drawable.Icon, @NonNull CharSequence, @NonNull android.app.PendingIntent);
|
||||
method @NonNull public android.service.quickaccesswallet.WalletCard build();
|
||||
method @NonNull public android.service.quickaccesswallet.WalletCard.Builder setCardIcon(@Nullable android.graphics.drawable.Icon);
|
||||
method @NonNull public android.service.quickaccesswallet.WalletCard.Builder setCardLabel(@Nullable CharSequence);
|
||||
}
|
||||
|
||||
public final class WalletServiceEvent implements android.os.Parcelable {
|
||||
ctor public WalletServiceEvent(int);
|
||||
method public int describeContents();
|
||||
method public int getEventType();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.service.quickaccesswallet.WalletServiceEvent> CREATOR;
|
||||
field public static final int TYPE_NFC_PAYMENT_STARTED = 1; // 0x1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.service.quicksettings {
|
||||
|
||||
public final class Tile implements android.os.Parcelable {
|
||||
|
||||
@@ -1968,6 +1968,21 @@ public final class Settings {
|
||||
public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE =
|
||||
"android.settings.REQUEST_SET_AUTOFILL_SERVICE";
|
||||
|
||||
/**
|
||||
* Activity Action: Show screen for controlling the Quick Access Wallet.
|
||||
* <p>
|
||||
* In some cases, a matching Activity may not exist, so ensure you
|
||||
* safeguard against this.
|
||||
* <p>
|
||||
* Input: The Intent's data URI specifies the application package name
|
||||
* to be shown, with the "package" scheme. That is "package:com.my.app".
|
||||
* <p>
|
||||
* Output: Nothing.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||
public static final String ACTION_QUICK_ACCESS_WALLET_SETTINGS =
|
||||
"android.settings.QUICK_ACCESS_WALLET_SETTINGS";
|
||||
|
||||
/**
|
||||
* Activity Action: Show screen for controlling which apps have access on volume directories.
|
||||
* <p>
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Handles response from the {@link QuickAccessWalletService} for {@link GetWalletCardsRequest}
|
||||
*/
|
||||
public final class GetWalletCardsCallback {
|
||||
|
||||
private static final String TAG = "QAWalletCallback";
|
||||
|
||||
private final IQuickAccessWalletServiceCallbacks mCallback;
|
||||
private final Handler mHandler;
|
||||
private boolean mCalled;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
GetWalletCardsCallback(IQuickAccessWalletServiceCallbacks callback, Handler handler) {
|
||||
mCallback = callback;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the Android System that an {@link QuickAccessWalletService#onWalletCardsRequested}
|
||||
* was successfully handled by the service.
|
||||
*
|
||||
* @param response The response contains the list of {@link WalletCard walletCards} to be shown
|
||||
* to the user as well as the index of the card that should initially be
|
||||
* presented as the selected card.
|
||||
*/
|
||||
public void onSuccess(@NonNull GetWalletCardsResponse response) {
|
||||
mHandler.post(() -> onSuccessInternal(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the Android System that an {@link QuickAccessWalletService#onWalletCardsRequested}
|
||||
* could not be handled by the service.
|
||||
*
|
||||
* @param error The error message. <b>Note: </b> this message should <b>not</b> contain PII
|
||||
* (Personally Identifiable Information, such as username or email address).
|
||||
* @throws IllegalStateException if this method or {@link #onSuccess} was already called.
|
||||
*/
|
||||
public void onFailure(@NonNull GetWalletCardsError error) {
|
||||
mHandler.post(() -> onFailureInternal(error));
|
||||
}
|
||||
|
||||
private void onSuccessInternal(GetWalletCardsResponse response) {
|
||||
if (mCalled) {
|
||||
Log.w(TAG, "already called");
|
||||
return;
|
||||
}
|
||||
mCalled = true;
|
||||
try {
|
||||
mCallback.onGetWalletCardsSuccess(response);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error returning wallet cards", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void onFailureInternal(GetWalletCardsError error) {
|
||||
if (mCalled) {
|
||||
Log.w(TAG, "already called");
|
||||
return;
|
||||
}
|
||||
mCalled = true;
|
||||
try {
|
||||
mCallback.onGetWalletCardsFailure(error);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error returning failure message", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
parcelable GetWalletCardsError;
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* Error response for an {@link GetWalletCardsRequest}.
|
||||
*/
|
||||
public final class GetWalletCardsError implements Parcelable {
|
||||
|
||||
private final Icon mIcon;
|
||||
private final CharSequence mMessage;
|
||||
|
||||
/**
|
||||
* Construct a new error response. If provided, the icon and message will be displayed to the
|
||||
* user.
|
||||
*
|
||||
* @param icon an icon to be shown to the user next to the message. Optional.
|
||||
* @param message message to be shown to the user. Optional.
|
||||
*/
|
||||
public GetWalletCardsError(@Nullable Icon icon, @Nullable CharSequence message) {
|
||||
mIcon = icon;
|
||||
mMessage = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
if (mIcon == null) {
|
||||
dest.writeByte((byte) 0);
|
||||
} else {
|
||||
dest.writeByte((byte) 1);
|
||||
mIcon.writeToParcel(dest, flags);
|
||||
}
|
||||
TextUtils.writeToParcel(mMessage, dest, flags);
|
||||
}
|
||||
|
||||
private static GetWalletCardsError readFromParcel(Parcel source) {
|
||||
Icon icon = source.readByte() == 0 ? null : Icon.CREATOR.createFromParcel(source);
|
||||
CharSequence message = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
|
||||
return new GetWalletCardsError(icon, message);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<GetWalletCardsError> CREATOR =
|
||||
new Creator<GetWalletCardsError>() {
|
||||
@Override
|
||||
public GetWalletCardsError createFromParcel(Parcel source) {
|
||||
return readFromParcel(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetWalletCardsError[] newArray(int size) {
|
||||
return new GetWalletCardsError[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An icon that may be displayed with the message to provide a visual indication of why cards
|
||||
* could not be provided in the Quick Access Wallet.
|
||||
*/
|
||||
@Nullable
|
||||
public Icon getIcon() {
|
||||
return mIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* A localized message that may be shown to the user in the event that the wallet cards cannot
|
||||
* be retrieved. <b>Note: </b> this message should <b>not</b> contain PII (Personally
|
||||
* Identifiable Information, such as username or email address).
|
||||
*/
|
||||
@Nullable
|
||||
public CharSequence getMessage() {
|
||||
return mMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
parcelable GetWalletCardsRequest;
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Represents a request to a {@link QuickAccessWalletService} for {@link WalletCard walletCards}.
|
||||
* Wallet cards may represent anything that a user might carry in their wallet -- a credit card,
|
||||
* library card, a transit pass, etc. This request contains the desired size of the card images and
|
||||
* icons as well as the maximum number of cards that may be returned in the {@link
|
||||
* GetWalletCardsResponse}.
|
||||
*
|
||||
* <p>Cards may be displayed with an optional icon and label. The icon and label should communicate
|
||||
* the same idea. For example, if a card can be used at an NFC terminal, the icon could be an NFC
|
||||
* icon and the label could inform the user how to interact with the NFC terminal.
|
||||
*
|
||||
* <p>The maximum number of cards that may be displayed in the wallet is provided in {@link
|
||||
* #getMaxCards()}. The {@link QuickAccessWalletService} may provide up to this many cards in the
|
||||
* {@link GetWalletCardsResponse#getWalletCards()}. If the list of cards provided exceeds this
|
||||
* number, some of the cards may not be shown to the user.
|
||||
*/
|
||||
public final class GetWalletCardsRequest implements Parcelable {
|
||||
|
||||
private final int mCardWidthPx;
|
||||
private final int mCardHeightPx;
|
||||
private final int mIconSizePx;
|
||||
private final int mMaxCards;
|
||||
|
||||
/**
|
||||
* Creates a new GetWalletCardsRequest.
|
||||
*
|
||||
* @param cardWidthPx The width of the card image in pixels.
|
||||
* @param cardHeightPx The height of the card image in pixels.
|
||||
* @param iconSizePx The width and height of the optional card icon in pixels.
|
||||
* @param maxCards The maximum number of cards that may be provided in the response.
|
||||
*/
|
||||
public GetWalletCardsRequest(int cardWidthPx, int cardHeightPx, int iconSizePx, int maxCards) {
|
||||
this.mCardWidthPx = cardWidthPx;
|
||||
this.mCardHeightPx = cardHeightPx;
|
||||
this.mIconSizePx = iconSizePx;
|
||||
this.mMaxCards = maxCards;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mCardWidthPx);
|
||||
dest.writeInt(mCardHeightPx);
|
||||
dest.writeInt(mIconSizePx);
|
||||
dest.writeInt(mMaxCards);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<GetWalletCardsRequest> CREATOR =
|
||||
new Creator<GetWalletCardsRequest>() {
|
||||
@Override
|
||||
public GetWalletCardsRequest createFromParcel(Parcel source) {
|
||||
int cardWidthPx = source.readInt();
|
||||
int cardHeightPx = source.readInt();
|
||||
int iconSizePx = source.readInt();
|
||||
int maxCards = source.readInt();
|
||||
return new GetWalletCardsRequest(cardWidthPx,
|
||||
cardHeightPx,
|
||||
iconSizePx,
|
||||
maxCards);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetWalletCardsRequest[] newArray(int size) {
|
||||
return new GetWalletCardsRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The desired width of the {@link WalletCard#getCardImage()}, in pixels. The dimensions of the
|
||||
* card image are requested so that it may be rendered without scaling.
|
||||
* <p>
|
||||
* The {@code cardWidthPx} and {@code cardHeightPx} should be applied to the size of the {@link
|
||||
* WalletCard#getCardImage()}. The size of the card image is specified so that it may be
|
||||
* rendered accurately and without distortion caused by scaling.
|
||||
*/
|
||||
public int getCardWidthPx() {
|
||||
return mCardWidthPx;
|
||||
}
|
||||
|
||||
/**
|
||||
* The desired height of the {@link WalletCard#getCardImage()}, in pixels. The dimensions of the
|
||||
* card image are requested so that it may be rendered without scaling.
|
||||
*/
|
||||
public int getCardHeightPx() {
|
||||
return mCardHeightPx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wallet cards may be displayed next to an icon. The icon can help to convey additional
|
||||
* information about the state of the card. If the provided icon is a bitmap, its width and
|
||||
* height should equal iconSizePx so that it is rendered without distortion caused by scaling.
|
||||
*/
|
||||
public int getIconSizePx() {
|
||||
return mIconSizePx;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum size of the {@link GetWalletCardsResponse#getWalletCards()}. If the list of cards
|
||||
* exceeds this number, not all cards may be displayed.
|
||||
*/
|
||||
public int getMaxCards() {
|
||||
return mMaxCards;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
parcelable GetWalletCardsResponse;
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The response for an {@link GetWalletCardsRequest} contains a list of wallet cards and the index
|
||||
* of the card that should initially be displayed in the 'selected' position.
|
||||
*/
|
||||
public final class GetWalletCardsResponse implements Parcelable {
|
||||
|
||||
private final List<WalletCard> mWalletCards;
|
||||
private final int mSelectedIndex;
|
||||
|
||||
/**
|
||||
* Construct a new response.
|
||||
*
|
||||
* @param walletCards The list of wallet cards.
|
||||
* @param selectedIndex The index of the card that should be presented as the initially
|
||||
* 'selected' card
|
||||
*/
|
||||
public GetWalletCardsResponse(@NonNull List<WalletCard> walletCards, int selectedIndex) {
|
||||
this.mWalletCards = walletCards;
|
||||
this.mSelectedIndex = selectedIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mWalletCards.size());
|
||||
dest.writeParcelableList(mWalletCards, flags);
|
||||
dest.writeInt(mSelectedIndex);
|
||||
}
|
||||
|
||||
private static GetWalletCardsResponse readFromParcel(Parcel source) {
|
||||
int size = source.readInt();
|
||||
List<WalletCard> walletCards =
|
||||
source.readParcelableList(new ArrayList<>(size), WalletCard.class.getClassLoader());
|
||||
int selectedIndex = source.readInt();
|
||||
return new GetWalletCardsResponse(walletCards, selectedIndex);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<GetWalletCardsResponse> CREATOR =
|
||||
new Creator<GetWalletCardsResponse>() {
|
||||
@Override
|
||||
public GetWalletCardsResponse createFromParcel(Parcel source) {
|
||||
return readFromParcel(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetWalletCardsResponse[] newArray(int size) {
|
||||
return new GetWalletCardsResponse[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The list of {@link WalletCard}s. The size of this list should not exceed {@link
|
||||
* GetWalletCardsRequest#getMaxCards()}.
|
||||
*/
|
||||
@NonNull
|
||||
public List<WalletCard> getWalletCards() {
|
||||
return mWalletCards;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@code selectedIndex} represents the index of the card that should be presented in the
|
||||
* 'selected' position when the cards are initially displayed in the quick access wallet. The
|
||||
* {@code selectedIndex} should be greater than or equal to zero and less than the size of the
|
||||
* list of {@link WalletCard walletCards}, unless the list is empty in which case the {@code
|
||||
* selectedIndex} can take any value. 0 is a nice round number for such cases.
|
||||
*/
|
||||
public int getSelectedIndex() {
|
||||
return mSelectedIndex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.service.quickaccesswallet.GetWalletCardsRequest;
|
||||
import android.service.quickaccesswallet.IQuickAccessWalletServiceCallbacks;
|
||||
import android.service.quickaccesswallet.SelectWalletCardRequest;
|
||||
import android.service.quickaccesswallet.WalletServiceEvent;
|
||||
import android.service.quickaccesswallet.WalletServiceEventListenerRequest;
|
||||
|
||||
/**
|
||||
* Implemented by QuickAccessWalletService in the payment application
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
interface IQuickAccessWalletService {
|
||||
// Request to get cards, which should be provided using the callback.
|
||||
oneway void onWalletCardsRequested(
|
||||
in GetWalletCardsRequest request, in IQuickAccessWalletServiceCallbacks callback);
|
||||
// Indicates that a card has been selected.
|
||||
oneway void onWalletCardSelected(in SelectWalletCardRequest request);
|
||||
// Sent when the wallet is dismissed or closed.
|
||||
oneway void onWalletDismissed();
|
||||
// Register an event listener
|
||||
oneway void registerWalletServiceEventListener(
|
||||
in WalletServiceEventListenerRequest request,
|
||||
in IQuickAccessWalletServiceCallbacks callback);
|
||||
// Unregister an event listener
|
||||
oneway void unregisterWalletServiceEventListener(in WalletServiceEventListenerRequest request);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.service.quickaccesswallet.GetWalletCardsError;
|
||||
import android.service.quickaccesswallet.GetWalletCardsResponse;
|
||||
import android.service.quickaccesswallet.WalletServiceEvent;
|
||||
|
||||
/**
|
||||
* Interface to receive the result of requests to the wallet application.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
interface IQuickAccessWalletServiceCallbacks {
|
||||
// Called in response to onWalletCardsRequested on success. May only be called once per request.
|
||||
oneway void onGetWalletCardsSuccess(in GetWalletCardsResponse response);
|
||||
// Called in response to onWalletCardsRequested when an error occurs. May only be called once
|
||||
// per request.
|
||||
oneway void onGetWalletCardsFailure(in GetWalletCardsError error);
|
||||
// Called in response to registerWalletServiceEventListener. May be called multiple times as
|
||||
// long as the event listener is registered.
|
||||
oneway void onWalletServiceEvent(in WalletServiceEvent event);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Facilitates accessing cards from the {@link QuickAccessWalletService}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface QuickAccessWalletClient {
|
||||
|
||||
/**
|
||||
* Create a client for accessing wallet cards from the {@link QuickAccessWalletService}. If the
|
||||
* service is unavailable, {@link #isWalletServiceAvailable()} will return false.
|
||||
*/
|
||||
@NonNull
|
||||
static QuickAccessWalletClient create(@NonNull Context context) {
|
||||
return new QuickAccessWalletClientImpl(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the {@link QuickAccessWalletService} is available.
|
||||
*/
|
||||
boolean isWalletServiceAvailable();
|
||||
|
||||
/**
|
||||
* Get wallet cards from the {@link QuickAccessWalletService}.
|
||||
*/
|
||||
void getWalletCards(
|
||||
@NonNull GetWalletCardsRequest request,
|
||||
@NonNull Consumer<GetWalletCardsResponse> onSuccessListener,
|
||||
@NonNull Consumer<GetWalletCardsError> onFailureListener);
|
||||
|
||||
/**
|
||||
* Notify the {@link QuickAccessWalletService} service that a wallet card was selected.
|
||||
*/
|
||||
void selectWalletCard(@NonNull SelectWalletCardRequest request);
|
||||
|
||||
/**
|
||||
* Notify the {@link QuickAccessWalletService} service that the Wallet was dismissed.
|
||||
*/
|
||||
void notifyWalletDismissed();
|
||||
|
||||
/**
|
||||
* Unregister event listener.
|
||||
*/
|
||||
void registerWalletServiceEventListener(Consumer<WalletServiceEvent> listener);
|
||||
|
||||
/**
|
||||
* Unregister event listener
|
||||
*/
|
||||
void unregisterWalletServiceEventListener(Consumer<WalletServiceEvent> listener);
|
||||
|
||||
/**
|
||||
* The manifest entry for the QuickAccessWalletService may also publish information about the
|
||||
* activity that hosts the Wallet view. This is typically the home screen of the Wallet
|
||||
* application.
|
||||
*/
|
||||
@Nullable
|
||||
Intent getWalletActivity();
|
||||
|
||||
/**
|
||||
* The manifest entry for the {@link QuickAccessWalletService} may publish the activity that
|
||||
* hosts the settings
|
||||
*/
|
||||
@Nullable
|
||||
Intent getSettingsActivity();
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import static android.service.quickaccesswallet.QuickAccessWalletService.SERVICE_INTERFACE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@SuppressWarnings("AndroidJdkLibsChecker")
|
||||
class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Handler.Callback,
|
||||
ServiceConnection {
|
||||
|
||||
private static final String TAG = "QAWalletSClient";
|
||||
private final Handler mHandler;
|
||||
private final Context mContext;
|
||||
private final Queue<ApiCaller> mRequestQueue;
|
||||
private final Map<Consumer<WalletServiceEvent>, String> mEventListeners;
|
||||
private boolean mIsConnected;
|
||||
@Nullable
|
||||
private IQuickAccessWalletService mService;
|
||||
|
||||
|
||||
@Nullable
|
||||
private final QuickAccessWalletServiceInfo mServiceInfo;
|
||||
|
||||
private static final int MSG_CONNECT = 1;
|
||||
private static final int MSG_CONNECTED = 2;
|
||||
private static final int MSG_EXECUTE = 3;
|
||||
private static final int MSG_DISCONNECT = 4;
|
||||
|
||||
QuickAccessWalletClientImpl(@NonNull Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
mServiceInfo = QuickAccessWalletServiceInfo.tryCreate(context);
|
||||
mHandler = new Handler(Looper.getMainLooper(), this);
|
||||
mRequestQueue = new LinkedList<>();
|
||||
mEventListeners = new HashMap<>(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_CONNECT:
|
||||
connectInternal();
|
||||
break;
|
||||
case MSG_CONNECTED:
|
||||
onConnectedInternal((IQuickAccessWalletService) msg.obj);
|
||||
break;
|
||||
case MSG_EXECUTE:
|
||||
executeInternal((ApiCaller) msg.obj);
|
||||
break;
|
||||
case MSG_DISCONNECT:
|
||||
disconnectInternal();
|
||||
break;
|
||||
default:
|
||||
Log.w(TAG, "Unknown what: " + msg.what);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void connect() {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_CONNECT));
|
||||
}
|
||||
|
||||
private void connectInternal() {
|
||||
if (mServiceInfo == null) {
|
||||
Log.w(TAG, "Wallet service unavailable");
|
||||
return;
|
||||
}
|
||||
if (mIsConnected) {
|
||||
Log.w(TAG, "already connected");
|
||||
return;
|
||||
}
|
||||
mIsConnected = true;
|
||||
Intent intent = new Intent(SERVICE_INTERFACE);
|
||||
intent.setComponent(mServiceInfo.getComponentName());
|
||||
int flags = Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY;
|
||||
mContext.bindService(intent, this, flags);
|
||||
}
|
||||
|
||||
private void onConnectedInternal(IQuickAccessWalletService service) {
|
||||
if (!mIsConnected) {
|
||||
Log.w(TAG, "onConnectInternal but connection closed");
|
||||
mService = null;
|
||||
return;
|
||||
}
|
||||
mService = service;
|
||||
for (ApiCaller apiCaller : new ArrayList<>(mRequestQueue)) {
|
||||
try {
|
||||
apiCaller.performApiCall(mService);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "onConnectedInternal error", e);
|
||||
apiCaller.onApiError();
|
||||
disconnect();
|
||||
break;
|
||||
}
|
||||
mRequestQueue.remove(apiCaller);
|
||||
}
|
||||
}
|
||||
|
||||
private void disconnect() {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_DISCONNECT));
|
||||
}
|
||||
|
||||
private void disconnectInternal() {
|
||||
if (!mIsConnected) {
|
||||
Log.w(TAG, "already disconnected");
|
||||
return;
|
||||
}
|
||||
mIsConnected = false;
|
||||
mContext.unbindService(/*conn=*/this);
|
||||
mService = null;
|
||||
mEventListeners.clear();
|
||||
mRequestQueue.clear();
|
||||
}
|
||||
|
||||
private void execute(ApiCaller apiCaller) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_EXECUTE, apiCaller));
|
||||
}
|
||||
|
||||
private void executeInternal(ApiCaller apiCall) {
|
||||
if (mIsConnected && mService != null) {
|
||||
try {
|
||||
apiCall.performApiCall(mService);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "executeInternal error", e);
|
||||
apiCall.onApiError();
|
||||
disconnect();
|
||||
}
|
||||
} else {
|
||||
mRequestQueue.add(apiCall);
|
||||
connect();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWalletServiceAvailable() {
|
||||
return mServiceInfo != null;
|
||||
}
|
||||
|
||||
private abstract static class ApiCaller {
|
||||
abstract void performApiCall(IQuickAccessWalletService service) throws RemoteException;
|
||||
|
||||
void onApiError() {
|
||||
Log.w(TAG, "api error");
|
||||
}
|
||||
}
|
||||
|
||||
public void getWalletCards(
|
||||
@NonNull GetWalletCardsRequest request,
|
||||
@NonNull Consumer<GetWalletCardsResponse> onSuccessListener,
|
||||
@NonNull Consumer<GetWalletCardsError> onFailureListener) {
|
||||
|
||||
BaseCallbacks callback = new BaseCallbacks() {
|
||||
@Override
|
||||
public void onGetWalletCardsSuccess(GetWalletCardsResponse response) {
|
||||
mHandler.post(() -> onSuccessListener.accept(response));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetWalletCardsFailure(GetWalletCardsError error) {
|
||||
mHandler.post(() -> onFailureListener.accept(error));
|
||||
}
|
||||
};
|
||||
|
||||
execute(new ApiCaller() {
|
||||
@Override
|
||||
public void performApiCall(IQuickAccessWalletService service) throws RemoteException {
|
||||
service.onWalletCardsRequested(request, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApiError() {
|
||||
callback.onGetWalletCardsFailure(new GetWalletCardsError(null, null));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void selectWalletCard(@NonNull SelectWalletCardRequest request) {
|
||||
execute(new ApiCaller() {
|
||||
@Override
|
||||
public void performApiCall(IQuickAccessWalletService service) throws RemoteException {
|
||||
service.onWalletCardSelected(request);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void notifyWalletDismissed() {
|
||||
execute(new ApiCaller() {
|
||||
@Override
|
||||
public void performApiCall(IQuickAccessWalletService service) throws RemoteException {
|
||||
service.onWalletDismissed();
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_DISCONNECT));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerWalletServiceEventListener(Consumer<WalletServiceEvent> listener) {
|
||||
|
||||
BaseCallbacks callback = new BaseCallbacks() {
|
||||
@Override
|
||||
public void onWalletServiceEvent(WalletServiceEvent event) {
|
||||
Log.i(TAG, "onWalletServiceEvent");
|
||||
mHandler.post(() -> listener.accept(event));
|
||||
}
|
||||
};
|
||||
|
||||
execute(new ApiCaller() {
|
||||
@Override
|
||||
public void performApiCall(IQuickAccessWalletService service) throws RemoteException {
|
||||
String listenerId = UUID.randomUUID().toString();
|
||||
WalletServiceEventListenerRequest request =
|
||||
new WalletServiceEventListenerRequest(listenerId);
|
||||
mEventListeners.put(listener, listenerId);
|
||||
service.registerWalletServiceEventListener(request, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterWalletServiceEventListener(Consumer<WalletServiceEvent> listener) {
|
||||
execute(new ApiCaller() {
|
||||
@Override
|
||||
public void performApiCall(IQuickAccessWalletService service) throws RemoteException {
|
||||
String listenerId = mEventListeners.get(listener);
|
||||
if (listenerId == null) {
|
||||
return;
|
||||
}
|
||||
WalletServiceEventListenerRequest request =
|
||||
new WalletServiceEventListenerRequest(listenerId);
|
||||
service.unregisterWalletServiceEventListener(request);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Intent getWalletActivity() {
|
||||
if (mServiceInfo == null || TextUtils.isEmpty(mServiceInfo.getWalletActivity())) {
|
||||
return null;
|
||||
}
|
||||
return new Intent(QuickAccessWalletService.ACTION_VIEW_WALLET)
|
||||
.setComponent(
|
||||
new ComponentName(
|
||||
mServiceInfo.getComponentName().getPackageName(),
|
||||
mServiceInfo.getWalletActivity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Intent getSettingsActivity() {
|
||||
if (mServiceInfo == null || TextUtils.isEmpty(mServiceInfo.getSettingsActivity())) {
|
||||
return null;
|
||||
}
|
||||
return new Intent(QuickAccessWalletService.ACTION_VIEW_WALLET_SETTINGS)
|
||||
.setComponent(
|
||||
new ComponentName(
|
||||
mServiceInfo.getComponentName().getPackageName(),
|
||||
mServiceInfo.getSettingsActivity()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Connection to the {@link QuickAccessWalletService}
|
||||
*/
|
||||
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||
IQuickAccessWalletService service = IQuickAccessWalletService.Stub.asInterface(binder);
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_CONNECTED, service));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
// Do not disconnect, as we may later be re-connected
|
||||
Log.w(TAG, "onServiceDisconnected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindingDied(ComponentName name) {
|
||||
// This is a recoverable error but the client will need to reconnect.
|
||||
Log.w(TAG, "onBindingDied");
|
||||
disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNullBinding(ComponentName name) {
|
||||
Log.w(TAG, "onNullBinding");
|
||||
disconnect();
|
||||
}
|
||||
|
||||
private static class BaseCallbacks extends IQuickAccessWalletServiceCallbacks.Stub {
|
||||
public void onGetWalletCardsSuccess(GetWalletCardsResponse response) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public void onGetWalletCardsFailure(GetWalletCardsError error) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public void onWalletServiceEvent(WalletServiceEvent event) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* A {@code QuickAccessWalletService} provides a list of {@code WalletCard}s shown in the Quick
|
||||
* Access Wallet. The Quick Access Wallet allows the user to change their selected payment method
|
||||
* and access other important passes, such as tickets and transit passes, without leaving the
|
||||
* context of their current app.
|
||||
*
|
||||
* <p>An {@code QuickAccessWalletService} is only bound to the Android System for the purposes of
|
||||
* showing wallet cards if:
|
||||
* <ol>
|
||||
* <li>The application hosting the QuickAccessWalletService is also the default NFC payment
|
||||
* application. This means that the same application must also have a
|
||||
* {@link android.nfc.cardemulation.HostApduService} or
|
||||
* {@link android.nfc.cardemulation.OffHostApduService} that requires the
|
||||
* android.permission.BIND_NFC_SERVICE permission.
|
||||
* <li>The user explicitly selected the application as the default payment application in
|
||||
* the Tap & pay settings screen.
|
||||
* <li>The application requires the {@code android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE}
|
||||
* permission in its manifest.
|
||||
* <li>The user explicitly enables it using Android Settings (the
|
||||
* {@link Settings#ACTION_QUICK_ACCESS_WALLET_SETTINGS} intent can be used to launch it).
|
||||
* </ol>
|
||||
*
|
||||
* <a name="BasicUsage"></a>
|
||||
* <h3>Basic usage</h3>
|
||||
*
|
||||
* <p>The basic Quick Access Wallet process is defined by the workflow below:
|
||||
* <ol>
|
||||
* <li>User performs a gesture to bring up the Quick Access Wallet, which is displayed by the
|
||||
* Android System.
|
||||
* <li>The Android System creates a {@link GetWalletCardsRequest}, binds to the
|
||||
* {@link QuickAccessWalletService}, and delivers the request.
|
||||
* <li>The service receives the request through {@link #onWalletCardsRequested}
|
||||
* <li>The service responds by calling {@link GetWalletCardsCallback#onSuccess} with a
|
||||
* {@link GetWalletCardsResponse response} that contains between 1 and
|
||||
* {@link GetWalletCardsRequest#getMaxCards() maxCards} cards.
|
||||
* <li>The Android System displays the Quick Access Wallet containing the provided cards. The
|
||||
* card at the {@link GetWalletCardsResponse#getSelectedIndex() selectedIndex} will initially
|
||||
* be presented as the 'selected' card.
|
||||
* <li>As soon as the cards are displayed, the Android System will notify the service that the
|
||||
* card at the selected index has been selected through {@link #onWalletCardSelected}.
|
||||
* <li>The user interacts with the wallet and may select one or more cards in sequence. Each time
|
||||
* a new card is selected, the Android System will notify the service through
|
||||
* {@link #onWalletCardSelected} and will provide the {@link WalletCard#getCardId() cardId} of the
|
||||
* card that is now selected.
|
||||
* <li>When the wallet is dismissed, the Android System will notify the service through
|
||||
* {@link #onWalletDismissed}.
|
||||
* </ol>
|
||||
*
|
||||
* <p>The workflow is designed to minimize the time that the Android System is bound to the
|
||||
* service, but connections may be cached and reused to improve performance and conserve memory.
|
||||
* All calls should be considered stateless: if the service needs to keep state between calls, it
|
||||
* must do its own state management (keeping in mind that the service's process might be killed
|
||||
* by the Android System when unbound; for example, if the device is running low in memory).
|
||||
*
|
||||
* <p>
|
||||
* <a name="ErrorHandling"></a>
|
||||
* <h3>Error handling</h3>
|
||||
* <p>If the service encountered an error processing the request, it should call
|
||||
* {@link GetWalletCardsCallback#onFailure}.
|
||||
* For performance reasons, it's paramount that the service calls either
|
||||
* {@link GetWalletCardsCallback#onSuccess} or
|
||||
* {@link GetWalletCardsCallback#onFailure} for each
|
||||
* {@link #onWalletCardsRequested} received - if it doesn't, the request will eventually time out
|
||||
* and be discarded by the Android System.
|
||||
*
|
||||
* <p>
|
||||
* <a name="ManifestEntry"></a>
|
||||
* <h3>Manifest entry</h3>
|
||||
*
|
||||
* <p>QuickAccessWalletService must require the permission
|
||||
* "android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE".
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* {@literal
|
||||
* <service
|
||||
* android:name=".MyQuickAccessWalletService"
|
||||
* android:label="@string/my_default_tile_label"
|
||||
* android:icon="@drawable/my_default_icon_label"
|
||||
* android:permission="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE">
|
||||
* <intent-filter>
|
||||
* <action android:name="android.service.quickaccesswallet.QuickAccessWalletService" />
|
||||
* </intent-filter>
|
||||
* <meta-data android:name="android.quickaccesswallet"
|
||||
* android:resource="@xml/quickaccesswallet_configuration" />;
|
||||
* </service>}
|
||||
* </pre>
|
||||
* <p>
|
||||
* The {@literal <meta-data>} element includes an android:resource attribute that points to an
|
||||
* XML resource with further details about the service. The {@code quickaccesswallet_configuration}
|
||||
* in the example above specifies an activity that allows the users to view the entire wallet.
|
||||
* The following example shows the quickaccesswallet_configuration XML resource:
|
||||
* <p>
|
||||
* <pre class="prettyprint">
|
||||
* {@literal
|
||||
* <quickaccesswallet-service
|
||||
* xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
* android:settingsActivity="com.example.android.SettingsActivity"
|
||||
* android:targetActivity="com.example.android.WalletActivity"/>
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The entry for {@code settingsActivity} should contain the fully qualified class name of an
|
||||
* activity that allows the user to modify the settings for this service. The {@code targetActivity}
|
||||
* entry should contain the fully qualified class name of an activity that allows the user to view
|
||||
* their entire wallet. If specified, the wallet activity will be started with the Intent action
|
||||
* {@link #ACTION_VIEW_WALLET} and the settings activity will be started with the Intent action
|
||||
* {@link #ACTION_VIEW_WALLET_SETTINGS}.
|
||||
*/
|
||||
public abstract class QuickAccessWalletService extends Service {
|
||||
|
||||
private static final String TAG = "QAWalletService";
|
||||
|
||||
/**
|
||||
* The {@link Intent} that must be declared as handled by the service. To be supported, the
|
||||
* service must also require the
|
||||
* {@link android.Manifest.permission#BIND_QUICK_ACCESS_WALLET_SERVICE}
|
||||
* permission so that other applications can not abuse it.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
|
||||
public static final String SERVICE_INTERFACE =
|
||||
"android.service.quickaccesswallet.QuickAccessWalletService";
|
||||
|
||||
/**
|
||||
* Intent action to launch an activity to display the wallet.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||
public static final String ACTION_VIEW_WALLET =
|
||||
"android.service.quickaccesswallet.action.VIEW_WALLET";
|
||||
|
||||
/**
|
||||
* Intent action to launch an activity to display quick access wallet settings.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||
public static final String ACTION_VIEW_WALLET_SETTINGS =
|
||||
"android.service.quickaccesswallet.action.VIEW_WALLET_SETTINGS";
|
||||
|
||||
/**
|
||||
* Broadcast Action: Sent by the wallet application to dismiss the Quick Access Wallet.
|
||||
* <p>
|
||||
* The Quick Access Wallet may be shown in a system window on top of other Activities. If the
|
||||
* user selects a payment card from the Quick Access Wallet and then holds their phone to an NFC
|
||||
* terminal, the wallet application will need to show a payment Activity. But if the Quick
|
||||
* Access Wallet is still being shown, it may obscure the payment Activity. To avoid this, the
|
||||
* wallet application can send a broadcast to the Android System with this action to request
|
||||
* that the Quick Access Wallet be dismissed.
|
||||
* <p>
|
||||
* This broadcast must use the {@code android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE}
|
||||
* permission to ensure that it is only delivered to System UI. Furthermore, your application
|
||||
* must require the {@code android.permission.DISMISS_QUICK_ACCESS_WALLET}
|
||||
* <p>
|
||||
* <pre class="prettyprint">
|
||||
* context.sendBroadcast(
|
||||
* new Intent(ACTION_DISMISS_WALLET), Manifest.permission.BIND_QUICK_ACCESS_WALLET_SERVICE);
|
||||
* </pre>
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_DISMISS_WALLET =
|
||||
"android.service.quickaccesswallet.action.DISMISS_WALLET";
|
||||
|
||||
/**
|
||||
* Name under which a QuickAccessWalletService component publishes information about itself.
|
||||
* This meta-data should reference an XML resource containing a
|
||||
* <code><{@link
|
||||
* android.R.styleable#QuickAccessWalletService quickaccesswallet-service}></code> tag. This
|
||||
* is a a sample XML file configuring an QuickAccessWalletService:
|
||||
* <pre> <quickaccesswallet-service
|
||||
* android:walletActivity="foo.bar.WalletActivity"
|
||||
* . . .
|
||||
* /></pre>
|
||||
*/
|
||||
public static final String SERVICE_META_DATA = "android.quickaccesswallet";
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
@Nullable
|
||||
private String mEventListenerId;
|
||||
@Nullable
|
||||
private IQuickAccessWalletServiceCallbacks mEventListener;
|
||||
|
||||
private final IQuickAccessWalletService mInterface = new IQuickAccessWalletService.Stub() {
|
||||
@Override
|
||||
public void onWalletCardsRequested(
|
||||
@NonNull GetWalletCardsRequest request,
|
||||
@NonNull IQuickAccessWalletServiceCallbacks callback) {
|
||||
mHandler.post(() -> onWalletCardsRequestedInternal(request, callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalletCardSelected(@NonNull SelectWalletCardRequest request) {
|
||||
mHandler.post(() -> QuickAccessWalletService.this.onWalletCardSelected(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalletDismissed() {
|
||||
mHandler.post(QuickAccessWalletService.this::onWalletDismissed);
|
||||
}
|
||||
|
||||
public void registerWalletServiceEventListener(
|
||||
@NonNull WalletServiceEventListenerRequest request,
|
||||
@NonNull IQuickAccessWalletServiceCallbacks callback) {
|
||||
mHandler.post(() -> registerDismissWalletListenerInternal(request, callback));
|
||||
}
|
||||
|
||||
public void unregisterWalletServiceEventListener(
|
||||
@NonNull WalletServiceEventListenerRequest request) {
|
||||
mHandler.post(() -> unregisterDismissWalletListenerInternal(request));
|
||||
}
|
||||
};
|
||||
|
||||
private void onWalletCardsRequestedInternal(
|
||||
GetWalletCardsRequest request,
|
||||
IQuickAccessWalletServiceCallbacks callback) {
|
||||
onWalletCardsRequested(request, new GetWalletCardsCallback(callback, mHandler));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public IBinder onBind(@NonNull Intent intent) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
// Binding to the QuickAccessWalletService is protected by the
|
||||
// android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE permission, which is defined in
|
||||
// R. Pre-R devices can have other side-loaded applications that claim this permission.
|
||||
// This ensures that the service is only available when properly permission protected.
|
||||
Log.w(TAG, "Warning: binding on pre-R device");
|
||||
}
|
||||
if (SERVICE_INTERFACE.equals(intent.getAction())) {
|
||||
return mInterface.asBinder();
|
||||
}
|
||||
Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user requests the service to provide wallet cards.
|
||||
*
|
||||
* <p>This method will be called on the main thread, but the callback may be called from any
|
||||
* thread. The callback should be called as quickly as possible. The service must always call
|
||||
* either {@link GetWalletCardsCallback#onSuccess(GetWalletCardsResponse)} or {@link
|
||||
* GetWalletCardsCallback#onFailure(GetWalletCardsError)}. Calling multiple times or calling
|
||||
* both methods will cause an exception to be thrown.
|
||||
*/
|
||||
public abstract void onWalletCardsRequested(
|
||||
@NonNull GetWalletCardsRequest request,
|
||||
@NonNull GetWalletCardsCallback callback);
|
||||
|
||||
/**
|
||||
* A wallet card was selected. Sent when the user selects a wallet card from the list of cards.
|
||||
* Selection may indicate that the card is now in the center of the screen, or highlighted in
|
||||
* some other fashion. It does not mean that the user clicked on the card -- clicking on the
|
||||
* card will cause the {@link WalletCard#getPendingIntent()} to be sent.
|
||||
*
|
||||
* <p>Card selection events are especially important to NFC payment applications because
|
||||
* many NFC terminals can only accept one payment card at a time. If the user has several NFC
|
||||
* cards in their wallet, selecting different cards can change which payment method is presented
|
||||
* to the terminal.
|
||||
*/
|
||||
public abstract void onWalletCardSelected(@NonNull SelectWalletCardRequest request);
|
||||
|
||||
/**
|
||||
* Indicates that the wallet was dismissed. This is received when the Quick Access Wallet is no
|
||||
* longer visible.
|
||||
*/
|
||||
public abstract void onWalletDismissed();
|
||||
|
||||
/**
|
||||
* Send a {@link WalletServiceEvent} to the Quick Access Wallet.
|
||||
* <p>
|
||||
* Background events may require that the Quick Access Wallet view be updated. For example, if
|
||||
* the wallet application hosting this service starts to handle an NFC payment while the Quick
|
||||
* Access Wallet is being shown, the Quick Access Wallet will need to be dismissed so that the
|
||||
* Activity showing the payment can be displayed to the user.
|
||||
*/
|
||||
public final void sendWalletServiceEvent(@NonNull WalletServiceEvent serviceEvent) {
|
||||
mHandler.post(() -> sendWalletServiceEventInternal(serviceEvent));
|
||||
}
|
||||
|
||||
private void sendWalletServiceEventInternal(WalletServiceEvent serviceEvent) {
|
||||
if (mEventListener == null) {
|
||||
Log.i(TAG, "No dismiss listener registered");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mEventListener.onWalletServiceEvent(serviceEvent);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "onWalletServiceEvent error", e);
|
||||
mEventListenerId = null;
|
||||
mEventListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerDismissWalletListenerInternal(
|
||||
@NonNull WalletServiceEventListenerRequest request,
|
||||
@NonNull IQuickAccessWalletServiceCallbacks callback) {
|
||||
mEventListenerId = request.getListenerId();
|
||||
mEventListener = callback;
|
||||
}
|
||||
|
||||
private void unregisterDismissWalletListenerInternal(
|
||||
@NonNull WalletServiceEventListenerRequest request) {
|
||||
if (mEventListenerId != null && mEventListenerId.equals(request.getListenerId())) {
|
||||
mEventListenerId = null;
|
||||
mEventListener = null;
|
||||
} else {
|
||||
Log.w(TAG, "dismiss listener missing or replaced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.provider.Settings;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link ServiceInfo} and meta-data about a {@link QuickAccessWalletService}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class QuickAccessWalletServiceInfo {
|
||||
|
||||
private static final String TAG = "QAWalletSInfo";
|
||||
private static final String TAG_WALLET_SERVICE = "quickaccesswallet-service";
|
||||
|
||||
private final ServiceInfo mServiceInfo;
|
||||
private final ServiceMetadata mServiceMetadata;
|
||||
|
||||
private QuickAccessWalletServiceInfo(
|
||||
@NonNull ServiceInfo serviceInfo,
|
||||
@NonNull ServiceMetadata metadata) {
|
||||
mServiceInfo = serviceInfo;
|
||||
mServiceMetadata = metadata;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static QuickAccessWalletServiceInfo tryCreate(@NonNull Context context) {
|
||||
ComponentName defaultPaymentApp = getDefaultPaymentApp(context);
|
||||
if (defaultPaymentApp == null) {
|
||||
Log.d(TAG, "create: default payment app not set");
|
||||
return null;
|
||||
}
|
||||
|
||||
ServiceInfo serviceInfo = getWalletServiceInfo(context, defaultPaymentApp.getPackageName());
|
||||
if (serviceInfo == null) {
|
||||
Log.d(TAG, "create: unable to resolve service intent");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Manifest.permission.BIND_QUICK_ACCESS_WALLET_SERVICE.equals(serviceInfo.permission)) {
|
||||
Log.w(TAG, String.format("QuickAccessWalletService from %s does not have permission %s",
|
||||
serviceInfo.packageName, Manifest.permission.BIND_QUICK_ACCESS_WALLET_SERVICE));
|
||||
return null;
|
||||
}
|
||||
|
||||
ServiceMetadata metadata = parseServiceMetadata(context, serviceInfo);
|
||||
return new QuickAccessWalletServiceInfo(serviceInfo, metadata);
|
||||
}
|
||||
|
||||
private static ComponentName getDefaultPaymentApp(Context context) {
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
String comp = Settings.Secure.getString(cr, Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
|
||||
return comp == null ? null : ComponentName.unflattenFromString(comp);
|
||||
}
|
||||
|
||||
private static ServiceInfo getWalletServiceInfo(Context context, String packageName) {
|
||||
Intent intent = new Intent(QuickAccessWalletService.SERVICE_INTERFACE);
|
||||
intent.setPackage(packageName);
|
||||
List<ResolveInfo> resolveInfos =
|
||||
context.getPackageManager().queryIntentServices(intent,
|
||||
PackageManager.MATCH_DEFAULT_ONLY);
|
||||
return resolveInfos.isEmpty() ? null : resolveInfos.get(0).serviceInfo;
|
||||
}
|
||||
|
||||
private static class ServiceMetadata {
|
||||
@Nullable
|
||||
private final String mSettingsActivity;
|
||||
@Nullable
|
||||
private final String mWalletActivity;
|
||||
|
||||
private ServiceMetadata(String settingsActivity, String walletActivity) {
|
||||
this.mSettingsActivity = settingsActivity;
|
||||
this.mWalletActivity = walletActivity;
|
||||
}
|
||||
}
|
||||
|
||||
private static ServiceMetadata parseServiceMetadata(Context context, ServiceInfo serviceInfo) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
final XmlResourceParser parser =
|
||||
serviceInfo.loadXmlMetaData(pm, QuickAccessWalletService.SERVICE_META_DATA);
|
||||
|
||||
if (parser == null) {
|
||||
return new ServiceMetadata(null, null);
|
||||
}
|
||||
|
||||
try {
|
||||
Resources resources = pm.getResourcesForApplication(serviceInfo.applicationInfo);
|
||||
int type = 0;
|
||||
while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
|
||||
type = parser.next();
|
||||
}
|
||||
|
||||
if (TAG_WALLET_SERVICE.equals(parser.getName())) {
|
||||
final AttributeSet allAttributes = Xml.asAttributeSet(parser);
|
||||
TypedArray afsAttributes = null;
|
||||
try {
|
||||
afsAttributes = resources.obtainAttributes(allAttributes,
|
||||
R.styleable.QuickAccessWalletService);
|
||||
String settingsActivity = afsAttributes.getString(
|
||||
R.styleable.QuickAccessWalletService_settingsActivity);
|
||||
String walletActivity = afsAttributes.getString(
|
||||
R.styleable.QuickAccessWalletService_targetActivity);
|
||||
return new ServiceMetadata(settingsActivity, walletActivity);
|
||||
} finally {
|
||||
if (afsAttributes != null) {
|
||||
afsAttributes.recycle();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Meta-data does not start with quickaccesswallet-service tag");
|
||||
}
|
||||
|
||||
} catch (PackageManager.NameNotFoundException
|
||||
| IOException
|
||||
| XmlPullParserException e) {
|
||||
Log.e(TAG, "Error parsing quickaccesswallet service meta-data", e);
|
||||
}
|
||||
return new ServiceMetadata(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the component name of the {@link QuickAccessWalletService}
|
||||
*/
|
||||
@NonNull
|
||||
ComponentName getComponentName() {
|
||||
return mServiceInfo.getComponentName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fully qualified name of the activity that hosts the full wallet. If available,
|
||||
* this intent should be started with the action
|
||||
* {@link QuickAccessWalletService#ACTION_VIEW_WALLET}
|
||||
*/
|
||||
@Nullable
|
||||
String getWalletActivity() {
|
||||
return mServiceMetadata.mWalletActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fully qualified name of the activity that allows the user to change quick access
|
||||
* wallet settings. If available, this intent should be started with the action {@link
|
||||
* QuickAccessWalletService#ACTION_VIEW_WALLET_SETTINGS}
|
||||
*/
|
||||
@Nullable
|
||||
String getSettingsActivity() {
|
||||
return mServiceMetadata.mSettingsActivity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
parcelable SelectWalletCardRequest;
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Represents a request to a {@link QuickAccessWalletService} to select a particular {@link
|
||||
* WalletCard walletCard}. Card selection events are transmitted to the WalletService so that the
|
||||
* selected card may be used by the NFC payment service.
|
||||
*/
|
||||
public final class SelectWalletCardRequest implements Parcelable {
|
||||
|
||||
private final String mCardId;
|
||||
|
||||
/**
|
||||
* Creates a new GetWalletCardsRequest.
|
||||
*
|
||||
* @param cardId The {@link WalletCard#getCardId() cardId} of the wallet card that is currently
|
||||
* selected.
|
||||
*/
|
||||
public SelectWalletCardRequest(@NonNull String cardId) {
|
||||
this.mCardId = cardId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(mCardId);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<SelectWalletCardRequest> CREATOR =
|
||||
new Creator<SelectWalletCardRequest>() {
|
||||
@Override
|
||||
public SelectWalletCardRequest createFromParcel(Parcel source) {
|
||||
String cardId = source.readString();
|
||||
return new SelectWalletCardRequest(cardId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectWalletCardRequest[] newArray(int size) {
|
||||
return new SelectWalletCardRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@link WalletCard#getCardId() cardId} of the wallet card that is currently selected.
|
||||
*/
|
||||
@NonNull
|
||||
public String getCardId() {
|
||||
return mCardId;
|
||||
}
|
||||
}
|
||||
19
core/java/android/service/quickaccesswallet/WalletCard.aidl
Normal file
19
core/java/android/service/quickaccesswallet/WalletCard.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
parcelable WalletCard;
|
||||
245
core/java/android/service/quickaccesswallet/WalletCard.java
Normal file
245
core/java/android/service/quickaccesswallet/WalletCard.java
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.PendingIntent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* A {@link WalletCard} can represent anything that a user might carry in their wallet -- a credit
|
||||
* card, library card, transit pass, etc. Cards are identified by a String identifier and contain a
|
||||
* card image, card image content description, and a {@link PendingIntent} to be used if the user
|
||||
* clicks on the card. Cards may be displayed with an icon and label, though these are optional.
|
||||
*/
|
||||
public final class WalletCard implements Parcelable {
|
||||
|
||||
private final String mCardId;
|
||||
private final Icon mCardImage;
|
||||
private final CharSequence mContentDescription;
|
||||
private final PendingIntent mPendingIntent;
|
||||
private final Icon mCardIcon;
|
||||
private final CharSequence mCardLabel;
|
||||
|
||||
private WalletCard(Builder builder) {
|
||||
this.mCardId = builder.mCardId;
|
||||
this.mCardImage = builder.mCardImage;
|
||||
this.mContentDescription = builder.mContentDescription;
|
||||
this.mPendingIntent = builder.mPendingIntent;
|
||||
this.mCardIcon = builder.mCardIcon;
|
||||
this.mCardLabel = builder.mCardLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(mCardId);
|
||||
mCardImage.writeToParcel(dest, flags);
|
||||
TextUtils.writeToParcel(mContentDescription, dest, flags);
|
||||
PendingIntent.writePendingIntentOrNullToParcel(mPendingIntent, dest);
|
||||
if (mCardIcon == null) {
|
||||
dest.writeByte((byte) 0);
|
||||
} else {
|
||||
dest.writeByte((byte) 1);
|
||||
mCardIcon.writeToParcel(dest, flags);
|
||||
}
|
||||
TextUtils.writeToParcel(mCardLabel, dest, flags);
|
||||
}
|
||||
|
||||
private static WalletCard readFromParcel(Parcel source) {
|
||||
String cardId = source.readString();
|
||||
Icon cardImage = Icon.CREATOR.createFromParcel(source);
|
||||
CharSequence contentDesc = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
|
||||
PendingIntent pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(source);
|
||||
Icon cardIcon = source.readByte() == 0 ? null : Icon.CREATOR.createFromParcel(source);
|
||||
CharSequence cardLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
|
||||
return new Builder(cardId, cardImage, contentDesc, pendingIntent)
|
||||
.setCardIcon(cardIcon)
|
||||
.setCardLabel(cardLabel)
|
||||
.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<WalletCard> CREATOR =
|
||||
new Creator<WalletCard>() {
|
||||
@Override
|
||||
public WalletCard createFromParcel(Parcel source) {
|
||||
return readFromParcel(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletCard[] newArray(int size) {
|
||||
return new WalletCard[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The card id must be unique within the list of cards returned.
|
||||
*/
|
||||
@NonNull
|
||||
public String getCardId() {
|
||||
return mCardId;
|
||||
}
|
||||
|
||||
/**
|
||||
* The visual representation of the card. If the card image Icon is a bitmap, it should have a
|
||||
* width of {@link GetWalletCardsRequest#getCardWidthPx()} and a height of {@link
|
||||
* GetWalletCardsRequest#getCardHeightPx()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Icon getCardImage() {
|
||||
return mCardImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* The content description of the card image.
|
||||
*/
|
||||
@NonNull
|
||||
public CharSequence getContentDescription() {
|
||||
return mContentDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user performs a click on the card, this PendingIntent will be sent. If the device is
|
||||
* locked, the wallet will first request device unlock before sending the pending intent.
|
||||
*/
|
||||
@NonNull
|
||||
public PendingIntent getPendingIntent() {
|
||||
return mPendingIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
* An icon may be shown alongside the card image to convey information about how the card can be
|
||||
* used, or if some other action must be taken before using the card. For example, an NFC logo
|
||||
* could indicate that the card is NFC-enabled and will be provided to an NFC terminal if the
|
||||
* phone is held in close proximity to the NFC reader.
|
||||
*
|
||||
* <p>If the supplied Icon is backed by a bitmap, it should have width and height
|
||||
* {@link GetWalletCardsRequest#getIconSizePx()}.
|
||||
*/
|
||||
@Nullable
|
||||
public Icon getCardIcon() {
|
||||
return mCardIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* A card label may be shown alongside the card image to convey information about how the card
|
||||
* can be used, or if some other action must be taken before using the card. For example, an
|
||||
* NFC-enabled card could be labeled "Hold near reader" to inform the user of how to use NFC
|
||||
* cards when interacting with an NFC reader.
|
||||
*
|
||||
* <p>If the provided label is too long to fit on one line, it may be truncated and ellipsized.
|
||||
*/
|
||||
@Nullable
|
||||
public CharSequence getCardLabel() {
|
||||
return mCardLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link WalletCard} objects. You must to provide cardId, cardImage,
|
||||
* contentDescription, and pendingIntent. If the card is opaque and should be shown with
|
||||
* elevation, set hasShadow to true. cardIcon and cardLabel are optional.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private String mCardId;
|
||||
private Icon mCardImage;
|
||||
private CharSequence mContentDescription;
|
||||
private PendingIntent mPendingIntent;
|
||||
private Icon mCardIcon;
|
||||
private CharSequence mCardLabel;
|
||||
|
||||
/**
|
||||
* @param cardId The card id must be non-null and unique within the list of
|
||||
* cards returned. <b>Note:
|
||||
* </b> this card ID should <b>not</b> contain PII (Personally
|
||||
* Identifiable Information, * such as username or email
|
||||
* address).
|
||||
* @param cardImage The visual representation of the card. If the card image Icon
|
||||
* is a bitmap, it should have a width of {@link
|
||||
* GetWalletCardsRequest#getCardWidthPx()} and a height of {@link
|
||||
* GetWalletCardsRequest#getCardHeightPx()}. If the card image
|
||||
* does not have these dimensions, it may appear distorted when it
|
||||
* is scaled to fit these dimensions on screen.
|
||||
* @param contentDescription The content description of the card image. This field is
|
||||
* required.
|
||||
* <b>Note: </b> this message should <b>not</b> contain PII
|
||||
* (Personally Identifiable Information, such as username or email
|
||||
* address).
|
||||
* @param pendingIntent If the user performs a click on the card, this PendingIntent
|
||||
* will be sent. If the device is locked, the wallet will first
|
||||
* request device unlock before sending the pending intent.
|
||||
*/
|
||||
public Builder(@NonNull String cardId,
|
||||
@NonNull Icon cardImage,
|
||||
@NonNull CharSequence contentDescription,
|
||||
@NonNull PendingIntent pendingIntent) {
|
||||
mCardId = cardId;
|
||||
mCardImage = cardImage;
|
||||
mContentDescription = contentDescription;
|
||||
mPendingIntent = pendingIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
* An icon may be shown alongside the card image to convey information about how the card
|
||||
* can be used, or if some other action must be taken before using the card. For example, an
|
||||
* NFC logo could indicate that the card is NFC-enabled and will be provided to an NFC
|
||||
* terminal if the phone is held in close proximity to the NFC reader. This field is
|
||||
* optional.
|
||||
*
|
||||
* <p>If the supplied Icon is backed by a bitmap, it should have width and height
|
||||
* {@link GetWalletCardsRequest#getIconSizePx()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCardIcon(@Nullable Icon cardIcon) {
|
||||
mCardIcon = cardIcon;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A card label may be shown alongside the card image to convey information about how the
|
||||
* card can be used, or if some other action must be taken before using the card. For
|
||||
* example, an NFC-enabled card could be labeled "Hold near reader" to inform the user of
|
||||
* how to use NFC cards when interacting with an NFC reader. This field is optional.
|
||||
* <b>Note: </b> this card label should <b>not</b> contain PII (Personally Identifiable
|
||||
* Information, such as username or email address). If the provided label is too long to fit
|
||||
* on one line, it may be truncated and ellipsized.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCardLabel(@Nullable CharSequence cardLabel) {
|
||||
mCardLabel = cardLabel;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new {@link WalletCard} instance.
|
||||
*
|
||||
* @return A built response.
|
||||
*/
|
||||
@NonNull
|
||||
public WalletCard build() {
|
||||
return new WalletCard(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
parcelable WalletServiceEvent;
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Represents a request from the {@link QuickAccessWalletService wallet app} to the Quick Access
|
||||
* Wallet in System UI. Background events may necessitate that the Quick Access Wallet update its
|
||||
* view. For example, if the wallet application handles an NFC payment while the Quick Access Wallet
|
||||
* is being shown, it needs to tell the Quick Access Wallet so that the wallet can be dismissed and
|
||||
* Activity showing the payment can be displayed to the user.
|
||||
*/
|
||||
public final class WalletServiceEvent implements Parcelable {
|
||||
|
||||
/**
|
||||
* An NFC payment has started. If the Quick Access Wallet is in a system window, it will need to
|
||||
* be dismissed so that an Activity showing the payment can be displayed.
|
||||
*/
|
||||
public static final int TYPE_NFC_PAYMENT_STARTED = 1;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({TYPE_NFC_PAYMENT_STARTED})
|
||||
public @interface EventType {
|
||||
}
|
||||
|
||||
@EventType
|
||||
private final int mEventType;
|
||||
|
||||
/**
|
||||
* Creates a new DismissWalletRequest.
|
||||
*/
|
||||
public WalletServiceEvent(@EventType int eventType) {
|
||||
this.mEventType = eventType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mEventType);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<WalletServiceEvent> CREATOR =
|
||||
new Creator<WalletServiceEvent>() {
|
||||
@Override
|
||||
public WalletServiceEvent createFromParcel(Parcel source) {
|
||||
int eventType = source.readInt();
|
||||
return new WalletServiceEvent(eventType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletServiceEvent[] newArray(int size) {
|
||||
return new WalletServiceEvent[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return the event type
|
||||
*/
|
||||
@EventType
|
||||
public int getEventType() {
|
||||
return mEventType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
parcelable WalletServiceEventListenerRequest;
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.quickaccesswallet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Register a dismiss request listener with the QuickAccessWalletService. This allows the service to
|
||||
* dismiss the wallet if it needs to show a payment activity in response to an NFC event.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class WalletServiceEventListenerRequest implements Parcelable {
|
||||
|
||||
private final String mListenerId;
|
||||
|
||||
/**
|
||||
* Construct a new {@code DismissWalletListenerRequest}.
|
||||
*
|
||||
* @param listenerKey A unique key that identifies the listener.
|
||||
*/
|
||||
public WalletServiceEventListenerRequest(@NonNull String listenerKey) {
|
||||
mListenerId = listenerKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(mListenerId);
|
||||
}
|
||||
|
||||
private static WalletServiceEventListenerRequest readFromParcel(Parcel source) {
|
||||
String listenerId = source.readString();
|
||||
return new WalletServiceEventListenerRequest(listenerId);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<WalletServiceEventListenerRequest> CREATOR =
|
||||
new Creator<WalletServiceEventListenerRequest>() {
|
||||
@Override
|
||||
public WalletServiceEventListenerRequest createFromParcel(Parcel source) {
|
||||
return readFromParcel(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalletServiceEventListenerRequest[] newArray(int size) {
|
||||
return new WalletServiceEventListenerRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the unique key that identifies the wallet dismiss request listener.
|
||||
*/
|
||||
@NonNull
|
||||
public String getListenerId() {
|
||||
return mListenerId;
|
||||
}
|
||||
}
|
||||
@@ -3226,6 +3226,13 @@
|
||||
<permission android:name="android.permission.BIND_NFC_SERVICE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Must be required by a {@link android.service.quickaccesswallet.QuickAccessWalletService}
|
||||
to ensure that only the system can bind to it.
|
||||
<p>Protection level: signature
|
||||
-->
|
||||
<permission android:name="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Must be required by the PrintSpooler to ensure that only the system can bind to it.
|
||||
@hide -->
|
||||
<permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
|
||||
|
||||
@@ -8329,6 +8329,26 @@
|
||||
<attr name="successColor" format="color|reference"/>
|
||||
</declare-styleable>
|
||||
|
||||
<!-- =============================== -->
|
||||
<!-- QuickAccessWallet attributes -->
|
||||
<!-- =============================== -->
|
||||
<eat-comment />
|
||||
|
||||
<!-- Use <code>quickaccesswallet-service</code> as the root tag of the XML resource
|
||||
that describes a {@link android.service.quickaccesswallet.QuickAccessWalletService},
|
||||
which is referenced from its
|
||||
{@link android.service.quickaccesswallet.QuickAccessWalletService#SERVICE_META_DATA}
|
||||
meta-data entry.
|
||||
-->
|
||||
<declare-styleable name="QuickAccessWalletService">
|
||||
<!-- Fully qualified class name of an activity that allows the user to modify
|
||||
the settings for this service. -->
|
||||
<attr name="settingsActivity"/>
|
||||
<!-- Fully qualified class name of an activity that allows the user to view
|
||||
their entire wallet -->
|
||||
<attr name="targetActivity"/>
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Use <code>recognition-service</code> as the root tag of the XML resource that
|
||||
describes a {@link android.speech.RecognitionService}, which is referenced from
|
||||
its {@link android.speech.RecognitionService#SERVICE_META_DATA} meta-data entry.
|
||||
|
||||
@@ -174,6 +174,9 @@
|
||||
<!-- Adding Quick Settings tiles -->
|
||||
<uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
|
||||
|
||||
<!-- Access Quick Access Wallet cards -->
|
||||
<uses-permission android:name="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE" />
|
||||
|
||||
<!-- Adding Controls to SystemUI -->
|
||||
<uses-permission android:name="android.permission.BIND_CONTROLS" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user