diff options
| author | Julian Veit <claymore1298@gmail.com> | 2025-06-11 19:06:51 +0200 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@box1> | 2025-06-11 19:06:51 +0200 |
| commit | e1424cddcc730de4555027b1eaf6a37fb93187c4 (patch) | |
| tree | 5b7d96dfb6ed8303730943e956037cf2da706cde | |
| parent | 6ac7aa3f485243879ad4326c9cc8bb3ff07cc990 (diff) | |
| parent | 95704d5a2d4a3ee11cdca23151ef5f1fe3b0155f (diff) | |
Merge changes from topic "S_asb_2025-03" into s12.1s12.1
* changes:
RESTRICT AUTOMERGE [PM] Fix the profile issue in UninstallerActivity
Check account type returned by AbstractAccountAuthenticator.
Resolve cross account user icon validation.
For the wallet card & icon, only allow the drawable be loaded from bitmap.
8 files changed, 658 insertions, 24 deletions
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java index 0198168f9fda..f487bfbd28c7 100755..100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java @@ -51,6 +51,7 @@ import android.net.Uri; 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.ErrorFragment; 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 @@ public class UninstallerActivity extends Activity { 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 000000000000..03c1f92aad4c --- /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 e8c6bb0abd68..46543200c90d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java @@ -247,15 +247,15 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> { } mSelectedCard = cards.get(selectedIndex); 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: - mCardViewDrawable = null; - break; case TYPE_RESOURCE: - case TYPE_BITMAP: - case TYPE_ADAPTIVE_BITMAP: case TYPE_DATA: - mCardViewDrawable = mSelectedCard.getCardImage().loadDrawable(mContext); + mCardViewDrawable = null; break; default: Log.e(TAG, "Unknown icon type: " + mSelectedCard.getCardImage().getType()); 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 2aafc14be551..96d90f192854 100644 --- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java +++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java @@ -319,13 +319,19 @@ public class WalletScreenController implements 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 9b2702ff7bf2..ca03625a4032 100644 --- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java +++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java @@ -275,6 +275,11 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard 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 01769e52c8d3..325d6a959abe 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 @@ -309,6 +309,31 @@ public class WalletScreenControllerTest extends SysuiTestCase { } @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); @@ -455,6 +480,25 @@ public class WalletScreenControllerTest extends SysuiTestCase { .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); @@ -468,6 +512,10 @@ public class WalletScreenControllerTest extends SysuiTestCase { 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 08aa3c7bd2fe..d971e08168e7 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -3071,6 +3071,12 @@ public class AccountManagerService "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 b7346331dc60..907a4b2a7000 100644 --- a/telecomm/java/android/telecom/StatusHints.java +++ b/telecomm/java/android/telecom/StatusHints.java @@ -27,6 +27,7 @@ import android.os.Bundle; 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 @@ public final class StatusHints implements Parcelable { private final CharSequence mLabel; private Icon mIcon; private final Bundle mExtras; + private static final String TAG = StatusHints.class.getSimpleName(); /** * @hide @@ -150,17 +152,37 @@ public final class StatusHints implements Parcelable { // 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); |
