1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.wallet.ui; 18 19 import static android.provider.Settings.ACTION_LOCKSCREEN_SETTINGS; 20 21 import android.content.Intent; 22 import android.graphics.drawable.Drawable; 23 import android.hardware.biometrics.BiometricSourceType; 24 import android.os.Bundle; 25 import android.os.Handler; 26 import android.service.quickaccesswallet.QuickAccessWalletClient; 27 import android.service.quickaccesswallet.WalletServiceEvent; 28 import android.util.Log; 29 import android.view.Menu; 30 import android.view.MenuItem; 31 import android.view.Window; 32 import android.view.WindowManager; 33 import android.widget.Toolbar; 34 35 import androidx.activity.ComponentActivity; 36 import androidx.annotation.NonNull; 37 import androidx.annotation.Nullable; 38 39 import com.android.internal.logging.UiEventLogger; 40 import com.android.keyguard.KeyguardUpdateMonitor; 41 import com.android.keyguard.KeyguardUpdateMonitorCallback; 42 import com.android.settingslib.Utils; 43 import com.android.systemui.R; 44 import com.android.systemui.classifier.FalsingCollector; 45 import com.android.systemui.dagger.qualifiers.Background; 46 import com.android.systemui.dagger.qualifiers.Main; 47 import com.android.systemui.plugins.ActivityStarter; 48 import com.android.systemui.plugins.FalsingManager; 49 import com.android.systemui.settings.UserTracker; 50 import com.android.systemui.statusbar.phone.KeyguardDismissUtil; 51 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; 52 import com.android.systemui.statusbar.policy.KeyguardStateController; 53 54 import java.util.concurrent.Executor; 55 56 import javax.inject.Inject; 57 58 /** 59 * Displays Wallet carousel screen inside an activity. 60 */ 61 public class WalletActivity extends ComponentActivity implements 62 QuickAccessWalletClient.WalletServiceEventListener { 63 64 private static final String TAG = "WalletActivity"; 65 private final KeyguardStateController mKeyguardStateController; 66 private final KeyguardDismissUtil mKeyguardDismissUtil; 67 private final ActivityStarter mActivityStarter; 68 private final Executor mExecutor; 69 private final Handler mHandler; 70 private final FalsingManager mFalsingManager; 71 private FalsingCollector mFalsingCollector; 72 private final UserTracker mUserTracker; 73 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; 74 private final StatusBarKeyguardViewManager mKeyguardViewManager; 75 private final UiEventLogger mUiEventLogger; 76 77 private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback; 78 private WalletScreenController mWalletScreenController; 79 private QuickAccessWalletClient mWalletClient; 80 private boolean mHasRegisteredListener; 81 82 @Inject WalletActivity( KeyguardStateController keyguardStateController, KeyguardDismissUtil keyguardDismissUtil, ActivityStarter activityStarter, @Background Executor executor, @Main Handler handler, FalsingManager falsingManager, FalsingCollector falsingCollector, UserTracker userTracker, KeyguardUpdateMonitor keyguardUpdateMonitor, StatusBarKeyguardViewManager keyguardViewManager, UiEventLogger uiEventLogger)83 public WalletActivity( 84 KeyguardStateController keyguardStateController, 85 KeyguardDismissUtil keyguardDismissUtil, 86 ActivityStarter activityStarter, 87 @Background Executor executor, 88 @Main Handler handler, 89 FalsingManager falsingManager, 90 FalsingCollector falsingCollector, 91 UserTracker userTracker, 92 KeyguardUpdateMonitor keyguardUpdateMonitor, 93 StatusBarKeyguardViewManager keyguardViewManager, 94 UiEventLogger uiEventLogger) { 95 mKeyguardStateController = keyguardStateController; 96 mKeyguardDismissUtil = keyguardDismissUtil; 97 mActivityStarter = activityStarter; 98 mExecutor = executor; 99 mHandler = handler; 100 mFalsingManager = falsingManager; 101 mFalsingCollector = falsingCollector; 102 mUserTracker = userTracker; 103 mKeyguardUpdateMonitor = keyguardUpdateMonitor; 104 mKeyguardViewManager = keyguardViewManager; 105 mUiEventLogger = uiEventLogger; 106 } 107 108 @Override onCreate(@ullable Bundle savedInstanceState)109 protected void onCreate(@Nullable Bundle savedInstanceState) { 110 super.onCreate(savedInstanceState); 111 112 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 113 requestWindowFeature(Window.FEATURE_NO_TITLE); 114 setContentView(R.layout.quick_access_wallet); 115 116 Toolbar toolbar = findViewById(R.id.action_bar); 117 if (toolbar != null) { 118 setActionBar(toolbar); 119 } 120 getActionBar().setDisplayShowTitleEnabled(false); 121 getActionBar().setDisplayHomeAsUpEnabled(true); 122 getActionBar().setHomeAsUpIndicator(getHomeIndicatorDrawable()); 123 getActionBar().setHomeActionContentDescription(R.string.accessibility_desc_close); 124 WalletView walletView = requireViewById(R.id.wallet_view); 125 126 mWalletClient = QuickAccessWalletClient.create(this, mExecutor); 127 mWalletScreenController = new WalletScreenController( 128 this, 129 walletView, 130 mWalletClient, 131 mActivityStarter, 132 mExecutor, 133 mHandler, 134 mUserTracker, 135 mFalsingManager, 136 mKeyguardUpdateMonitor, 137 mKeyguardStateController, 138 mUiEventLogger); 139 mKeyguardUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { 140 @Override 141 public void onBiometricRunningStateChanged( 142 boolean running, 143 BiometricSourceType biometricSourceType) { 144 Log.d(TAG, "Biometric running state has changed."); 145 mWalletScreenController.queryWalletCards(); 146 } 147 }; 148 149 walletView.setFalsingCollector(mFalsingCollector); 150 walletView.setShowWalletAppOnClickListener( 151 v -> { 152 if (mWalletClient.createWalletIntent() == null) { 153 Log.w(TAG, "Unable to create wallet app intent."); 154 return; 155 } 156 if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { 157 return; 158 } 159 160 if (mKeyguardStateController.isUnlocked()) { 161 mUiEventLogger.log(WalletUiEvent.QAW_SHOW_ALL); 162 mActivityStarter.startActivity( 163 mWalletClient.createWalletIntent(), true); 164 finish(); 165 } else { 166 mUiEventLogger.log(WalletUiEvent.QAW_UNLOCK_FROM_SHOW_ALL_BUTTON); 167 mKeyguardDismissUtil.executeWhenUnlocked(() -> { 168 mUiEventLogger.log(WalletUiEvent.QAW_SHOW_ALL); 169 mActivityStarter.startActivity( 170 mWalletClient.createWalletIntent(), true); 171 finish(); 172 return false; 173 }, false, true); 174 } 175 }); 176 177 // Click the action button to re-render the screen when the device is unlocked. 178 walletView.setDeviceLockedActionOnClickListener( 179 v -> { 180 Log.d(TAG, "Wallet action button is clicked."); 181 if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { 182 Log.d(TAG, "False tap detected on wallet action button."); 183 return; 184 } 185 186 mUiEventLogger.log(WalletUiEvent.QAW_UNLOCK_FROM_UNLOCK_BUTTON); 187 mKeyguardDismissUtil.executeWhenUnlocked(() -> false, false, 188 false); 189 }); 190 } 191 192 @Override onStart()193 protected void onStart() { 194 super.onStart(); 195 if (!mHasRegisteredListener) { 196 // Listener is registered even when device is locked. Should only be registered once. 197 mWalletClient.addWalletServiceEventListener(this); 198 mHasRegisteredListener = true; 199 } 200 mKeyguardStateController.addCallback(mWalletScreenController); 201 mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); 202 } 203 204 @Override onResume()205 protected void onResume() { 206 super.onResume(); 207 mWalletScreenController.queryWalletCards(); 208 mKeyguardViewManager.requestFp( 209 true, 210 Utils.getColorAttrDefaultColor( 211 this, com.android.internal.R.attr.colorAccentPrimary)); 212 mKeyguardViewManager.requestFace(true); 213 } 214 215 @Override onPause()216 protected void onPause() { 217 super.onPause(); 218 mKeyguardViewManager.requestFp(false, -1); 219 mKeyguardViewManager.requestFace(false); 220 } 221 222 @Override onStop()223 protected void onStop() { 224 super.onStop(); 225 finish(); 226 } 227 228 @Override onCreateOptionsMenu(Menu menu)229 public boolean onCreateOptionsMenu(Menu menu) { 230 getMenuInflater().inflate(R.menu.wallet_activity_options_menu, menu); 231 return super.onCreateOptionsMenu(menu); 232 } 233 234 /** 235 * Implements {@link QuickAccessWalletClient.WalletServiceEventListener}. Called when the wallet 236 * application propagates an event, such as an NFC tap, to the quick access wallet view. 237 */ 238 @Override onWalletServiceEvent(WalletServiceEvent event)239 public void onWalletServiceEvent(WalletServiceEvent event) { 240 switch (event.getEventType()) { 241 case WalletServiceEvent.TYPE_NFC_PAYMENT_STARTED: 242 break; 243 case WalletServiceEvent.TYPE_WALLET_CARDS_UPDATED: 244 mWalletScreenController.queryWalletCards(); 245 break; 246 default: 247 Log.w(TAG, "onWalletServiceEvent: Unknown event type"); 248 } 249 } 250 251 @Override onOptionsItemSelected(@onNull MenuItem item)252 public boolean onOptionsItemSelected(@NonNull MenuItem item) { 253 int itemId = item.getItemId(); 254 if (itemId == android.R.id.home) { 255 finish(); 256 return true; 257 } else if (itemId == R.id.wallet_lockscreen_settings) { 258 Intent intent = 259 new Intent(ACTION_LOCKSCREEN_SETTINGS) 260 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 261 mActivityStarter.startActivity(intent, true); 262 return true; 263 } 264 return super.onOptionsItemSelected(item); 265 } 266 267 @Override onDestroy()268 protected void onDestroy() { 269 mKeyguardStateController.removeCallback(mWalletScreenController); 270 if (mKeyguardUpdateMonitorCallback != null) { 271 mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback); 272 } 273 mWalletScreenController.onDismissed(); 274 mWalletClient.removeWalletServiceEventListener(this); 275 mHasRegisteredListener = false; 276 super.onDestroy(); 277 } 278 getHomeIndicatorDrawable()279 private Drawable getHomeIndicatorDrawable() { 280 Drawable drawable = getDrawable(R.drawable.ic_close); 281 drawable.setTint(getColor(R.color.material_dynamic_neutral70)); 282 return drawable; 283 } 284 } 285