diff --git a/packages/SystemUI/res/drawable/ic_wallet_lockscreen.xml b/packages/SystemUI/res/drawable/ic_wallet_lockscreen.xml new file mode 100644 index 0000000000000..2f8f11d72331b --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_wallet_lockscreen.xml @@ -0,0 +1,37 @@ + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml b/packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml new file mode 100644 index 0000000000000..1535e7276a6f3 --- /dev/null +++ b/packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index cf9de5e7e226d..69d73c1b94e14 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -90,9 +90,11 @@ android:layout_width="@dimen/keyguard_affordance_width" android:layout_gravity="bottom|end" android:scaleType="center" - android:tint="?attr/wallpaperTextColor" - android:layout_marginStart="24dp" - android:layout_marginBottom="48dp" + android:tint="?android:attr/textColorPrimary" + android:src="@drawable/ic_wallet_lockscreen" + android:background="@drawable/wallet_lockscreen_bg" + android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset" + android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset" android:visibility="gone" /> 56dp - - 56dp - 56dp + + 48dp + 48dp + 32dp + 32dp + 42dp diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 411a2a3a29113..c3325b103022b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -48,8 +48,11 @@ 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.telecom.TelecomManager; import android.text.TextUtils; import android.util.AttributeSet; @@ -64,6 +67,8 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; @@ -75,6 +80,7 @@ import com.android.systemui.animation.Interpolators; import com.android.systemui.assist.AssistManager; import com.android.systemui.camera.CameraIntents; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.IntentButtonProvider; import com.android.systemui.plugins.IntentButtonProvider.IntentButton; import com.android.systemui.plugins.IntentButtonProvider.IntentButton.IconState; @@ -87,6 +93,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.wallet.ui.WalletActivity; + +import java.util.concurrent.Executor; /** * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status @@ -121,7 +130,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private KeyguardAffordanceView mRightAffordanceView; private KeyguardAffordanceView mLeftAffordanceView; + private ImageView mWalletButton; + private boolean mWalletEnabled = false; + private boolean mHasCard = false; + private WalletCardRetriever mCardRetriever = new WalletCardRetriever(); + private QuickAccessWalletClient mQuickAccessWalletClient; + private ViewGroup mIndicationArea; private TextView mIndicationText; private TextView mIndicationTextBottom; @@ -138,7 +153,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private AccessibilityController mAccessibilityController; private StatusBar mStatusBar; private KeyguardAffordanceHelper mAffordanceHelper; - + private FalsingManager mFalsingManager; private boolean mUserSetupComplete; private boolean mPrewarmBound; private Messenger mPrewarmMessenger; @@ -170,7 +185,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private int mBurnInXOffset; private int mBurnInYOffset; private ActivityIntentHelper mActivityIntentHelper; - private int mLockScreenMode; private KeyguardUpdateMonitor mKeyguardUpdateMonitor; public KeyguardBottomAreaView(Context context) { @@ -415,10 +429,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } private void updateWalletVisibility() { - if (mDozing) { + if (mDozing || !mWalletEnabled) { mWalletButton.setVisibility(GONE); } else { mWalletButton.setVisibility(VISIBLE); + mWalletButton.setOnClickListener(this::onWalletClick); } } @@ -871,25 +886,63 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL return insets; } - private void setupWallet() { - boolean inNewLayout = mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; - boolean settingEnabled = Settings.Global.getInt(mContext.getContentResolver(), - "controls_lockscreen", 0) == 1; - if (!inNewLayout || !settingEnabled) { - mWalletButton.setVisibility(View.GONE); - return; - } - - // TODO: add image - // mWalletButton.setImageDrawable(list.get(0).loadIcon()); - updateWalletVisibility(); + /** Set the falsing manager */ + public void setFalsingManager(FalsingManager falsingManager) { + mFalsingManager = falsingManager; } /** - * Optionally add controls when in the new lockscreen mode + * Initialize the wallet feature, only enabling if the feature is enabled within the platform. */ - public void onLockScreenModeChanged(int mode) { - mLockScreenMode = mode; - setupWallet(); + public void initWallet(QuickAccessWalletClient client, Executor uiExecutor, boolean enabled) { + mQuickAccessWalletClient = client; + mWalletEnabled = enabled && client.isWalletFeatureAvailable(); + + if (mWalletEnabled) { + queryWalletCards(uiExecutor); + } + updateWalletVisibility(); + } + + private void queryWalletCards(Executor uiExecutor) { + GetWalletCardsRequest request = + new GetWalletCardsRequest(1 /* cardWidth */, 1 /* cardHeight */, + 1 /* iconSizePx */, 2 /* maxCards */); + mQuickAccessWalletClient.getWalletCards(uiExecutor, request, mCardRetriever); + } + + private void onWalletClick(View v) { + // More coming here; need to inform the user about how to proceed + mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY); + + if (mHasCard) { + Intent intent = new Intent(mContext, WalletActivity.class) + .setAction(Intent.ACTION_VIEW) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + } else { + if (mQuickAccessWalletClient.createWalletIntent() == null) { + Log.w(TAG, "Could not get intent of the wallet app."); + return; + } + mActivityStarter.postStartActivityDismissingKeyguard( + mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0); + } + } + + private class WalletCardRetriever implements + QuickAccessWalletClient.OnWalletCardsRetrievedCallback { + + @Override + public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) { + mHasCard = !response.getWalletCards().isEmpty(); + updateWalletVisibility(); + } + + @Override + public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) { + mHasCard = false; + updateWalletVisibility(); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 7032aefc7a4dd..6a35293def766 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -53,6 +53,7 @@ import android.os.Bundle; import android.os.PowerManager; import android.os.SystemClock; import android.os.UserManager; +import android.service.quickaccesswallet.QuickAccessWalletClient; import android.util.Log; import android.util.MathUtils; import android.view.DisplayCutout; @@ -154,6 +155,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.Function; @@ -517,6 +519,9 @@ public class NotificationPanelViewController extends PanelViewController { private int mOldLayoutDirection; private NotificationShelfController mNotificationShelfController; + private final QuickAccessWalletClient mQuickAccessWalletClient; + private final Executor mUiExecutor; + private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() { @@ -578,7 +583,9 @@ public class NotificationPanelViewController extends PanelViewController { NotificationShadeDepthController notificationShadeDepthController, AmbientState ambientState, LockIconViewController lockIconViewController, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + QuickAccessWalletClient quickAccessWalletClient, + @Main Executor uiExecutor) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(), @@ -624,6 +631,8 @@ public class NotificationPanelViewController extends PanelViewController { mScrimController = scrimController; mUserManager = userManager; mMediaDataManager = mediaDataManager; + mQuickAccessWalletClient = quickAccessWalletClient; + mUiExecutor = uiExecutor; pulseExpansionHandler.setPulseExpandAbortListener(() -> { if (mQs != null) { mQs.animateHeaderSlidingOut(); @@ -975,6 +984,9 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper); mKeyguardBottomArea.setStatusBar(mStatusBar); mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete); + mKeyguardBottomArea.setFalsingManager(mFalsingManager); + mKeyguardBottomArea.initWallet(mQuickAccessWalletClient, mUiExecutor, + mFeatureFlags.isQuickAccessWalletEnabled()); } private void updateMaxDisplayedNotifications(boolean recompute) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 7d052b910cc62..cebf8be491504 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -39,6 +39,7 @@ 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; @@ -98,6 +99,8 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import com.android.wm.shell.animation.FlingAnimationUtils; import org.junit.Before; @@ -235,6 +238,8 @@ public class NotificationPanelViewTest extends SysuiTestCase { private UiEventLogger mUiEventLogger; @Mock private LockIconViewController mLockIconViewController; + @Mock + private QuickAccessWalletClient mQuickAccessWalletClient; private SysuiStatusBarStateController mStatusBarStateController; private NotificationPanelViewController mNotificationPanelViewController; @@ -339,7 +344,9 @@ public class NotificationPanelViewTest extends SysuiTestCase { mNotificationShadeDepthController, mAmbientState, mLockIconViewController, - mFeatureFlags); + mFeatureFlags, + mQuickAccessWalletClient, + new FakeExecutor(new FakeSystemClock())); mNotificationPanelViewController.initDependencies( mStatusBar, mNotificationShelfController);