Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d00aefb4 authored by Sean Pont's avatar Sean Pont
Browse files

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
parent 30b7a575
Loading
Loading
Loading
Loading
+90 −0
Original line number Original line Diff line number Diff line
@@ -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_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_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_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_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_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
    field public static final String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
    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_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_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_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_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_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";
    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 {
package android.service.quicksettings {
  public final class Tile implements android.os.Parcelable {
  public final class Tile implements android.os.Parcelable {
+15 −0
Original line number Original line Diff line number Diff line
@@ -1968,6 +1968,21 @@ public final class Settings {
    public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE =
    public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE =
            "android.settings.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.
     * Activity Action: Show screen for controlling which apps have access on volume directories.
     * <p>
     * <p>
+92 −0
Original line number Original line Diff line number Diff line
/*
 * 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);
        }
    }
}
+19 −0
Original line number Original line Diff line number Diff line
/*
 * 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;
 No newline at end of file
+100 −0
Original line number Original line Diff line number Diff line
/*
 * 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;
    }
}
Loading