/* * Copyright (C) 2021 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 com.android.systemui.wallet.controller; import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE; import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE; import android.content.Context; import android.database.ContentObserver; import android.provider.Settings; import android.service.quickaccesswallet.GetWalletCardsRequest; import android.service.quickaccesswallet.QuickAccessWalletClient; import android.service.quickaccesswallet.QuickAccessWalletClientImpl; import android.util.Log; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.time.SystemClock; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import javax.inject.Inject; /** * Controller to handle communication between SystemUI and Quick Access Wallet Client. */ @SysUISingleton public class QuickAccessWalletController { /** * Event for the wallet status change, e.g. the default payment app change and the wallet * preference change. */ public enum WalletChangeEvent { DEFAULT_PAYMENT_APP_CHANGE, WALLET_PREFERENCE_CHANGE, } private static final String TAG = "QAWController"; private static final long RECREATION_TIME_WINDOW = TimeUnit.MINUTES.toMillis(10L); private final Context mContext; private final Executor mExecutor; private final SecureSettings mSecureSettings; private final SystemClock mClock; private QuickAccessWalletClient mQuickAccessWalletClient; private ContentObserver mWalletPreferenceObserver; private ContentObserver mDefaultPaymentAppObserver; private int mWalletPreferenceChangeEvents = 0; private int mDefaultPaymentAppChangeEvents = 0; private boolean mWalletEnabled = false; private long mQawClientCreatedTimeMillis; @Inject public QuickAccessWalletController( Context context, @Main Executor executor, SecureSettings secureSettings, QuickAccessWalletClient quickAccessWalletClient, SystemClock clock) { mContext = context; mExecutor = executor; mSecureSettings = secureSettings; mQuickAccessWalletClient = quickAccessWalletClient; mClock = clock; mQawClientCreatedTimeMillis = mClock.elapsedRealtime(); } /** * Returns true if the Quick Access Wallet service & feature is available. */ public boolean isWalletEnabled() { return mWalletEnabled; } /** * Returns the current instance of {@link QuickAccessWalletClient} in the controller. */ public QuickAccessWalletClient getWalletClient() { return mQuickAccessWalletClient; } /** * Setup the wallet change observers per {@link WalletChangeEvent} * * @param cardsRetriever a callback that retrieves the wallet cards * @param events {@link WalletChangeEvent} need to be handled. */ public void setupWalletChangeObservers( QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever, WalletChangeEvent... events) { for (WalletChangeEvent event : events) { if (event == WALLET_PREFERENCE_CHANGE) { setupWalletPreferenceObserver(); } else if (event == DEFAULT_PAYMENT_APP_CHANGE) { setupDefaultPaymentAppObserver(cardsRetriever); } } } /** * Unregister wallet change observers per {@link WalletChangeEvent} if needed. * */ public void unregisterWalletChangeObservers(WalletChangeEvent... events) { for (WalletChangeEvent event : events) { if (event == WALLET_PREFERENCE_CHANGE && mWalletPreferenceObserver != null) { mWalletPreferenceChangeEvents--; if (mWalletPreferenceChangeEvents == 0) { mSecureSettings.unregisterContentObserver(mWalletPreferenceObserver); } } else if (event == DEFAULT_PAYMENT_APP_CHANGE && mDefaultPaymentAppObserver != null) { mDefaultPaymentAppChangeEvents--; if (mDefaultPaymentAppChangeEvents == 0) { mSecureSettings.unregisterContentObserver(mDefaultPaymentAppObserver); } } } } /** * Update the "show wallet" preference. */ public void updateWalletPreference() { mWalletEnabled = mQuickAccessWalletClient.isWalletServiceAvailable() && mQuickAccessWalletClient.isWalletFeatureAvailable() && mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked(); } /** * Query the wallet cards from {@link QuickAccessWalletClient}. * * @param cardsRetriever a callback to retrieve wallet cards. */ public void queryWalletCards( QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) { if (mClock.elapsedRealtime() - mQawClientCreatedTimeMillis > RECREATION_TIME_WINDOW) { Log.i(TAG, "Re-creating the QAW client to avoid stale."); reCreateWalletClient(); } if (!mQuickAccessWalletClient.isWalletFeatureAvailable()) { Log.d(TAG, "QuickAccessWallet feature is not available."); return; } int cardWidth = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width); int cardHeight = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height); int iconSizePx = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_icon_size); GetWalletCardsRequest request = new GetWalletCardsRequest(cardWidth, cardHeight, iconSizePx, /* maxCards= */ 1); mQuickAccessWalletClient.getWalletCards(mExecutor, request, cardsRetriever); } /** * Re-create the {@link QuickAccessWalletClient} of the controller. */ public void reCreateWalletClient() { mQuickAccessWalletClient = QuickAccessWalletClient.create(mContext); mQawClientCreatedTimeMillis = mClock.elapsedRealtime(); } private void setupDefaultPaymentAppObserver( QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) { if (mDefaultPaymentAppObserver == null) { mDefaultPaymentAppObserver = new ContentObserver(null /* handler */) { @Override public void onChange(boolean selfChange) { mExecutor.execute(() -> { reCreateWalletClient(); updateWalletPreference(); queryWalletCards(cardsRetriever); }); } }; mSecureSettings.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT), false /* notifyForDescendants */, mDefaultPaymentAppObserver); } mDefaultPaymentAppChangeEvents++; } private void setupWalletPreferenceObserver() { if (mWalletPreferenceObserver == null) { mWalletPreferenceObserver = new ContentObserver(null /* handler */) { @Override public void onChange(boolean selfChange) { mExecutor.execute(() -> { updateWalletPreference(); }); } }; mSecureSettings.registerContentObserver( Settings.Secure.getUriFor(QuickAccessWalletClientImpl.SETTING_KEY), false /* notifyForDescendants */, mWalletPreferenceObserver); } mWalletPreferenceChangeEvents++; } }