Merge cherrypicks of ['googleplex-android-review.googlesource.com/30596089', 'googleplex-android-review.googlesource.com/30595924', 'googleplex-android-review.googlesource.com/31157079', 'googleplex-android-review.googlesource.com/31105383', 'googleplex-android-review.googlesource.com/31095394'] into security-aosp-sc-release.

Change-Id: Id2957e5db5cb4f939ae2a3ec84d16cbcf9d389a1
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
old mode 100755
new mode 100644
index 0198168..f487bfb
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
@@ -51,6 +51,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -63,8 +64,6 @@
 import com.android.packageinstaller.television.UninstallAlertFragment;
 import com.android.packageinstaller.television.UninstallAppProgress;
 
-import java.util.List;
-
 /*
  * This activity presents UI to uninstall an application. Usually launched with intent
  * Intent.ACTION_UNINSTALL_PKG_COMMAND and attribute
@@ -172,13 +171,16 @@
         if (mDialogInfo.user == null) {
             mDialogInfo.user = android.os.Process.myUserHandle();
         } else {
-            UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
-            List<UserHandle> profiles = userManager.getUserProfiles();
-            if (!profiles.contains(mDialogInfo.user)) {
-                Log.e(TAG, "User " + android.os.Process.myUserHandle() + " can't request uninstall "
-                        + "for user " + mDialogInfo.user);
-                showUserIsNotAllowed();
-                return;
+            if (!mDialogInfo.user.equals(Process.myUserHandle())) {
+                UserManager userManager = getBaseContext().getSystemService(UserManager.class);
+                final boolean isCurrentUserProfileOwner = Process.myUserHandle().equals(
+                        userManager.getProfileParent(mDialogInfo.user));
+                if (!isCurrentUserProfileOwner) {
+                    Log.e(TAG, "User " + Process.myUserHandle() + " can't request uninstall "
+                            + "for user " + mDialogInfo.user);
+                    showUserIsNotAllowed();
+                    return;
+                }
             }
         }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
new file mode 100644
index 0000000..03c1f92
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -0,0 +1,545 @@
+/*
+ * 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.qs.tiles;
+
+import static android.content.pm.PackageManager.FEATURE_NFC_HOST_CARD_EMULATION;
+import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.service.quickaccesswallet.GetWalletCardsError;
+import android.service.quickaccesswallet.GetWalletCardsResponse;
+import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.service.quickaccesswallet.QuickAccessWalletService;
+import android.service.quickaccesswallet.WalletCard;
+import android.service.quicksettings.Tile;
+import android.testing.TestableLooper;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.QsEventLogger;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
+
+import org.junit.After;
+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;
+
+import java.util.Collections;
+
+@RunWith(AndroidJUnit4.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class QuickAccessWalletTileTest extends SysuiTestCase {
+
+    private static final String CARD_ID = "card_id";
+    private static final String LABEL = "QAW";
+    private static final String CARD_DESCRIPTION = "•••• 1234";
+    private static final Icon CARD_IMAGE =
+            Icon.createWithBitmap(Bitmap.createBitmap(70, 50, Bitmap.Config.ARGB_8888));
+    private static final Icon INVALID_CARD_IMAGE =
+            Icon.createWithContentUri("content://media/external/images/media");
+    private static final int PRIMARY_USER_ID = 0;
+    private static final int SECONDARY_USER_ID = 10;
+
+    private final Drawable mTileIcon = mContext.getDrawable(R.drawable.ic_qs_wallet);
+    private final Intent mWalletIntent = new Intent(QuickAccessWalletService.ACTION_VIEW_WALLET)
+            .setComponent(new ComponentName(mContext.getPackageName(), "WalletActivity"));
+
+    @Mock
+    private QSHost mHost;
+    @Mock
+    private MetricsLogger mMetricsLogger;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private ActivityStarter mActivityStarter;
+    @Mock
+    private QSLogger mQSLogger;
+    @Mock
+    private QsEventLogger mUiEventLogger;
+    @Mock
+    private QuickAccessWalletClient mQuickAccessWalletClient;
+    @Mock
+    private KeyguardStateController mKeyguardStateController;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private SecureSettings mSecureSettings;
+    @Mock
+    private QuickAccessWalletController mController;
+    @Mock
+    private Icon mCardImage;
+    @Captor
+    ArgumentCaptor<QuickAccessWalletClient.OnWalletCardsRetrievedCallback> mCallbackCaptor;
+
+    private Context mSpiedContext;
+    private TestableLooper mTestableLooper;
+    private QuickAccessWalletTile mTile;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mTestableLooper = TestableLooper.get(this);
+        mSpiedContext = spy(mContext);
+
+        doNothing().when(mSpiedContext).startActivity(any(Intent.class));
+        when(mHost.getContext()).thenReturn(mSpiedContext);
+        when(mQuickAccessWalletClient.getServiceLabel()).thenReturn(LABEL);
+        when(mQuickAccessWalletClient.getTileIcon()).thenReturn(mTileIcon);
+        when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
+        when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true);
+        when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(true);
+        when(mController.getWalletClient()).thenReturn(mQuickAccessWalletClient);
+        when(mCardImage.getType()).thenReturn(Icon.TYPE_URI);
+        when(mCardImage.loadDrawableAsUser(any(), eq(SECONDARY_USER_ID))).thenReturn(null);
+
+        mTile = new QuickAccessWalletTile(
+                mHost,
+                mUiEventLogger,
+                mTestableLooper.getLooper(),
+                new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
+                mMetricsLogger,
+                mStatusBarStateController,
+                mActivityStarter,
+                mQSLogger,
+                mKeyguardStateController,
+                mPackageManager,
+                mSecureSettings,
+                mController);
+
+        mTile.initialize();
+        mTestableLooper.processAllMessages();
+    }
+
+    @After
+    public void tearDown() {
+        mTile.destroy();
+        mTestableLooper.processAllMessages();
+    }
+
+    @Test
+    public void testNewTile() {
+        assertFalse(mTile.newTileState().handlesLongClick);
+    }
+
+    @Test
+    public void testWalletServiceUnavailable_recreateWalletClient() {
+        when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
+
+        mTile.handleSetListening(true);
+
+        verify(mController, times(1)).reCreateWalletClient();
+    }
+
+    @Test
+    public void testWalletFeatureUnavailable_recreateWalletClient() {
+        when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false);
+
+        mTile.handleSetListening(true);
+
+        verify(mController, times(1)).reCreateWalletClient();
+    }
+
+    @Test
+    public void testIsAvailable_qawFeatureAvailableWalletUnavailable() {
+        when(mController.isWalletRoleAvailable()).thenReturn(false);
+        when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(true);
+        when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
+        when(mSecureSettings.getStringForUser(NFC_PAYMENT_DEFAULT_COMPONENT,
+                UserHandle.USER_CURRENT)).thenReturn("Component");
+
+        assertTrue(mTile.isAvailable());
+    }
+
+    @Test
+    public void testIsAvailable_nfcUnavailableWalletAvailable() {
+        when(mController.isWalletRoleAvailable()).thenReturn(true);
+        when(mHost.getUserId()).thenReturn(PRIMARY_USER_ID);
+        when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(false);
+        when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
+
+        assertTrue(mTile.isAvailable());
+    }
+
+    @Test
+    public void testHandleClick_startQuickAccessUiIntent_noCard() {
+        setUpWalletCard(/* hasCard= */ false);
+
+        mTile.handleClick(/* view= */ null);
+        mTestableLooper.processAllMessages();
+
+        verify(mController).startQuickAccessUiIntent(
+                eq(mActivityStarter),
+                eq(null),
+                /* hasCard= */ eq(false));
+    }
+
+    @Test
+    public void testHandleClick_startQuickAccessUiIntent_hasCard() {
+        setUpWalletCard(/* hasCard= */ true);
+
+        mTile.handleClick(null /* view */);
+        mTestableLooper.processAllMessages();
+
+        verify(mController).startQuickAccessUiIntent(
+                eq(mActivityStarter),
+                eq(null),
+                /* hasCard= */ eq(true));
+    }
+
+    @Test
+    public void testHandleUpdateState_updateLabelAndIcon() {
+        QSTile.State state = new QSTile.State();
+
+        mTile.handleUpdateState(state, null);
+
+        assertEquals(LABEL, state.label.toString());
+        assertTrue(state.label.toString().contentEquals(state.contentDescription));
+        assertEquals(mTileIcon, state.icon.getDrawable(mContext));
+    }
+
+    @Test
+    public void testHandleUpdateState_updateLabelAndIcon_noIconFromApi() {
+        when(mQuickAccessWalletClient.getTileIcon()).thenReturn(null);
+        QSTile.State state = new QSTile.State();
+        QSTile.Icon icon = QSTileImpl.ResourceIcon.get(R.drawable.ic_wallet_lockscreen);
+
+        mTile.handleUpdateState(state, null);
+
+        assertEquals(LABEL, state.label.toString());
+        assertTrue(state.label.toString().contentEquals(state.contentDescription));
+        assertEquals(icon, state.icon);
+    }
+
+    @Test
+    public void testGetTileLabel_serviceLabelExists() {
+        assertEquals(LABEL, mTile.getTileLabel().toString());
+    }
+
+    @Test
+    public void testGetTileLabel_serviceLabelDoesNotExist() {
+        when(mQuickAccessWalletClient.getServiceLabel()).thenReturn(null);
+        assertEquals(mContext.getString(R.string.wallet_title), mTile.getTileLabel().toString());
+    }
+
+    @Test
+    public void testHandleUpdateState_walletIsUpdating() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+        QSTile.State state = new QSTile.State();
+        GetWalletCardsResponse response =
+                new GetWalletCardsResponse(
+                        Collections.singletonList(createWalletCard(mContext)), 0);
+
+        mTile.handleSetListening(true);
+
+        verify(mController).queryWalletCards(mCallbackCaptor.capture());
+
+        // Wallet cards fetching on its way; wallet updating.
+        mTile.handleUpdateState(state, null);
+
+        assertEquals(Tile.STATE_INACTIVE, state.state);
+        assertEquals(
+                mContext.getString(R.string.wallet_secondary_label_updating), state.secondaryLabel);
+        assertNotNull(state.stateDescription);
+        assertNull(state.sideViewCustomDrawable);
+
+        // Wallet cards fetching completed.
+        mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
+        mTestableLooper.processAllMessages();
+
+        mTile.handleUpdateState(state, null);
+
+        assertEquals(Tile.STATE_ACTIVE, state.state);
+        assertEquals(CARD_DESCRIPTION, state.secondaryLabel);
+        assertNotNull(state.stateDescription);
+        assertNotNull(state.sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testHandleUpdateState_hasCard_deviceLocked_tileInactive() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+        QSTile.State state = new QSTile.State();
+        setUpWalletCard(/* hasCard= */ true);
+
+        mTile.handleUpdateState(state, null);
+
+        assertEquals(Tile.STATE_INACTIVE, state.state);
+        assertEquals(CARD_DESCRIPTION, state.secondaryLabel);
+        assertNotNull(state.stateDescription);
+        assertNotNull(state.sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testHandleUpdateState_hasCard_deviceUnlocked_tileActive() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+        QSTile.State state = new QSTile.State();
+        setUpWalletCard(/* hasCard= */ true);
+
+        mTile.handleUpdateState(state, null);
+
+        assertEquals(Tile.STATE_ACTIVE, state.state);
+        assertEquals(CARD_DESCRIPTION, state.secondaryLabel);
+        assertNotNull(state.stateDescription);
+        assertNotNull(state.sideViewCustomDrawable);
+    }
+
+
+    @Test
+    public void testHandleUpdateState_noCard_tileInactive() {
+        QSTile.State state = new QSTile.State();
+        setUpWalletCard(/* hasCard= */ false);
+
+        mTile.handleUpdateState(state, null);
+
+        assertEquals(Tile.STATE_INACTIVE, state.state);
+        assertEquals(
+                mContext.getString(R.string.wallet_secondary_label_no_card),
+                state.secondaryLabel);
+        assertNotNull(state.stateDescription);
+        assertNull(state.sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testHandleUpdateState_qawServiceUnavailable_tileUnavailable() {
+        when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
+        QSTile.State state = new QSTile.State();
+
+        mTile.handleUpdateState(state, null);
+
+        assertEquals(Tile.STATE_UNAVAILABLE, state.state);
+        assertNull(state.stateDescription);
+        assertNull(state.sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testHandleUpdateState_qawFeatureUnavailable_tileUnavailable() {
+        when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false);
+        QSTile.State state = new QSTile.State();
+
+        mTile.handleUpdateState(state, null);
+
+        assertEquals(Tile.STATE_UNAVAILABLE, state.state);
+        assertNull(state.stateDescription);
+        assertNull(state.sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testHandleSetListening_queryCards() {
+        mTile.handleSetListening(true);
+
+        verify(mController).queryWalletCards(mCallbackCaptor.capture());
+
+        assertThat(mCallbackCaptor.getValue()).isInstanceOf(
+                QuickAccessWalletClient.OnWalletCardsRetrievedCallback.class);
+    }
+
+    @Test
+    public void testQueryCards_hasCards_updateSideViewDrawable() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+        setUpWalletCard(/* hasCard= */ true);
+
+        assertNotNull(mTile.getState().sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testQueryCards_notCurrentUser_hasCards_noSideViewDrawable() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(mContext, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
+        WalletCard walletCard =
+                new WalletCard.Builder(
+                        CARD_ID, mCardImage, CARD_DESCRIPTION, pendingIntent).build();
+        GetWalletCardsResponse response =
+                new GetWalletCardsResponse(Collections.singletonList(walletCard), 0);
+
+        mTile.handleSetListening(true);
+
+        verify(mController).queryWalletCards(mCallbackCaptor.capture());
+
+        mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
+        mTestableLooper.processAllMessages();
+
+        assertNull(mTile.getState().sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testQueryCards_cardDataPayment_updateSideViewDrawable() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+        setUpWalletCardWithType(/* hasCard =*/ true, WalletCard.CARD_TYPE_PAYMENT);
+
+        assertNotNull(mTile.getState().sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testQueryCards_cardDataNonPayment_updateSideViewDrawable() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+        setUpWalletCardWithType(/* hasCard =*/ true, WalletCard.CARD_TYPE_NON_PAYMENT);
+
+        assertNull(mTile.getState().sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testQueryCards_noCards_notUpdateSideViewDrawable() {
+        setUpWalletCard(/* hasCard= */ false);
+
+        assertNull(mTile.getState().sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testQueryCards_invalidDrawable_noSideViewDrawable() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+        setUpInvalidWalletCard(/* hasCard= */ true);
+
+        assertNull(mTile.getState().sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testQueryCards_error_notUpdateSideViewDrawable() {
+        String errorMessage = "getWalletCardsError";
+        GetWalletCardsError error = new GetWalletCardsError(CARD_IMAGE, errorMessage);
+
+        mTile.handleSetListening(true);
+
+        verify(mController).queryWalletCards(mCallbackCaptor.capture());
+
+        mCallbackCaptor.getValue().onWalletCardRetrievalError(error);
+        mTestableLooper.processAllMessages();
+
+        assertNull(mTile.getState().sideViewCustomDrawable);
+    }
+
+    @Test
+    public void testHandleSetListening_notListening_notQueryCards() {
+        mTile.handleSetListening(false);
+
+        verifyNoMoreInteractions(mQuickAccessWalletClient);
+    }
+
+    private WalletCard createWalletCardWithType(Context context, int cardType) {
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
+        return new WalletCard.Builder(CARD_ID, cardType, CARD_IMAGE, CARD_DESCRIPTION,
+                pendingIntent).build();
+    }
+
+    private void setUpWalletCardWithType(boolean hasCard, int cardType) {
+        GetWalletCardsResponse response =
+                new GetWalletCardsResponse(
+                        hasCard
+                                ? Collections.singletonList(
+                                createWalletCardWithType(mContext, cardType))
+                                : Collections.EMPTY_LIST, 0);
+
+        mTile.handleSetListening(true);
+
+        verify(mController).queryWalletCards(mCallbackCaptor.capture());
+
+        mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
+        mTestableLooper.processAllMessages();
+    }
+
+    private void setUpWalletCard(boolean hasCard) {
+        GetWalletCardsResponse response =
+                new GetWalletCardsResponse(
+                        hasCard
+                                ? Collections.singletonList(createWalletCard(mContext))
+                                : Collections.EMPTY_LIST, 0);
+
+        mTile.handleSetListening(true);
+
+        verify(mController).queryWalletCards(mCallbackCaptor.capture());
+
+        mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
+        mTestableLooper.processAllMessages();
+    }
+
+    private void setUpInvalidWalletCard(boolean hasCard) {
+        GetWalletCardsResponse response =
+                new GetWalletCardsResponse(
+                        hasCard
+                                ? Collections.singletonList(createInvalidWalletCard(mContext))
+                                : Collections.EMPTY_LIST, 0);
+
+        mTile.handleSetListening(true);
+
+        verify(mController).queryWalletCards(mCallbackCaptor.capture());
+
+        mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
+        mTestableLooper.processAllMessages();
+    }
+
+    private WalletCard createWalletCard(Context context) {
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
+        return new WalletCard.Builder(CARD_ID, CARD_IMAGE, CARD_DESCRIPTION, pendingIntent).build();
+    }
+
+    private WalletCard createInvalidWalletCard(Context context) {
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
+        return new WalletCard.Builder(
+                CARD_ID, INVALID_CARD_IMAGE, CARD_DESCRIPTION, pendingIntent).build();
+    }
+
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index 5f14233..76d935d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -16,8 +16,13 @@
 
 package com.android.systemui.qs.tiles;
 
-import static android.graphics.drawable.Icon.TYPE_URI;
 import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT;
+import static android.graphics.drawable.Icon.TYPE_URI;
+import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
+import static android.graphics.drawable.Icon.TYPE_RESOURCE;
+import static android.graphics.drawable.Icon.TYPE_BITMAP;
+import static android.graphics.drawable.Icon.TYPE_ADAPTIVE_BITMAP;
+import static android.graphics.drawable.Icon.TYPE_DATA;
 
 import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
 
@@ -247,11 +252,21 @@
                 return;
             }
             mSelectedCard = cards.get(selectedIndex);
-            android.graphics.drawable.Icon cardImageIcon = mSelectedCard.getCardImage();
-            if (cardImageIcon.getType() == TYPE_URI) {
-                mCardViewDrawable = null;
-            } else {
-                mCardViewDrawable = mSelectedCard.getCardImage().loadDrawable(mContext);
+            switch (mSelectedCard.getCardImage().getType()) {
+                case TYPE_BITMAP:
+                case TYPE_ADAPTIVE_BITMAP:
+                    mCardViewDrawable = mSelectedCard.getCardImage().loadDrawable(mContext);
+                    break;
+                case TYPE_URI:
+                case TYPE_URI_ADAPTIVE_BITMAP:
+                case TYPE_RESOURCE:
+                case TYPE_DATA:
+                    mCardViewDrawable = null;
+                    break;
+                default:
+                    Log.e(TAG, "Unknown icon type: " + mSelectedCard.getCardImage().getType());
+                    mCardViewDrawable = null;
+                    break;
             }
             refreshState();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
index a921feb..21e0475 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
@@ -320,13 +320,19 @@
         QAWalletCardViewInfo(Context context, WalletCard walletCard) {
             mWalletCard = walletCard;
             Icon cardImageIcon = mWalletCard.getCardImage();
-            if (cardImageIcon.getType() == Icon.TYPE_URI) {
-                mCardDrawable = null;
-            } else {
+            if (cardImageIcon.getType() == Icon.TYPE_BITMAP
+                    || cardImageIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
                 mCardDrawable = mWalletCard.getCardImage().loadDrawable(context);
+            } else {
+                mCardDrawable = null;
             }
             Icon icon = mWalletCard.getCardIcon();
-            mIconDrawable = icon == null ? null : icon.loadDrawable(context);
+            if (icon != null && (icon.getType() == Icon.TYPE_BITMAP
+                    || icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP)) {
+                mIconDrawable = icon.loadDrawable(context);
+            } else {
+                mIconDrawable = null;
+            }
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
index 420f84a..f98f79e 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
@@ -279,6 +279,11 @@
         return mCardLabel;
     }
 
+    @VisibleForTesting
+    ImageView getIcon() {
+        return mIcon;
+    }
+
     @Nullable
     private static Drawable getHeaderIcon(Context context, WalletCardViewInfo walletCard) {
         Drawable icon = walletCard.getIcon();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
index e3b07b3..4f5b063 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
@@ -310,6 +310,31 @@
     }
 
     @Test
+    public void queryCards_hasCards_showCarousel_invalidIconSource_noIcon() {
+        GetWalletCardsResponse response =
+                new GetWalletCardsResponse(
+                        Collections.singletonList(createWalletCardWithInvalidIcon(mContext)), 0);
+
+        mController.queryWalletCards();
+        mTestableLooper.processAllMessages();
+
+        verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
+
+        QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
+                mCallbackCaptor.getValue();
+
+        assertEquals(mController, callback);
+
+        callback.onWalletCardsRetrieved(response);
+        mTestableLooper.processAllMessages();
+
+        assertEquals(VISIBLE, mWalletView.getCardCarousel().getVisibility());
+        assertEquals(GONE, mWalletView.getEmptyStateView().getVisibility());
+        assertEquals(GONE, mWalletView.getErrorView().getVisibility());
+        assertEquals(null, mWalletView.getIcon().getDrawable());
+    }
+
+    @Test
     public void queryCards_noCards_showEmptyState() {
         GetWalletCardsResponse response = new GetWalletCardsResponse(Collections.EMPTY_LIST, 0);
 
@@ -454,6 +479,25 @@
                 .build();
     }
 
+    private WalletCard createWalletCardWithType(Context context, int cardType) {
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
+        return new WalletCard.Builder(CARD_ID_1, cardType, createIcon(), "•••• 1234", pendingIntent)
+                .setCardIcon(createIcon())
+                .setCardLabel("Hold to reader")
+                .build();
+    }
+
+    private WalletCard createWalletCardWithInvalidIcon(Context context) {
+        PendingIntent pendingIntent =
+                PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
+        return new WalletCard.Builder(
+                CARD_ID_1, createIconWithInvalidSource(), "•••• 1234", pendingIntent)
+                .setCardIcon(createIconWithInvalidSource())
+                .setCardLabel("Hold to reader")
+                .build();
+    }
+
     private WalletCard createCrazyWalletCard(Context context, boolean hasLabel) {
         PendingIntent pendingIntent =
                 PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
@@ -467,6 +511,10 @@
         return Icon.createWithBitmap(Bitmap.createBitmap(70, 44, Bitmap.Config.ARGB_8888));
     }
 
+    private static Icon createIconWithInvalidSource() {
+        return Icon.createWithContentUri("content://media/external/images/media");
+    }
+
     private WalletCardViewInfo createCardViewInfo(WalletCard walletCard) {
         return new WalletScreenController.QAWalletCardViewInfo(
                 mContext, walletCard);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 5f434ee..5b83a02 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3070,6 +3070,12 @@
                                         "the type and name should not be empty");
                                 return;
                             }
+                            if (!type.equals(mAccountType)) {
+                                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                                        "incorrect account type");
+                                return;
+                            }
+
                             Account resultAccount = new Account(name, type);
                             if (!customTokens) {
                                 saveAuthTokenToDatabase(
diff --git a/telecomm/java/android/telecom/StatusHints.java b/telecomm/java/android/telecom/StatusHints.java
index b734633..907a4b2 100644
--- a/telecomm/java/android/telecom/StatusHints.java
+++ b/telecomm/java/android/telecom/StatusHints.java
@@ -27,6 +27,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -40,6 +41,7 @@
     private final CharSequence mLabel;
     private Icon mIcon;
     private final Bundle mExtras;
+    private static final String TAG = StatusHints.class.getSimpleName();
 
     /**
      * @hide
@@ -150,17 +152,37 @@
         // incompatible types.
         if (icon != null && (icon.getType() == Icon.TYPE_URI
                 || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
-            String encodedUser = icon.getUri().getEncodedUserInfo();
-            // If there is no encoded user, the URI is calling into the calling user space
-            if (encodedUser != null) {
-                int userId = Integer.parseInt(encodedUser);
-                // Do not try to save the icon if the user id isn't in the calling user space.
-                if (userId != callingUserHandle.getIdentifier()) return null;
+            int callingUserId = callingUserHandle.getIdentifier();
+            int requestingUserId = getUserIdFromAuthority(
+                    icon.getUri().getAuthority(), callingUserId);
+            if (callingUserId != requestingUserId) {
+                return null;
             }
+
         }
         return icon;
     }
 
+    /**
+     * Derives the user id from the authority or the default user id if none could be found.
+     * @param auth
+     * @param defaultUserId
+     * @return The user id from the given authority.
+     * @hide
+     */
+    public static int getUserIdFromAuthority(String auth, int defaultUserId) {
+        if (auth == null) return defaultUserId;
+        int end = auth.lastIndexOf('@');
+        if (end == -1) return defaultUserId;
+        String userIdString = auth.substring(0, end);
+        try {
+            return Integer.parseInt(userIdString);
+        } catch (NumberFormatException e) {
+            Log.w(TAG, "Error parsing userId." + e);
+            return UserHandle.USER_NULL;
+        }
+    }
+
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeCharSequence(mLabel);