Merge "Recreate QuickAccessWallet for Wallet Tile and Lockscreen Icon when the default payment app has changed." into sc-dev

This commit is contained in:
TreeHugger Robot
2021-05-26 20:50:05 +00:00
committed by Android (Google) Code Review
8 changed files with 454 additions and 141 deletions

View File

@@ -18,13 +18,14 @@ package com.android.systemui.qs.tiles;
import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT;
import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.service.quickaccesswallet.GetWalletCardsError;
import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.service.quickaccesswallet.WalletCard;
@@ -51,6 +52,7 @@ import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.systemui.wallet.ui.WalletActivity;
import java.util.List;
@@ -66,16 +68,15 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
private final CharSequence mLabel = mContext.getString(R.string.wallet_title);
private final WalletCardRetriever mCardRetriever = new WalletCardRetriever();
// TODO(b/180959290): Re-create the QAW Client when the default NFC payment app changes.
private final QuickAccessWalletClient mQuickAccessWalletClient;
private final KeyguardStateController mKeyguardStateController;
private final PackageManager mPackageManager;
private final SecureSettings mSecureSettings;
private final Executor mExecutor;
private final QuickAccessWalletController mController;
private final FeatureFlags mFeatureFlags;
@VisibleForTesting Drawable mCardViewDrawable;
private WalletCard mSelectedCard;
@VisibleForTesting Drawable mCardViewDrawable;
@Inject
public QuickAccessWalletTile(
@@ -87,15 +88,15 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
QuickAccessWalletClient quickAccessWalletClient,
KeyguardStateController keyguardStateController,
PackageManager packageManager,
SecureSettings secureSettings,
@Background Executor executor,
@Main Executor executor,
QuickAccessWalletController quickAccessWalletController,
FeatureFlags featureFlags) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mQuickAccessWalletClient = quickAccessWalletClient;
mController = quickAccessWalletController;
mKeyguardStateController = keyguardStateController;
mPackageManager = packageManager;
mSecureSettings = secureSettings;
@@ -115,7 +116,11 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
protected void handleSetListening(boolean listening) {
super.handleSetListening(listening);
if (listening) {
queryWalletCards();
mController.setupWalletChangeObservers(mCardRetriever, DEFAULT_PAYMENT_APP_CHANGE);
if (!mController.getWalletClient().isWalletServiceAvailable()) {
mController.reCreateWalletClient();
}
mController.queryWalletCards(mCardRetriever);
}
}
@@ -139,12 +144,13 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
mContext.startActivity(intent);
}
} else {
if (mQuickAccessWalletClient.createWalletIntent() == null) {
if (mController.getWalletClient().createWalletIntent() == null) {
Log.w(TAG, "Could not get intent of the wallet app.");
return;
}
mActivityStarter.postStartActivityDismissingKeyguard(
mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0,
mController.getWalletClient().createWalletIntent(),
/* delay= */ 0,
animationController);
}
});
@@ -152,30 +158,34 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
@Override
protected void handleUpdateState(State state, Object arg) {
CharSequence label = mQuickAccessWalletClient.getServiceLabel();
CharSequence label = mController.getWalletClient().getServiceLabel();
state.label = label == null ? mLabel : label;
state.contentDescription = state.label;
state.icon = ResourceIcon.get(R.drawable.ic_wallet_lockscreen);
boolean isDeviceLocked = !mKeyguardStateController.isUnlocked();
if (mQuickAccessWalletClient.isWalletServiceAvailable()) {
if (mController.getWalletClient().isWalletServiceAvailable()) {
if (mSelectedCard != null) {
if (isDeviceLocked) {
state.state = Tile.STATE_INACTIVE;
state.secondaryLabel =
mContext.getString(R.string.wallet_secondary_label_device_locked);
state.sideViewCustomDrawable = null;
} else {
state.state = Tile.STATE_ACTIVE;
state.secondaryLabel = mSelectedCard.getContentDescription();
state.sideViewCustomDrawable = mCardViewDrawable;
}
} else {
state.state = Tile.STATE_INACTIVE;
state.secondaryLabel = mContext.getString(R.string.wallet_secondary_label_no_card);
state.sideViewCustomDrawable = null;
}
state.stateDescription = state.secondaryLabel;
} else {
state.state = Tile.STATE_UNAVAILABLE;
state.secondaryLabel = null;
state.sideViewCustomDrawable = null;
}
state.sideViewCustomDrawable = isDeviceLocked ? null : mCardViewDrawable;
}
@Override
@@ -198,19 +208,14 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
@Override
public CharSequence getTileLabel() {
CharSequence label = mQuickAccessWalletClient.getServiceLabel();
CharSequence label = mController.getWalletClient().getServiceLabel();
return label == null ? mLabel : label;
}
private void queryWalletCards() {
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, mCardRetriever);
@Override
protected void handleDestroy() {
super.handleDestroy();
mController.unregisterWalletChangeObservers(DEFAULT_PAYMENT_APP_CHANGE);
}
private class WalletCardRetriever implements

View File

@@ -24,6 +24,8 @@ import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTT
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_UNLOCK;
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.app.ActivityManager;
import android.app.ActivityOptions;
@@ -39,7 +41,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -49,13 +50,10 @@ import android.os.Messenger;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.MediaStore;
import android.provider.Settings;
import android.service.media.CameraPrewarmService;
import android.service.quickaccesswallet.GetWalletCardsError;
import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.service.quickaccesswallet.QuickAccessWalletClientImpl;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -71,7 +69,6 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
@@ -97,11 +94,9 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.PreviewInflater;
import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.systemui.wallet.ui.WalletActivity;
import java.util.concurrent.Executor;
/**
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
* text.
@@ -137,10 +132,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private KeyguardAffordanceView mLeftAffordanceView;
private ImageView mWalletButton;
private boolean mWalletEnabled = false;
private boolean mHasCard = false;
private WalletCardRetriever mCardRetriever = new WalletCardRetriever();
private QuickAccessWalletClient mQuickAccessWalletClient;
private QuickAccessWalletController mQuickAccessWalletController;
private ViewGroup mIndicationArea;
private TextView mIndicationText;
@@ -159,7 +153,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private StatusBar mStatusBar;
private KeyguardAffordanceHelper mAffordanceHelper;
private FalsingManager mFalsingManager;
@Nullable private Executor mUiExecutor;
private boolean mUserSetupComplete;
private boolean mPrewarmBound;
private Messenger mPrewarmMessenger;
@@ -193,8 +186,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private int mBurnInYOffset;
private ActivityIntentHelper mActivityIntentHelper;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private ContentObserver mWalletPreferenceObserver;
private SecureSettings mSecureSettings;
public KeyguardBottomAreaView(Context context) {
this(context, null);
@@ -332,8 +323,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
getContext().unregisterReceiver(mDevicePolicyReceiver);
mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
if (mWalletPreferenceObserver != null) {
mSecureSettings.unregisterContentObserver(mWalletPreferenceObserver);
if (mQuickAccessWalletController != null) {
mQuickAccessWalletController.unregisterWalletChangeObservers(
WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
}
}
@@ -456,7 +448,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
private void updateWalletVisibility() {
if (mDozing || !mWalletEnabled || !mHasCard) {
if (mDozing
|| mQuickAccessWalletController == null
|| !mQuickAccessWalletController.isWalletEnabled()
|| !mHasCard) {
mWalletButton.setVisibility(GONE);
mIndicationArea.setPadding(0, 0, 0, 0);
} else {
@@ -690,7 +685,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
public void onKeyguardShowingChanged() {
if (mKeyguardStateController.isShowing()) {
queryWalletCards();
if (mQuickAccessWalletController != null) {
mQuickAccessWalletController.queryWalletCards(mCardRetriever);
}
}
}
@@ -935,50 +932,17 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
/**
* Initialize the wallet feature, only enabling if the feature is enabled within the platform.
*/
public void initWallet(QuickAccessWalletClient client, Executor uiExecutor,
SecureSettings secureSettings) {
mQuickAccessWalletClient = client;
mSecureSettings = secureSettings;
setupWalletPreferenceObserver();
updateWalletPreference();
mUiExecutor = uiExecutor;
queryWalletCards();
public void initWallet(
QuickAccessWalletController controller) {
mQuickAccessWalletController = controller;
mQuickAccessWalletController.setupWalletChangeObservers(
mCardRetriever, WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
mQuickAccessWalletController.updateWalletPreference();
mQuickAccessWalletController.queryWalletCards(mCardRetriever);
updateWalletVisibility();
}
private void setupWalletPreferenceObserver() {
if (mWalletPreferenceObserver == null) {
mWalletPreferenceObserver = new ContentObserver(null /* handler */) {
@Override
public void onChange(boolean selfChange) {
mUiExecutor.execute(() -> updateWalletPreference());
}
};
mSecureSettings.registerContentObserver(
Settings.Secure.getUriFor(QuickAccessWalletClientImpl.SETTING_KEY),
false /* notifyForDescendants */,
mWalletPreferenceObserver);
}
}
private void updateWalletPreference() {
mWalletEnabled = mQuickAccessWalletClient.isWalletFeatureAvailable()
&& mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked();
}
private void queryWalletCards() {
if (!mWalletEnabled || mUiExecutor == null) {
return;
}
GetWalletCardsRequest request =
new GetWalletCardsRequest(1 /* cardWidth */, 1 /* cardHeight */,
1 /* iconSizePx */, 1 /* maxCards */);
mQuickAccessWalletClient.getWalletCards(mUiExecutor, request, mCardRetriever);
}
private void onWalletClick(View v) {
// More coming here; need to inform the user about how to proceed
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
@@ -991,12 +955,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
} else {
if (mQuickAccessWalletClient.createWalletIntent() == null) {
if (mQuickAccessWalletController.getWalletClient().createWalletIntent() == null) {
Log.w(TAG, "Could not get intent of the wallet app.");
return;
}
mActivityStarter.postStartActivityDismissingKeyguard(
mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0);
mQuickAccessWalletController.getWalletClient().createWalletIntent(),
/* delay= */ 0);
}
}

View File

@@ -54,7 +54,6 @@ import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserManager;
import android.os.VibrationEffect;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.util.Log;
import android.util.MathUtils;
import android.view.DisplayCutout;
@@ -153,6 +152,7 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.util.Utils;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
@@ -310,6 +310,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final FeatureFlags mFeatureFlags;
private final ScrimController mScrimController;
private final PrivacyDotViewController mPrivacyDotViewController;
private final QuickAccessWalletController mQuickAccessWalletController;
// Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
// If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
@@ -584,7 +585,6 @@ public class NotificationPanelViewController extends PanelViewController {
private int mNotificationScrimPadding;
private boolean mQSAnimatingHiddenFromCollapsed;
private final QuickAccessWalletClient mQuickAccessWalletClient;
private final Executor mUiExecutor;
private final SecureSettings mSecureSettings;
@@ -665,11 +665,11 @@ public class NotificationPanelViewController extends PanelViewController {
AmbientState ambientState,
LockIconViewController lockIconViewController,
FeatureFlags featureFlags,
QuickAccessWalletClient quickAccessWalletClient,
KeyguardMediaController keyguardMediaController,
PrivacyDotViewController privacyDotViewController,
TapAgainViewController tapAgainViewController,
FragmentService fragmentService,
QuickAccessWalletController quickAccessWalletController,
@Main Executor uiExecutor,
SecureSettings secureSettings) {
super(view, falsingManager, dozeLog, keyguardStateController,
@@ -680,6 +680,7 @@ public class NotificationPanelViewController extends PanelViewController {
mVibratorHelper = vibratorHelper;
mKeyguardMediaController = keyguardMediaController;
mPrivacyDotViewController = privacyDotViewController;
mQuickAccessWalletController = quickAccessWalletController;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
mConfigurationController = configurationController;
@@ -722,7 +723,6 @@ public class NotificationPanelViewController extends PanelViewController {
mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
mUserManager = userManager;
mMediaDataManager = mediaDataManager;
mQuickAccessWalletClient = quickAccessWalletClient;
mTapAgainViewController = tapAgainViewController;
mUiExecutor = uiExecutor;
mSecureSettings = secureSettings;
@@ -1123,7 +1123,7 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardBottomArea.setFalsingManager(mFalsingManager);
if (mFeatureFlags.isQuickAccessWalletEnabled()) {
mKeyguardBottomArea.initWallet(mQuickAccessWalletClient, mUiExecutor, mSecureSettings);
mKeyguardBottomArea.initWallet(mQuickAccessWalletController);
}
}

View File

@@ -0,0 +1,207 @@
/*
* 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 java.util.concurrent.Executor;
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 final Context mContext;
private final Executor mExecutor;
private final SecureSettings mSecureSettings;
private QuickAccessWalletClient mQuickAccessWalletClient;
private ContentObserver mWalletPreferenceObserver;
private ContentObserver mDefaultPaymentAppObserver;
private int mWalletPreferenceChangeEvents = 0;
private int mDefaultPaymentAppChangeEvents = 0;
private boolean mWalletEnabled = false;
@Inject
public QuickAccessWalletController(
Context context,
@Main Executor executor,
SecureSettings secureSettings,
QuickAccessWalletClient quickAccessWalletClient) {
mContext = context;
mExecutor = executor;
mSecureSettings = secureSettings;
mQuickAccessWalletClient = quickAccessWalletClient;
}
/**
* 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 (!mWalletEnabled) {
Log.w(TAG, "QuickAccessWallet is unavailable, unable to query cards.");
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);
}
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++;
}
}

View File

@@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
@@ -52,7 +53,7 @@ import javax.inject.Inject;
*/
public class WalletActivity extends LifecycleActivity {
private final QuickAccessWalletClient mQuickAccessWalletClient;
private static final String TAG = "WalletActivity";
private final KeyguardStateController mKeyguardStateController;
private final KeyguardDismissUtil mKeyguardDismissUtil;
private final ActivityStarter mActivityStarter;
@@ -65,7 +66,6 @@ public class WalletActivity extends LifecycleActivity {
@Inject
public WalletActivity(
QuickAccessWalletClient quickAccessWalletClient,
KeyguardStateController keyguardStateController,
KeyguardDismissUtil keyguardDismissUtil,
ActivityStarter activityStarter,
@@ -74,7 +74,6 @@ public class WalletActivity extends LifecycleActivity {
FalsingManager falsingManager,
UserTracker userTracker,
StatusBarKeyguardViewManager keyguardViewManager) {
mQuickAccessWalletClient = quickAccessWalletClient;
mKeyguardStateController = keyguardStateController;
mKeyguardDismissUtil = keyguardDismissUtil;
mActivityStarter = activityStarter;
@@ -103,10 +102,11 @@ public class WalletActivity extends LifecycleActivity {
getActionBar().setHomeActionContentDescription(R.string.accessibility_desc_close);
WalletView walletView = requireViewById(R.id.wallet_view);
QuickAccessWalletClient walletClient = QuickAccessWalletClient.create(this);
mWalletScreenController = new WalletScreenController(
this,
walletView,
mQuickAccessWalletClient,
walletClient,
mActivityStarter,
mExecutor,
mHandler,
@@ -116,6 +116,10 @@ public class WalletActivity extends LifecycleActivity {
walletView.getAppButton().setOnClickListener(
v -> {
if (walletClient.createWalletIntent() == null) {
Log.w(TAG, "Unable to create wallet app intent.");
return;
}
if (!mKeyguardStateController.isUnlocked()
&& mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return;
@@ -123,12 +127,12 @@ public class WalletActivity extends LifecycleActivity {
if (mKeyguardStateController.isUnlocked()) {
mActivityStarter.startActivity(
mQuickAccessWalletClient.createWalletIntent(), true);
walletClient.createWalletIntent(), true);
finish();
} else {
mKeyguardDismissUtil.executeWhenUnlocked(() -> {
mActivityStarter.startActivity(
mQuickAccessWalletClient.createWalletIntent(), true);
walletClient.createWalletIntent(), true);
finish();
return false;
}, false, true);

View File

@@ -73,6 +73,7 @@ import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.google.common.util.concurrent.MoreExecutors;
@@ -119,6 +120,8 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
@Mock
private SecureSettings mSecureSettings;
@Mock
private QuickAccessWalletController mController;
@Mock
private FeatureFlags mFeatureFlags;
@Captor
ArgumentCaptor<Intent> mIntentCaptor;
@@ -145,6 +148,8 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
when(mQuickAccessWalletClient.getServiceLabel()).thenReturn(LABEL);
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true);
when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(true);
when(mController.getWalletClient()).thenReturn(mQuickAccessWalletClient);
mTile = new QuickAccessWalletTile(
mHost,
@@ -155,11 +160,11 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
mStatusBarStateController,
mActivityStarter,
mQSLogger,
mQuickAccessWalletClient,
mKeyguardStateController,
mPackageManager,
mSecureSettings,
MoreExecutors.directExecutor(),
mController,
mFeatureFlags);
}
@@ -174,6 +179,15 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
assertFalse(mTile.isAvailable());
}
@Test
public void testWalletServiceUnavailable_recreateWalletClient() {
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
mTile.handleSetListening(true);
verify(mController, times(1)).reCreateWalletClient();
}
@Test
public void testIsAvailable_qawFeatureAvailable() {
when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(true);
@@ -330,17 +344,8 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
public void testHandleSetListening_queryCards() {
mTile.handleSetListening(true);
verify(mQuickAccessWalletClient)
.getWalletCards(any(), mRequestCaptor.capture(), mCallbackCaptor.capture());
verify(mController).queryWalletCards(mCallbackCaptor.capture());
GetWalletCardsRequest request = mRequestCaptor.getValue();
assertEquals(
mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width),
request.getCardWidthPx());
assertEquals(
mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height),
request.getCardHeightPx());
assertEquals(1, request.getMaxCards());
assertThat(mCallbackCaptor.getValue()).isInstanceOf(
QuickAccessWalletClient.OnWalletCardsRetrievedCallback.class);
}
@@ -353,37 +358,6 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
assertNotNull(mTile.getState().sideViewCustomDrawable);
}
@Test
public void testState_queryCards_hasCards_then_noCards() {
when(mKeyguardStateController.isUnlocked()).thenReturn(true);
GetWalletCardsResponse responseWithCards =
new GetWalletCardsResponse(
Collections.singletonList(createWalletCard(mContext)), 0);
GetWalletCardsResponse responseWithoutCards =
new GetWalletCardsResponse(Collections.EMPTY_LIST, 0);
mTile.handleSetListening(true);
verify(mQuickAccessWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
// query wallet cards, has cards
mCallbackCaptor.getValue().onWalletCardsRetrieved(responseWithCards);
mTestableLooper.processAllMessages();
assertNotNull(mTile.getState().sideViewCustomDrawable);
mTile.handleSetListening(true);
verify(mQuickAccessWalletClient, times(2))
.getWalletCards(any(), any(), mCallbackCaptor.capture());
// query wallet cards, has no cards
mCallbackCaptor.getValue().onWalletCardsRetrieved(responseWithoutCards);
mTestableLooper.processAllMessages();
assertNull(mTile.getState().sideViewCustomDrawable);
}
@Test
public void testQueryCards_noCards_notUpdateSideViewDrawable() {
setUpWalletCard(/* hasCard= */ false);
@@ -398,7 +372,7 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
mTile.handleSetListening(true);
verify(mQuickAccessWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
verify(mController).queryWalletCards(mCallbackCaptor.capture());
mCallbackCaptor.getValue().onWalletCardRetrievalError(error);
mTestableLooper.processAllMessages();
@@ -422,7 +396,7 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
mTile.handleSetListening(true);
verify(mQuickAccessWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
verify(mController).queryWalletCards(mCallbackCaptor.capture());
mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();

View File

@@ -42,7 +42,6 @@ import android.content.res.Resources;
import android.hardware.biometrics.BiometricSourceType;
import android.os.PowerManager;
import android.os.UserManager;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.DisplayMetrics;
@@ -112,6 +111,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
@@ -252,8 +252,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private LockIconViewController mLockIconViewController;
@Mock
private QuickAccessWalletClient mQuickAccessWalletClient;
@Mock
private KeyguardMediaController mKeyguardMediaController;
@Mock
private PrivacyDotViewController mPrivacyDotViewController;
@@ -267,6 +265,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private FragmentService mFragmentService;
@Mock
private FragmentHostManager mFragmentHostManager;
@Mock
private QuickAccessWalletController mQuickAccessWalletController;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -380,11 +380,11 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mAmbientState,
mLockIconViewController,
mFeatureFlags,
mQuickAccessWalletClient,
mKeyguardMediaController,
mPrivacyDotViewController,
mTapAgainViewController,
mFragmentService,
mQuickAccessWalletController,
new FakeExecutor(new FakeSystemClock()),
mSecureSettings);
mNotificationPanelViewController.initDependencies(

View File

@@ -0,0 +1,158 @@
/*
* 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 org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.settings.SecureSettings;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class QuickAccessWalletControllerTest extends SysuiTestCase {
@Mock
private QuickAccessWalletClient mQuickAccessWalletClient;
@Mock
private SecureSettings mSecureSettings;
@Mock
private QuickAccessWalletClient.OnWalletCardsRetrievedCallback mCardsRetriever;
@Captor
private ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor;
private QuickAccessWalletController mController;
private TestableLooper mTestableLooper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true);
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(true);
mController = new QuickAccessWalletController(
mContext,
MoreExecutors.directExecutor(),
mSecureSettings,
mQuickAccessWalletClient);
}
@Test
public void walletEnabled() {
mController.updateWalletPreference();
assertTrue(mController.isWalletEnabled());
}
@Test
public void walletServiceUnavailable_walletNotEnabled() {
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
mController.updateWalletPreference();
assertFalse(mController.isWalletEnabled());
}
@Test
public void walletFeatureUnavailable_walletNotEnabled() {
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false);
mController.updateWalletPreference();
assertFalse(mController.isWalletEnabled());
}
@Test
public void walletFeatureWhenLockedUnavailable_walletNotEnabled() {
when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(false);
mController.updateWalletPreference();
assertFalse(mController.isWalletEnabled());
}
@Test
public void getWalletClient_NoRecreation_sameClient() {
assertSame(mQuickAccessWalletClient, mController.getWalletClient());
}
@Test
public void getWalletClient_reCreateClient_notSameClient() {
mController.reCreateWalletClient();
assertNotSame(mQuickAccessWalletClient, mController.getWalletClient());
}
@Test
public void queryWalletCards_walletNotEnabled_notQuery() {
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
mController.queryWalletCards(mCardsRetriever);
verify(mQuickAccessWalletClient, never()).getWalletCards(any(), any(), any());
}
@Test
public void queryWalletCards_walletEnabled_queryCards() {
mController.updateWalletPreference();
mController.queryWalletCards(mCardsRetriever);
verify(mQuickAccessWalletClient)
.getWalletCards(
eq(MoreExecutors.directExecutor()),
mRequestCaptor.capture(),
eq(mCardsRetriever));
GetWalletCardsRequest request = mRequestCaptor.getValue();
assertEquals(1, mRequestCaptor.getValue().getMaxCards());
assertEquals(
mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width),
request.getCardWidthPx());
assertEquals(
mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height),
request.getCardHeightPx());
}
}