1 /* 2 * Copyright (C) 2014 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 package com.android.nfc.cardemulation; 17 18 import android.annotation.TargetApi; 19 import android.app.ActivityManager; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.database.ContentObserver; 23 import android.net.Uri; 24 import android.nfc.ComponentNameAndUser; 25 import android.nfc.Constants; 26 import android.nfc.PackageAndUser; 27 import android.nfc.cardemulation.ApduServiceInfo; 28 import android.nfc.cardemulation.CardEmulation; 29 import android.nfc.cardemulation.Utils; 30 import android.os.Build; 31 import android.os.Handler; 32 import android.os.Looper; 33 import android.os.UserHandle; 34 import android.os.UserManager; 35 import android.provider.Settings; 36 import android.provider.Settings.SettingNotFoundException; 37 import android.sysprop.NfcProperties; 38 import android.util.Log; 39 import android.util.proto.ProtoOutputStream; 40 41 import com.android.nfc.ForegroundUtils; 42 43 import java.io.FileDescriptor; 44 import java.io.PrintWriter; 45 import java.util.ArrayList; 46 import java.util.List; 47 import java.util.Objects; 48 49 /** 50 * This class keeps track of what HCE/SE-based services are 51 * preferred by the user. It currently has 3 inputs: 52 * 1) The default set in tap&pay menu for payment category 53 * 2) An app in the foreground asking for a specific 54 * service for a specific category 55 * 3) If we had to disambiguate a previous tap (because no 56 * preferred service was there), we need to temporarily 57 * store the user's choice for the next tap. 58 * 59 * This class keeps track of all 3 inputs, and computes a new 60 * preferred services as needed. It then passes this service 61 * (if it changed) through a callback, which allows other components 62 * to adapt as necessary (ie the AID cache can update its AID 63 * mappings and the routing table). 64 */ 65 public class PreferredServices implements com.android.nfc.ForegroundUtils.Callback { 66 static final String TAG = "PreferredCardEmulationServices"; 67 static final boolean DBG = NfcProperties.debug_enabled().orElse(true); 68 static final Uri paymentDefaultUri = Settings.Secure.getUriFor( 69 Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT); 70 static final Uri paymentForegroundUri = Settings.Secure.getUriFor( 71 Constants.SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND); 72 73 final SettingsObserver mSettingsObserver; 74 final Context mContext; 75 final WalletRoleObserver mWalletRoleObserver; 76 final RegisteredServicesCache mServiceCache; 77 final RegisteredAidCache mAidCache; 78 final Callback mCallback; 79 final ForegroundUtils mForegroundUtils; 80 final Handler mHandler = new Handler(Looper.getMainLooper()); 81 82 final class PaymentDefaults { 83 boolean preferForeground; // The current selection mode for this category 84 ComponentName settingsDefault; // The component preferred in settings (eg Tap&Pay) 85 ComponentName currentPreferred; // The computed preferred component 86 UserHandle mUserHandle; 87 } 88 89 final Object mLock = new Object(); 90 // Variables below synchronized on mLock 91 PaymentDefaults mPaymentDefaults = new PaymentDefaults(); 92 93 ComponentName mForegroundRequested; // The component preferred by fg app 94 int mForegroundUid; // The UID of the fg app, or -1 if fg app didn't request 95 96 ComponentName mNextTapDefault; // The component preferred by active disambig dialog 97 int mNextTapDefaultUserId; 98 boolean mClearNextTapDefault = false; // Set when the next tap default must be cleared 99 100 ComponentName mForegroundCurrent; // The currently computed foreground component 101 int mForegroundCurrentUid; // The UID of the currently computed foreground component 102 103 ComponentName mDefaultWalletHolderPaymentService; 104 105 int mUserIdDefaultWalletHolder; 106 107 public interface Callback { 108 /** 109 * Notify when preferred payment service is changed 110 */ onPreferredPaymentServiceChanged(ComponentNameAndUser service)111 void onPreferredPaymentServiceChanged(ComponentNameAndUser service); 112 /** 113 * Notify when preferred foreground service is changed 114 */ onPreferredForegroundServiceChanged(ComponentNameAndUser service)115 void onPreferredForegroundServiceChanged(ComponentNameAndUser service); 116 } 117 PreferredServices(Context context, RegisteredServicesCache serviceCache, RegisteredAidCache aidCache, WalletRoleObserver walletRoleObserver, Callback callback)118 public PreferredServices(Context context, RegisteredServicesCache serviceCache, 119 RegisteredAidCache aidCache, WalletRoleObserver walletRoleObserver, 120 Callback callback) { 121 mContext = context; 122 mWalletRoleObserver = walletRoleObserver; 123 mForegroundUtils = ForegroundUtils.getInstance( 124 context.getSystemService(ActivityManager.class)); 125 mServiceCache = serviceCache; 126 mAidCache = aidCache; 127 mCallback = callback; 128 mSettingsObserver = new SettingsObserver(mHandler); 129 mContext.getContentResolver().registerContentObserverAsUser( 130 paymentDefaultUri, 131 true, mSettingsObserver, UserHandle.ALL); 132 133 mContext.getContentResolver().registerContentObserverAsUser( 134 paymentForegroundUri, 135 true, mSettingsObserver, UserHandle.ALL); 136 137 int currentUserId = ActivityManager.getCurrentUser(); 138 139 // Load current settings defaults for payments 140 loadDefaultsFromSettings(currentUserId, false); 141 142 if (mWalletRoleObserver.isWalletRoleFeatureEnabled()) { 143 PackageAndUser holder = mWalletRoleObserver.getDefaultWalletRoleHolder( 144 currentUserId); 145 onWalletRoleHolderChanged(holder.getPackage(), holder.getUserId()); 146 } 147 } 148 149 private final class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler)150 public SettingsObserver(Handler handler) { 151 super(handler); 152 } 153 154 @Override onChange(boolean selfChange, Uri uri)155 public void onChange(boolean selfChange, Uri uri) { 156 super.onChange(selfChange, uri); 157 // Do it just for the current user. If it was in fact 158 // a change made for another user, we'll sync it down 159 // on user switch. 160 int currentUser = ActivityManager.getCurrentUser(); 161 loadDefaultsFromSettings(currentUser, false); 162 } 163 }; 164 165 @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) onWalletRoleHolderChanged(String defaultWalletHolderPackageName, int userId)166 public void onWalletRoleHolderChanged(String defaultWalletHolderPackageName, int userId) { 167 if (defaultWalletHolderPackageName == null) { 168 mDefaultWalletHolderPaymentService = null; 169 mUserIdDefaultWalletHolder = userId; 170 mCallback.onPreferredPaymentServiceChanged(new ComponentNameAndUser(userId, null)); 171 return; 172 } 173 List<ApduServiceInfo> serviceInfos = mServiceCache.getInstalledServices(userId); 174 List<ComponentName> roleHolderPaymentServices = new ArrayList<>(); 175 int servicesCount = serviceInfos.size(); 176 for (int i = 0; i < servicesCount; i++) { 177 ApduServiceInfo serviceInfo = serviceInfos.get(i); 178 ComponentName componentName = serviceInfo.getComponent(); 179 if (componentName.getPackageName() 180 .equals(defaultWalletHolderPackageName)) { 181 List<String> aids = serviceInfo.getAids(); 182 int aidsCount = aids.size(); 183 for (int j = 0; j < aidsCount; j++) { 184 String aid = aids.get(j); 185 if (serviceInfo.getCategoryForAid(aid) 186 .equals(CardEmulation.CATEGORY_PAYMENT)) { 187 roleHolderPaymentServices.add(componentName); 188 break; 189 } 190 } 191 } 192 } 193 ComponentName candidate = !roleHolderPaymentServices.isEmpty() 194 ? roleHolderPaymentServices.get(0) : null; 195 if (!Objects.equals(candidate, mDefaultWalletHolderPaymentService) || 196 userId != mUserIdDefaultWalletHolder) { 197 mDefaultWalletHolderPaymentService = candidate; 198 mUserIdDefaultWalletHolder = userId; 199 mCallback.onPreferredPaymentServiceChanged(new ComponentNameAndUser(userId, candidate)); 200 } 201 } 202 loadDefaultsFromSettings(int userId, boolean force)203 void loadDefaultsFromSettings(int userId, boolean force) { 204 boolean paymentDefaultChanged = false; 205 boolean paymentPreferForegroundChanged = false; 206 // Load current payment default from settings 207 UserHandle currentUser = UserHandle.of(ActivityManager.getCurrentUser()); 208 UserManager um = mContext.createContextAsUser(currentUser, /*flags=*/0) 209 .getSystemService(UserManager.class); 210 List<UserHandle> userHandles = um.getEnabledProfiles(); 211 212 String name = null; 213 String newDefaultName = null; 214 UserHandle newUser = null; 215 // search for default payment setting within enabled profiles 216 for (UserHandle uh : userHandles) { 217 try { 218 name = Settings.Secure.getString( 219 mContext.createContextAsUser(uh, 0).getContentResolver(), 220 Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT); 221 } catch (IllegalStateException e) { 222 Log.d(TAG, 223 "loadDefaultsFromSettings: Fail to get default payment component for user: " 224 + uh); 225 continue; 226 } 227 228 if (name != null) { 229 newUser = uh; 230 newDefaultName = name; 231 } 232 if (uh.getIdentifier() == userId) { 233 currentUser = uh; 234 } 235 } 236 if (currentUser == null) { 237 Log.e(TAG, "loadDefaultsFromSettings: NULL/ Error fetching currentUser info"); 238 return; 239 } 240 // no default payment setting in all profles 241 if (newUser == null) { 242 newUser = currentUser; 243 } 244 ComponentName newDefault = newDefaultName != null 245 ? ComponentName.unflattenFromString(newDefaultName) : null; 246 boolean preferForeground = false; 247 try { 248 // get the setting from the main user instead of from the user profiles. 249 preferForeground = mWalletRoleObserver.isWalletRoleFeatureEnabled() 250 || Settings.Secure.getInt(mContext 251 .createContextAsUser(currentUser, 0).getContentResolver(), 252 Constants.SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND) != 0; 253 } catch (SettingNotFoundException e) { 254 } 255 synchronized (mLock) { 256 paymentPreferForegroundChanged = (preferForeground != mPaymentDefaults.preferForeground); 257 mPaymentDefaults.preferForeground = preferForeground; 258 259 mPaymentDefaults.settingsDefault = newDefault; 260 if (newDefault != null && (!newDefault.equals(mPaymentDefaults.currentPreferred) 261 || mPaymentDefaults.mUserHandle.getIdentifier() != newUser.getIdentifier())) { 262 paymentDefaultChanged = true; 263 mPaymentDefaults.currentPreferred = newDefault; 264 mPaymentDefaults.mUserHandle = newUser; 265 } else if (newDefault == null && mPaymentDefaults.currentPreferred != null) { 266 paymentDefaultChanged = true; 267 mPaymentDefaults.currentPreferred = newDefault; 268 mPaymentDefaults.mUserHandle = newUser; 269 } else { 270 // Same default as before 271 } 272 } 273 // Notify if anything changed 274 if (!mWalletRoleObserver.isWalletRoleFeatureEnabled() && (paymentDefaultChanged || force)) { 275 mCallback.onPreferredPaymentServiceChanged( 276 new ComponentNameAndUser(newUser.getIdentifier(), newDefault)); 277 } 278 if (paymentPreferForegroundChanged || force) { 279 computePreferredForegroundService(); 280 } 281 } 282 computePreferredForegroundService()283 void computePreferredForegroundService() { 284 ComponentName preferredService = null; 285 int preferredServiceUserId; 286 boolean changed = false; 287 synchronized (mLock) { 288 // Prio 1: next tap default 289 preferredService = mNextTapDefault; 290 preferredServiceUserId = mNextTapDefaultUserId; 291 if (preferredService == null) { 292 // Prio 2: foreground requested by app 293 preferredService = mForegroundRequested; 294 preferredServiceUserId = 295 UserHandle.getUserHandleForUid(mForegroundUid).getIdentifier(); 296 } 297 if (preferredService != null && (!preferredService.equals(mForegroundCurrent) 298 || preferredServiceUserId 299 != UserHandle.getUserHandleForUid(mForegroundCurrentUid).getIdentifier())) { 300 mForegroundCurrent = preferredService; 301 mForegroundCurrentUid = mForegroundUid; 302 changed = true; 303 } else if (preferredService == null && mForegroundCurrent != null) { 304 mForegroundCurrent = preferredService; 305 mForegroundCurrentUid = mForegroundUid; 306 changed = true; 307 } 308 } 309 // Notify if anything changed 310 if (changed) { 311 mCallback.onPreferredForegroundServiceChanged( 312 new ComponentNameAndUser(preferredServiceUserId, preferredService)); 313 } 314 } 315 316 /** 317 * Set default service for next tap 318 */ setDefaultForNextTap(int userId, ComponentName service)319 public boolean setDefaultForNextTap(int userId, ComponentName service) { 320 // This is a trusted API, so update without checking 321 synchronized (mLock) { 322 mNextTapDefault = service; 323 mNextTapDefaultUserId = userId; 324 } 325 computePreferredForegroundService(); 326 return true; 327 } 328 onServicesUpdated()329 public void onServicesUpdated() { 330 // If this service is the current foreground service, verify 331 // there are no conflicts 332 boolean foregroundChanged = false; 333 synchronized (mLock) { 334 // Check if the current foreground service is still allowed to override; 335 // it could have registered new AIDs that make it conflict with user 336 // preferences. 337 if (mForegroundCurrent != null) { 338 if (!isForegroundAllowedLocked(mForegroundCurrent, mForegroundCurrentUid)) { 339 Log.d(TAG, "onServicesUpdated: Removing foreground preferred service."); 340 mForegroundRequested = null; 341 mForegroundUid = -1; 342 mForegroundCurrentUid = -1; 343 foregroundChanged = true; 344 } 345 } else { 346 // Don't care about this service 347 } 348 } 349 if (foregroundChanged) { 350 computePreferredForegroundService(); 351 } 352 353 if (mWalletRoleObserver.isWalletRoleFeatureEnabled() 354 && mUserIdDefaultWalletHolder >= 0) { 355 PackageAndUser roleHolder = mWalletRoleObserver 356 .getDefaultWalletRoleHolder(mUserIdDefaultWalletHolder); 357 onWalletRoleHolderChanged(roleHolder.getPackage(), roleHolder.getUserId()); 358 } 359 } 360 361 // Verifies whether a service is allowed to register as preferred isForegroundAllowedLocked(ComponentName service, int callingUid)362 boolean isForegroundAllowedLocked(ComponentName service, int callingUid) { 363 if (service.equals(mPaymentDefaults.currentPreferred)) { 364 // If the requester is already the payment default, allow it to request foreground 365 // override as well (it could use this to make sure it handles AIDs of category OTHER) 366 return true; 367 } 368 ApduServiceInfo serviceInfo = mServiceCache.getService( 369 UserHandle.getUserHandleForUid(callingUid).getIdentifier(), service); 370 if (serviceInfo == null) { 371 Log.d(TAG, "isForegroundAllowedLocked: Requested foreground service " 372 + "unexpectedly removed"); 373 return false; 374 } 375 // Do some quick checking 376 if (!mPaymentDefaults.preferForeground) { 377 // Foreground apps are not allowed to override payment default 378 // Check if this app registers payment AIDs, in which case we'll fail anyway 379 if (serviceInfo.hasCategory(CardEmulation.CATEGORY_PAYMENT)) { 380 Log.d(TAG, "isForegroundAllowedLocked: User doesn't allow payment " 381 + "services to be overridden"); 382 return false; 383 } 384 // If no payment AIDs, get AIDs of category other, and see if there's any 385 // conflict with payment AIDs of current default payment app. That means 386 // the current default payment app said this was a payment AID, and the 387 // foreground app says it was not. In this case we'll still prefer the payment 388 // app, since that is the one that the user has explicitly selected (and said 389 // it's not allowed to be overridden). 390 final List<String> otherAids = serviceInfo.getAids(); 391 ApduServiceInfo paymentServiceInfo = mServiceCache.getService( 392 mPaymentDefaults.mUserHandle.getIdentifier(), 393 mPaymentDefaults.currentPreferred); 394 if (paymentServiceInfo != null && otherAids != null && otherAids.size() > 0) { 395 for (String aid : otherAids) { 396 RegisteredAidCache.AidResolveInfo resolveInfo = mAidCache.resolveAid(aid); 397 if (CardEmulation.CATEGORY_PAYMENT.equals(resolveInfo.category) && 398 paymentServiceInfo.equals(resolveInfo.defaultService)) { 399 if (DBG) { 400 Log.d(TAG, "isForegroundAllowedLocked: AID " + aid 401 + " is handled by the default payment app," 402 + " and the user has not allowed payments to be overridden."); 403 } 404 return false; 405 } 406 } 407 return true; 408 } else { 409 // Could not find payment service or fg app doesn't register other AIDs; 410 // okay to proceed. 411 return true; 412 } 413 } else { 414 // Payment allows override, so allow anything. 415 return true; 416 } 417 } 418 registerPreferredForegroundService(ComponentName service, int callingUid)419 public boolean registerPreferredForegroundService(ComponentName service, int callingUid) { 420 boolean success = false; 421 synchronized (mLock) { 422 if (isForegroundAllowedLocked(service, callingUid)) { 423 if (mForegroundUtils.registerUidToBackgroundCallback(this, callingUid)) { 424 mForegroundRequested = service; 425 mForegroundUid = callingUid; 426 success = true; 427 } else { 428 Log.e(TAG, "registerPreferredForegroundService: Calling UID is not in " 429 + "the foreground, ignoring!"); 430 success = false; 431 } 432 } else { 433 Log.e(TAG, "registerPreferredForegroundService: Requested foreground service " 434 + "conflicts or was removed"); 435 } 436 } 437 if (success) { 438 computePreferredForegroundService(); 439 } 440 return success; 441 } 442 unregisterForegroundService(int uid)443 boolean unregisterForegroundService(int uid) { 444 boolean success = false; 445 synchronized (mLock) { 446 if (mForegroundUid == uid) { 447 mForegroundRequested = null; 448 mForegroundUid = -1; 449 success = true; 450 } // else, other UID in foreground 451 } 452 if (success) { 453 computePreferredForegroundService(); 454 } 455 return success; 456 } 457 unregisteredPreferredForegroundService(int callingUid)458 public boolean unregisteredPreferredForegroundService(int callingUid) { 459 // Verify the calling UID is in the foreground 460 if (mForegroundUtils.isInForeground(callingUid)) { 461 return unregisterForegroundService(callingUid); 462 } else { 463 Log.e(TAG, "unregisteredPreferredForegroundService: Calling UID is not in " 464 + "the foreground, ignoring!"); 465 return false; 466 } 467 } 468 469 @Override onUidToBackground(int uid)470 public void onUidToBackground(int uid) { 471 unregisterForegroundService(uid); 472 } 473 onHostEmulationActivated()474 public void onHostEmulationActivated() { 475 synchronized (mLock) { 476 mClearNextTapDefault = (mNextTapDefault != null); 477 } 478 } 479 onHostEmulationDeactivated()480 public void onHostEmulationDeactivated() { 481 // If we had any next tap defaults set, clear them out 482 boolean changed = false; 483 synchronized (mLock) { 484 if (mClearNextTapDefault) { 485 // The reason we need to check this boolean is because the next tap 486 // default may have been set while the user held the phone 487 // on the reader; when the user then removes his phone from 488 // the reader (causing the "onHostEmulationDeactivated" event), 489 // the next tap default would immediately be cleared 490 // again. Instead, clear out defaults only if a next tap default 491 // had already been set at time of activation, which is captured 492 // by mClearNextTapDefault. 493 if (mNextTapDefault != null) { 494 mNextTapDefault = null; 495 changed = true; 496 } 497 mClearNextTapDefault = false; 498 } 499 } 500 if (changed) { 501 computePreferredForegroundService(); 502 } 503 } 504 onUserSwitched(int userId)505 public void onUserSwitched(int userId) { 506 loadDefaultsFromSettings(userId, true); 507 } 508 packageHasPreferredService(String packageName)509 public boolean packageHasPreferredService(String packageName) { 510 if (packageName == null) return false; 511 synchronized (mLock) { 512 if (mPaymentDefaults.currentPreferred != null 513 && packageName.equals(mPaymentDefaults.currentPreferred.getPackageName())) { 514 return true; 515 } 516 return (mForegroundCurrent != null 517 && packageName.equals(mForegroundCurrent.getPackageName())); 518 } 519 } 520 dump(FileDescriptor fd, PrintWriter pw, String[] args)521 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 522 synchronized (mLock) { 523 pw.println("Preferred services (in order of importance): "); 524 pw.println(" *** Current preferred foreground service: " + mForegroundCurrent 525 + " (UID:" + mForegroundCurrentUid + ")"); 526 if (mWalletRoleObserver.isWalletRoleFeatureEnabled()) { 527 boolean roleNotSet = mDefaultWalletHolderPaymentService == null; 528 pw.println(" *** Current wallet payment service: " 529 + (roleNotSet ? "null" : 530 mDefaultWalletHolderPaymentService) + "(" 531 + (roleNotSet ? "no user" 532 : getUserName(UserHandle.of(mUserIdDefaultWalletHolder))) + ")"); 533 } 534 pw.println(" *** Current preferred payment service: " 535 + mPaymentDefaults.currentPreferred + "(" 536 + getUserName(mPaymentDefaults.mUserHandle) + ")"); 537 pw.println(" Next tap default: " + mNextTapDefault 538 + " (" + getUserName(UserHandle.of(mNextTapDefaultUserId)) + ")"); 539 pw.println(" Default for foreground app (UID: " + mForegroundUid 540 + "): " + mForegroundRequested); 541 if (!mWalletRoleObserver.isWalletRoleFeatureEnabled()) { 542 pw.println(" Default in payment settings: " + mPaymentDefaults.settingsDefault 543 + "(" + getUserName(mPaymentDefaults.mUserHandle) + ")"); 544 pw.println(" Payment settings allows override: " 545 + mPaymentDefaults.preferForeground); 546 } 547 pw.println(""); 548 } 549 } 550 getUserName(UserHandle uh)551 private String getUserName(UserHandle uh) { 552 if (uh == null) { 553 return null; 554 } 555 UserManager um = mContext.createContextAsUser( 556 uh, /*flags=*/0).getSystemService(UserManager.class); 557 if (um == null) { 558 return null; 559 } 560 return com.android.nfc.Utils.maskSubstring(um.getUserName(), 3); 561 } 562 563 /** 564 * Dump debugging information as a PreferredServicesProto 565 * 566 * Note: 567 * See proto definition in frameworks/base/core/proto/android/nfc/card_emulation.proto 568 * When writing a nested message, must call {@link ProtoOutputStream#start(long)} before and 569 * {@link ProtoOutputStream#end(long)} after. 570 * Never reuse a proto field number. When removing a field, mark it as reserved. 571 */ dumpDebug(ProtoOutputStream proto)572 void dumpDebug(ProtoOutputStream proto) { 573 synchronized (mLock) { 574 if (mForegroundCurrent != null) { 575 Utils.dumpDebugComponentName( 576 mForegroundCurrent, proto, PreferredServicesProto.FOREGROUND_CURRENT); 577 } 578 if (mPaymentDefaults.currentPreferred != null) { 579 Utils.dumpDebugComponentName( 580 mPaymentDefaults.currentPreferred, proto, 581 PreferredServicesProto.FOREGROUND_CURRENT); 582 } 583 if (mWalletRoleObserver.isWalletRoleFeatureEnabled()) { 584 if (mDefaultWalletHolderPaymentService != null) { 585 Utils.dumpDebugComponentName( 586 mDefaultWalletHolderPaymentService, proto, 587 PreferredServicesProto.WALLET_ROLE_HOLDER_PAYMENT_SERVICE); 588 } 589 } 590 if (mNextTapDefault != null) { 591 Utils.dumpDebugComponentName( 592 mNextTapDefault, proto, PreferredServicesProto.NEXT_TAP_DEFAULT); 593 } 594 proto.write(PreferredServicesProto.FOREGROUND_UID, mForegroundUid); 595 if (mForegroundRequested != null) { 596 Utils.dumpDebugComponentName( 597 mForegroundRequested, proto, PreferredServicesProto.FOREGROUND_REQUESTED); 598 } 599 if (!mWalletRoleObserver.isWalletRoleFeatureEnabled()) { 600 if (mPaymentDefaults.settingsDefault != null) { 601 Utils.dumpDebugComponentName( 602 mPaymentDefaults.settingsDefault, proto, 603 PreferredServicesProto.SETTINGS_DEFAULT); 604 } 605 proto.write(PreferredServicesProto.PREFER_FOREGROUND, 606 mPaymentDefaults.preferForeground); 607 } 608 } 609 } 610 } 611