From 58affb521c4818f20e8c340488f6a3b9c59e4784 Mon Sep 17 00:00:00 2001 From: Alex Johnston Date: Wed, 5 Jan 2022 22:19:29 +0000 Subject: [PATCH 01/35] Add caller check to com.android.credentials.RESET * Only the Settings app can reset credentials via com.android.credentials.RESET. * com.android.credentials.INSTALL should still be callable by CertInstaller. Manual testing steps: * Install certificate via Settings * Verify unable to reset certificates via test app provided in the bug (app-debug.apk) * Verify able to reset certificates via Settings * Verify com.android.credentials.INSTALL isn't changed Bug: 200164168 Test: manual Change-Id: I9dfde586616d004befbee529f2ae842d22795065 (cherry picked from commit 4c1272a921bb9037e17a01e1e5a0692f7f704c3d) Merged-In: I9dfde586616d004befbee529f2ae842d22795065 (cherry picked from commit f8a1a563c7c598db6fe5f902e35d968ea7dc0003) Merged-In:I9dfde586616d004befbee529f2ae842d22795065 --- .../settings/security/CredentialStorage.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/security/CredentialStorage.java b/src/com/android/settings/security/CredentialStorage.java index e0daaaa8fd9..ef6edb2b930 100644 --- a/src/com/android/settings/security/CredentialStorage.java +++ b/src/com/android/settings/security/CredentialStorage.java @@ -87,7 +87,7 @@ protected void onResume() { final String action = intent.getAction(); final UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); if (!userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS)) { - if (ACTION_RESET.equals(action)) { + if (ACTION_RESET.equals(action) && checkCallerIsSelf()) { new ResetDialog(); } else { if (ACTION_INSTALL.equals(action) && checkCallerIsCertInstallerOrSelfInProfile()) { @@ -319,6 +319,19 @@ private void onKeyInstalled(String alias, int uid, boolean result) { finish(); } + /** + * Check that the caller is Settings. + */ + private boolean checkCallerIsSelf() { + try { + return Process.myUid() == android.app.ActivityManager.getService() + .getLaunchedFromUid(getActivityToken()); + } catch (RemoteException re) { + // Error talking to ActivityManager, just give up + return false; + } + } + /** * Check that the caller is either certinstaller or Settings running in a profile of this user. */ From 4f47540f2017d1a744d76db7dcb61b2c5f7c6efb Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 14 Jan 2022 23:13:54 +0800 Subject: [PATCH 02/35] Do not let guest user disable secure nfc Bug: 209446496 Test: manual Merged-In: I7253f7f08fde04e30400a30d9a0d24f1ceff04b0 Change-Id: I7253f7f08fde04e30400a30d9a0d24f1ceff04b0 (cherry picked from commit d9e3e6e4b1c3cb1a04dba0f530505843ef44a748) (cherry picked from commit a579ca7554dcbfd3fce1c90451fb54cb676cfdda) Merged-In:I7253f7f08fde04e30400a30d9a0d24f1ceff04b0 --- .../NfcAndPaymentFragment.java | 19 ++++++++++++++++++- .../settings/nfc/SecureNfcEnabler.java | 14 +++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/connecteddevice/NfcAndPaymentFragment.java b/src/com/android/settings/connecteddevice/NfcAndPaymentFragment.java index 4ebc0cdcccd..feb757f9e41 100644 --- a/src/com/android/settings/connecteddevice/NfcAndPaymentFragment.java +++ b/src/com/android/settings/connecteddevice/NfcAndPaymentFragment.java @@ -17,6 +17,12 @@ package com.android.settings.connecteddevice; import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.os.UserHandle; +import android.os.UserManager; + import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; @@ -54,5 +60,16 @@ public int getHelpResource() { * For Search. */ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.nfc_and_payment_settings); + new BaseSearchIndexProvider(R.xml.nfc_and_payment_settings) { + @Override + protected boolean isPageSearchEnabled(Context context) { + final UserManager userManager = context.getSystemService(UserManager.class); + final UserInfo myUserInfo = userManager.getUserInfo(UserHandle.myUserId()); + if (myUserInfo.isGuest()) { + return false; + } + final PackageManager pm = context.getPackageManager(); + return pm.hasSystemFeature(PackageManager.FEATURE_NFC); + } + }; } diff --git a/src/com/android/settings/nfc/SecureNfcEnabler.java b/src/com/android/settings/nfc/SecureNfcEnabler.java index 9acaf6461f2..f31a382a571 100644 --- a/src/com/android/settings/nfc/SecureNfcEnabler.java +++ b/src/com/android/settings/nfc/SecureNfcEnabler.java @@ -18,9 +18,8 @@ import android.content.Context; import android.nfc.NfcAdapter; -import android.provider.Settings; +import android.os.UserManager; -import androidx.annotation.VisibleForTesting; import androidx.preference.SwitchPreference; import com.android.settings.R; @@ -32,10 +31,12 @@ */ public class SecureNfcEnabler extends BaseNfcEnabler { private final SwitchPreference mPreference; + private final UserManager mUserManager; public SecureNfcEnabler(Context context, SwitchPreference preference) { super(context); mPreference = preference; + mUserManager = context.getSystemService(UserManager.class); } @Override @@ -48,7 +49,7 @@ protected void handleNfcStateChanged(int newState) { case NfcAdapter.STATE_ON: mPreference.setSummary(R.string.nfc_secure_toggle_summary); mPreference.setChecked(mPreference.isChecked()); - mPreference.setEnabled(true); + mPreference.setEnabled(isToggleable()); break; case NfcAdapter.STATE_TURNING_ON: mPreference.setEnabled(false); @@ -58,4 +59,11 @@ protected void handleNfcStateChanged(int newState) { break; } } + + private boolean isToggleable() { + if (mUserManager.isGuestUser()) { + return false; + } + return true; + } } From 634ff0177a85ca5c44a65d68bb8fef59819599b5 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Wed, 9 Mar 2022 10:52:43 +0800 Subject: [PATCH 03/35] Hide private DNS settings UI in Guest mode Hide private DNS settings UI in Guest mode to prevent guest users modifying global private DNS settings. Bug: 206987762 Test: 1. make RunSettingsRoboTests \ ROBOTEST_FILTER=PrivateDnsPreferenceControllerTest 2. Switch to Guest user and check if the private DNS UI is hidden or not. Change-Id: Iebfb8684da3be32110decd9e8447dd07b1c40387 (cherry picked from commit 52e863b5a212889d4f8cb89a4028c42af59c9327) Merged-In: Iebfb8684da3be32110decd9e8447dd07b1c40387 --- .../network/PrivateDnsPreferenceController.java | 9 ++++++--- .../network/PrivateDnsPreferenceControllerTest.java | 11 +++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/network/PrivateDnsPreferenceController.java b/src/com/android/settings/network/PrivateDnsPreferenceController.java index 84cae88f856..22633e0081a 100644 --- a/src/com/android/settings/network/PrivateDnsPreferenceController.java +++ b/src/com/android/settings/network/PrivateDnsPreferenceController.java @@ -84,9 +84,12 @@ public String getPreferenceKey() { @Override public int getAvailabilityStatus() { - return mContext.getResources().getBoolean(R.bool.config_show_private_dns_settings) - ? AVAILABLE - : UNSUPPORTED_ON_DEVICE; + if (!mContext.getResources().getBoolean(R.bool.config_show_private_dns_settings)) { + return UNSUPPORTED_ON_DEVICE; + } + final UserManager userManager = mContext.getSystemService(UserManager.class); + if (userManager.isGuestUser()) return DISABLED_FOR_USER; + return AVAILABLE; } @Override diff --git a/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java index efb77eba402..1eeffded9d9 100644 --- a/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/PrivateDnsPreferenceControllerTest.java @@ -27,6 +27,7 @@ import static androidx.lifecycle.Lifecycle.Event.ON_STOP; import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_FOR_USER; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.google.common.truth.Truth.assertThat; @@ -36,6 +37,7 @@ import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; @@ -109,6 +111,8 @@ public class PrivateDnsPreferenceControllerTest { private Network mNetwork; @Mock private Preference mPreference; + @Mock + private UserManager mUserManager; @Captor private ArgumentCaptor mCallbackCaptor; private PrivateDnsPreferenceController mController; @@ -127,6 +131,7 @@ public void setUp() { mShadowContentResolver = Shadow.extract(mContentResolver); when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) .thenReturn(mConnectivityManager); + when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); doNothing().when(mConnectivityManager).registerDefaultNetworkCallback( mCallbackCaptor.capture(), nullable(Handler.class)); @@ -173,6 +178,12 @@ public void getAvailabilityStatus_unsupportedWhenSet() { assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } + @Test + public void getAvailabilityStatus_disabledForGuestUser() { + doReturn(true).when(mUserManager).isGuestUser(); + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_FOR_USER); + } + @Test public void goThroughLifecycle_shouldRegisterUnregisterSettingsObserver() { mLifecycle.handleLifecycleEvent(ON_START); From 4491d437b6bed9e7ebfcd9181aa6891a842aea76 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Fri, 25 Feb 2022 15:22:27 +0000 Subject: [PATCH 04/35] Prevent exfiltration of system files via user image settings. This is a backport of ag/17005706. This adds mitigations to prevent system files being exfiltrated via the settings content provider when a content URI is provided as a chosen user image. The mitigations are: 1) Copy the image to a new URI rather than the existing takePictureUri prior to cropping. 2) Only allow a system handler to respond to the CROP intent. Bug: 187702830 Test: build and check functionality Change-Id: Ia6314b6810afb5efa0329f3eeaee9ccfff791966 Merged-In: I15e15ad88b768a5b679de32c5429d921d850a3cb (cherry picked from commit 8950a9002402de6e1218bab3da52868a51104a95) (cherry picked from commit 3c63dd20ebdbead1ea92d16ee94a9397238895d5) Merged-In: Ia6314b6810afb5efa0329f3eeaee9ccfff791966 --- .../users/EditUserPhotoController.java | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/com/android/settings/users/EditUserPhotoController.java b/src/com/android/settings/users/EditUserPhotoController.java index 60f720eacf7..bd698c2b34b 100644 --- a/src/com/android/settings/users/EditUserPhotoController.java +++ b/src/com/android/settings/users/EditUserPhotoController.java @@ -21,6 +21,8 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; @@ -77,6 +79,7 @@ public class EditUserPhotoController { private static final int REQUEST_CODE_TAKE_PHOTO = 1002; private static final int REQUEST_CODE_CROP_PHOTO = 1003; + private static final String PRE_CROP_PICTURE_FILE_NAME = "PreCropEditUserPhoto.jpg"; private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg"; private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg"; private static final String NEW_USER_PHOTO_FILE_NAME = "NewUserPhoto.png"; @@ -87,6 +90,7 @@ public class EditUserPhotoController { private final Fragment mFragment; private final ImageView mImageView; + private final Uri mPreCropPictureUri; private final Uri mCropPictureUri; private final Uri mTakePictureUri; @@ -98,6 +102,8 @@ public EditUserPhotoController(Fragment fragment, ImageView view, mContext = view.getContext(); mFragment = fragment; mImageView = view; + + mPreCropPictureUri = createTempImageUri(mContext, PRE_CROP_PICTURE_FILE_NAME, !waiting); mCropPictureUri = createTempImageUri(mContext, CROP_PICTURE_FILE_NAME, !waiting); mTakePictureUri = createTempImageUri(mContext, TAKE_PICTURE_FILE_NAME, !waiting); mPhotoSize = getPhotoSize(mContext); @@ -132,7 +138,7 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { case REQUEST_CODE_TAKE_PHOTO: case REQUEST_CODE_CHOOSE_PHOTO: if (mTakePictureUri.equals(pictureUri)) { - cropPhoto(); + cropPhoto(pictureUri); } else { copyAndCropPhoto(pictureUri); } @@ -228,7 +234,7 @@ private void copyAndCropPhoto(final Uri pictureUri) { protected Void doInBackground(Void... params) { final ContentResolver cr = mContext.getContentResolver(); try (InputStream in = cr.openInputStream(pictureUri); - OutputStream out = cr.openOutputStream(mTakePictureUri)) { + OutputStream out = cr.openOutputStream(mPreCropPictureUri)) { Streams.copy(in, out); } catch (IOException e) { Log.w(TAG, "Failed to copy photo", e); @@ -239,27 +245,38 @@ protected Void doInBackground(Void... params) { @Override protected void onPostExecute(Void result) { if (!mFragment.isAdded()) return; - cropPhoto(); + cropPhoto(mPreCropPictureUri); } }.execute(); } - private void cropPhoto() { + private void cropPhoto(final Uri pictureUri) { // TODO: Use a public intent, when there is one. Intent intent = new Intent("com.android.camera.action.CROP"); - intent.setDataAndType(mTakePictureUri, "image/*"); + intent.setDataAndType(pictureUri, "image/*"); appendOutputExtra(intent, mCropPictureUri); appendCropExtras(intent); - if (intent.resolveActivity(mContext.getPackageManager()) != null) { - try { - StrictMode.disableDeathOnFileUriExposure(); - mFragment.startActivityForResult(intent, REQUEST_CODE_CROP_PHOTO); - } finally { - StrictMode.enableDeathOnFileUriExposure(); + try { + StrictMode.disableDeathOnFileUriExposure(); + if (startSystemActivityForResult(intent, REQUEST_CODE_CROP_PHOTO)) { + return; } - } else { - onPhotoCropped(mTakePictureUri, false); + } finally { + StrictMode.enableDeathOnFileUriExposure(); + } + onPhotoCropped(mTakePictureUri, false); + } + + private boolean startSystemActivityForResult(Intent intent, int code) { + ActivityInfo info = intent.resolveActivityInfo(mContext.getPackageManager(), + PackageManager.MATCH_SYSTEM_ONLY); + if (info == null) { + Log.w(TAG, "No system package activity could be found for code " + code); + return false; } + intent.setPackage(info.packageName); + mFragment.startActivityForResult(intent, code); + return true; } private void appendOutputExtra(Intent intent, Uri pictureUri) { From b8937a76b3a873dcf1586510d17e56ba59272a63 Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Fri, 6 May 2022 17:42:30 +0800 Subject: [PATCH 05/35] [DO NOT MERGE] Verify ringtone from ringtone picker is audio To improve privacy. Bug: 221041256 Test: atest com.android.settings.DefaultRingtonePreferenceTest Change-Id: I0a9ca163f5ae91b67c9f957fde4c6db326b8718d Merged-In: I0a9ca163f5ae91b67c9f957fde4c6db326b8718d (cherry picked from commit e4c22580c9a66a3d5523782c2daa707531210227) (cherry picked from commit 1682354551b8ee3c35a9ee1c1d9dc8238f5d6117) Merged-In: I0a9ca163f5ae91b67c9f957fde4c6db326b8718d --- .../settings/DefaultRingtonePreference.java | 21 +++++ tests/unit/Android.bp | 1 + .../DefaultRingtonePreferenceTest.java | 81 +++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java diff --git a/src/com/android/settings/DefaultRingtonePreference.java b/src/com/android/settings/DefaultRingtonePreference.java index 9f9f832b100..914c4b214d1 100644 --- a/src/com/android/settings/DefaultRingtonePreference.java +++ b/src/com/android/settings/DefaultRingtonePreference.java @@ -22,6 +22,9 @@ import android.media.RingtoneManager; import android.net.Uri; import android.util.AttributeSet; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; public class DefaultRingtonePreference extends RingtonePreference { private static final String TAG = "DefaultRingtonePreference"; @@ -43,6 +46,24 @@ public void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) { @Override protected void onSaveRingtone(Uri ringtoneUri) { + String mimeType = getContext().getContentResolver().getType(ringtoneUri); + if (mimeType == null) { + Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri + + " ignored: failure to find mimeType (no access from this context?)"); + return; + } + + if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) { + Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri + + " ignored: associated mimeType:" + mimeType + " is not an audio type"); + return; + } + + setActualDefaultRingtoneUri(ringtoneUri); + } + + @VisibleForTesting + void setActualDefaultRingtoneUri(Uri ringtoneUri) { RingtoneManager.setActualDefaultRingtoneUri(mUserContext, getRingtoneType(), ringtoneUri); } diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp index 583b46e4b31..7556cbe35ea 100644 --- a/tests/unit/Android.bp +++ b/tests/unit/Android.bp @@ -17,6 +17,7 @@ android_test { "androidx.test.espresso.core", "androidx.test.espresso.contrib-nodeps", "androidx.test.espresso.intents-nodeps", + "androidx.test.ext.junit", "mockito-target-minus-junit4", "platform-test-annotations", "truth-prebuilt", diff --git a/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java b/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java new file mode 100644 index 00000000000..b9dea0167b5 --- /dev/null +++ b/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2022 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.settings; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.media.RingtoneManager; +import android.net.Uri; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** Unittest for DefaultRingtonePreference. */ +@RunWith(AndroidJUnit4.class) +public class DefaultRingtonePreferenceTest { + + private DefaultRingtonePreference mDefaultRingtonePreference; + + @Mock + private ContentResolver mContentResolver; + @Mock + private Uri mRingtoneUri; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + Context context = spy(ApplicationProvider.getApplicationContext()); + doReturn(mContentResolver).when(context).getContentResolver(); + + mDefaultRingtonePreference = spy(new DefaultRingtonePreference(context, null /* attrs */)); + doReturn(context).when(mDefaultRingtonePreference).getContext(); + when(mDefaultRingtonePreference.getRingtoneType()) + .thenReturn(RingtoneManager.TYPE_RINGTONE); + mDefaultRingtonePreference.setUserId(1); + } + + @Test + public void onSaveRingtone_nullMimeType_shouldNotSetRingtone() { + when(mContentResolver.getType(mRingtoneUri)).thenReturn(null); + + mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri); + + verify(mDefaultRingtonePreference, never()).setActualDefaultRingtoneUri(mRingtoneUri); + } + + @Test + public void onSaveRingtone_notAudioMimeType_shouldNotSetRingtone() { + when(mContentResolver.getType(mRingtoneUri)).thenReturn("text/plain"); + + mDefaultRingtonePreference.onSaveRingtone(mRingtoneUri); + + verify(mDefaultRingtonePreference, never()).setActualDefaultRingtoneUri(mRingtoneUri); + } +} From cef248f69f41c25205e1cb9254f29187fb6a8d5e Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 4 May 2022 18:01:15 +0800 Subject: [PATCH 06/35] Do not let guest user disable secuer nfc via SettingsSlice Do not let guest user switch the secure nfc preferernce setting. Bug: 228314987 Test: manual Change-Id: I60a832e32d83bb57d968af2f8b92d94e2ac7c6a2 (cherry picked from commit 2290b0af8cb4b640709fa904f73ce3e69208f872) Merged-In: I60a832e32d83bb57d968af2f8b92d94e2ac7c6a2 --- .../nfc/SecureNfcPreferenceController.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/nfc/SecureNfcPreferenceController.java b/src/com/android/settings/nfc/SecureNfcPreferenceController.java index 4e548d141b7..575bab1ca7e 100644 --- a/src/com/android/settings/nfc/SecureNfcPreferenceController.java +++ b/src/com/android/settings/nfc/SecureNfcPreferenceController.java @@ -17,6 +17,7 @@ import android.content.Context; import android.nfc.NfcAdapter; +import android.os.UserManager; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; @@ -31,10 +32,12 @@ public class SecureNfcPreferenceController extends TogglePreferenceController private final NfcAdapter mNfcAdapter; private SecureNfcEnabler mSecureNfcEnabler; + private final UserManager mUserManager; public SecureNfcPreferenceController(Context context, String key) { super(context, key); mNfcAdapter = NfcAdapter.getDefaultAdapter(context); + mUserManager = context.getSystemService(UserManager.class); } @Override @@ -57,7 +60,11 @@ public boolean isChecked() { @Override public boolean setChecked(boolean isChecked) { - return mNfcAdapter.enableSecureNfc(isChecked); + if (isToggleable()) { + return mNfcAdapter.enableSecureNfc(isChecked); + } else { + return false; + } } @Override @@ -94,4 +101,12 @@ public void onPause() { mSecureNfcEnabler.pause(); } } + + private boolean isToggleable() { + if (mUserManager.isGuestUser()) { + return false; + } + return true; + } + } From 2ca801a33b17ef7eb5e353ebdf9c482c0c66413e Mon Sep 17 00:00:00 2001 From: Lin Yuan Date: Wed, 1 Jun 2022 07:17:47 -0400 Subject: [PATCH 07/35] RESTRICT AUTOMERGE Fix: policy enforcement for location wifi scanning Make DISALLOW_CONFIG_LOCATION effectively disallow wifi scanning and bluetooth scanning settings for location services. screenshots: https://screenshot.googleplex.com/AqvEW2kTrQT2Ufp Bug: 228315522 Bug: 228315529 Test: manually on sunfish flashed with rvc. Change-Id: I6ef64a34764e52de7b461e87ea0af40a6d050587 (cherry picked from commit 78799a550a6ea1bb9596b6b3ab6402ec8a038d6b) Merged-In: I6ef64a34764e52de7b461e87ea0af40a6d050587 --- res/xml/location_scanning.xml | 4 ++-- .../BluetoothScanningPreferenceController.java | 11 +++++++++++ .../location/WifiScanningPreferenceController.java | 11 +++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/res/xml/location_scanning.xml b/res/xml/location_scanning.xml index f82500bf8e9..99aed9a73b4 100644 --- a/res/xml/location_scanning.xml +++ b/res/xml/location_scanning.xml @@ -17,13 +17,13 @@ - - Date: Mon, 16 May 2022 14:36:19 +0800 Subject: [PATCH 08/35] [DO NOT MERGE] Fix Settings crash when setting a null ringtone Ringtone picker may callback a null ringtone Uri if users select None. This change pass null ringtone Uri to RingtoneManager and return. Bug: 232502532 Bug: 221041256 Test: maunal Settings - Sound & Vibration -> Phone ringtone -> My Sounds -> None Change-Id: I044b680871472a3c272f6264c4ef272df542112e Merged-In: I044b680871472a3c272f6264c4ef272df542112e (cherry picked from commit 973a46134b439b6dce2626bb0ba8ac34af7db29c) Merged-In: I044b680871472a3c272f6264c4ef272df542112e --- src/com/android/settings/DefaultRingtonePreference.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/com/android/settings/DefaultRingtonePreference.java b/src/com/android/settings/DefaultRingtonePreference.java index 914c4b214d1..824a5a05dc1 100644 --- a/src/com/android/settings/DefaultRingtonePreference.java +++ b/src/com/android/settings/DefaultRingtonePreference.java @@ -46,6 +46,11 @@ public void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) { @Override protected void onSaveRingtone(Uri ringtoneUri) { + if (ringtoneUri == null) { + setActualDefaultRingtoneUri(ringtoneUri); + return; + } + String mimeType = getContext().getContentResolver().getType(ringtoneUri); if (mimeType == null) { Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri From 77059064da4b3944172d796f9562cd417d9d67ec Mon Sep 17 00:00:00 2001 From: Tsung-Mao Fang Date: Fri, 27 May 2022 15:52:30 +0800 Subject: [PATCH 09/35] [DO NOT MERGE] Fix can't change notification sound for work profile. Use correct user id context to query the type, so we won't get empty result unexpectedly. If we get the null result, then we won't set sound sucessfully. Bug: 233580016 Bug: 221041256 Test: Manual test and set work profile sound works. Change-Id: I7f8fb737a7c6f77a380f3f075a5c89a1970e39ad Merged-In: I7f8fb737a7c6f77a380f3f075a5c89a1970e39ad (cherry picked from commit 32145cc362f9b111a7239539466eb5c788445a11) Merged-In: I7f8fb737a7c6f77a380f3f075a5c89a1970e39ad --- src/com/android/settings/DefaultRingtonePreference.java | 2 +- .../src/com/android/settings/DefaultRingtonePreferenceTest.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/DefaultRingtonePreference.java b/src/com/android/settings/DefaultRingtonePreference.java index 824a5a05dc1..9bf626c9898 100644 --- a/src/com/android/settings/DefaultRingtonePreference.java +++ b/src/com/android/settings/DefaultRingtonePreference.java @@ -51,7 +51,7 @@ protected void onSaveRingtone(Uri ringtoneUri) { return; } - String mimeType = getContext().getContentResolver().getType(ringtoneUri); + String mimeType = mUserContext.getContentResolver().getType(ringtoneUri); if (mimeType == null) { Log.e(TAG, "onSaveRingtone for URI:" + ringtoneUri + " ignored: failure to find mimeType (no access from this context?)"); diff --git a/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java b/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java index b9dea0167b5..7877684dce6 100644 --- a/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java +++ b/tests/unit/src/com/android/settings/DefaultRingtonePreferenceTest.java @@ -59,6 +59,7 @@ public void setUp() { when(mDefaultRingtonePreference.getRingtoneType()) .thenReturn(RingtoneManager.TYPE_RINGTONE); mDefaultRingtonePreference.setUserId(1); + mDefaultRingtonePreference.mUserContext = context; } @Test From c1a16ca63a6548eb09cd151cc1bd3f2fb3300499 Mon Sep 17 00:00:00 2001 From: Raphael Kim Date: Fri, 22 Apr 2022 00:40:06 +0000 Subject: [PATCH 10/35] Extract app label from component name in notification access confirmation UI Bug: 228178437 Test: Manually tested on POC Change-Id: I8613d9b87a53d4641c0689bca9c961c66a2e9415 Merged-In: I8613d9b87a53d4641c0689bca9c961c66a2e9415 (cherry picked from commit 8d749c55f4efd6b2e514d90204667ffa804eb0f9) Merged-In: I8613d9b87a53d4641c0689bca9c961c66a2e9415 --- ...otificationAccessConfirmationActivity.java | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java index a7d9f6889cd..dfe6df2a5ca 100644 --- a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java +++ b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java @@ -20,7 +20,6 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_COMPONENT_NAME; -import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_PACKAGE_TITLE; import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_USER_ID; import android.Manifest; @@ -30,10 +29,13 @@ import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.UserHandle; +import android.text.TextUtils; import android.util.Slog; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; @@ -63,15 +65,38 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { mComponentName = getIntent().getParcelableExtra(EXTRA_COMPONENT_NAME); mUserId = getIntent().getIntExtra(EXTRA_USER_ID, UserHandle.USER_NULL); - String pkgTitle = getIntent().getStringExtra(EXTRA_PACKAGE_TITLE); + CharSequence mAppLabel; + + if (mComponentName == null || mComponentName.getPackageName() == null) { + finish(); + return; + } + + try { + ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo( + mComponentName.getPackageName(), 0); + mAppLabel = applicationInfo.loadSafeLabel(getPackageManager(), + PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, + PackageItemInfo.SAFE_LABEL_FLAG_TRIM + | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); + } catch (PackageManager.NameNotFoundException e) { + Slog.e(LOG_TAG, "Couldn't find app with package name for " + mComponentName, e); + finish(); + return; + } + + if (TextUtils.isEmpty(mAppLabel)) { + finish(); + return; + } AlertController.AlertParams p = new AlertController.AlertParams(this); p.mTitle = getString( R.string.notification_listener_security_warning_title, - pkgTitle); + mAppLabel); p.mMessage = getString( R.string.notification_listener_security_warning_summary, - pkgTitle); + mAppLabel); p.mPositiveButtonText = getString(R.string.allow); p.mPositiveButtonListener = (a, b) -> onAllow(); p.mNegativeButtonText = getString(R.string.deny); From 5b6f85e174c97fd8d3ab25473ac49bf139d760e5 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 16 Jun 2021 14:00:39 -0400 Subject: [PATCH 11/35] Validate config activities with their rule owners Test: RoboTests Bug: 189332346 Bug: 235823407 Change-Id: Iee1b1caca4d6eb2729feb872c3e4954b6c16519c Merged-In: Iee1b1caca4d6eb2729feb872c3e4954b6c16519c (cherry picked from commit b161a3b8502376ed12c308fce33f9592919a579e) Merged-In: Iee1b1caca4d6eb2729feb872c3e4954b6c16519c --- ...ModeAutomaticRulePreferenceController.java | 54 ++++-- .../notification/zen/ZenRulePreference.java | 2 +- ...AutomaticRulePreferenceControllerTest.java | 169 ++++++++++++++++++ 3 files changed, 207 insertions(+), 18 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceControllerTest.java diff --git a/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceController.java b/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceController.java index f6f183995ec..701abbb0b65 100644 --- a/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceController.java +++ b/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceController.java @@ -26,8 +26,11 @@ import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; +import android.os.Binder; import android.provider.Settings; import android.service.notification.ConditionProviderService; +import android.util.Log; +import android.util.Slog; import androidx.fragment.app.Fragment; import androidx.preference.Preference; @@ -36,6 +39,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.Map; +import java.util.Objects; abstract public class AbstractZenModeAutomaticRulePreferenceController extends AbstractZenModePreferenceController implements PreferenceControllerMixin { @@ -92,7 +96,7 @@ public static ZenRuleInfo getRuleInfo(PackageManager pm, ComponentInfo ci) { ? ci.metaData.getString(ConditionProviderService.META_DATA_RULE_TYPE) : ci.metaData.getString(NotificationManager.META_DATA_AUTOMATIC_RULE_TYPE); - final ComponentName configurationActivity = getSettingsActivity(null, ci); + final ComponentName configurationActivity = getSettingsActivity(pm, null, ci); if (ruleType != null && !ruleType.trim().isEmpty() && configurationActivity != null) { final ZenRuleInfo ri = new ZenRuleInfo(); ri.serviceComponent = @@ -110,28 +114,44 @@ public static ZenRuleInfo getRuleInfo(PackageManager pm, ComponentInfo ci) { return null; } - protected static ComponentName getSettingsActivity(AutomaticZenRule rule, ComponentInfo ci) { + protected static ComponentName getSettingsActivity(PackageManager pm, AutomaticZenRule rule, + ComponentInfo ci) { + String owner = rule != null ? rule.getPackageName() : ci.packageName; + ComponentName settingsActivity = null; // prefer config activity on the rule itself; fallback to manifest definition if (rule != null && rule.getConfigurationActivity() != null) { - return rule.getConfigurationActivity(); - } - if (ci == null) { - return null; + settingsActivity = rule.getConfigurationActivity(); + } else { + if (ci == null) { + settingsActivity = null; + } else if (ci instanceof ActivityInfo) { + // new activity backed rule + settingsActivity = new ComponentName(ci.packageName, ci.name); + } else if (ci.metaData != null) { + // old service backed rule + final String configurationActivity = ci.metaData.getString( + ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY); + if (configurationActivity != null) { + settingsActivity = ComponentName.unflattenFromString(configurationActivity); + } + } } - // new activity backed rule - if (ci instanceof ActivityInfo) { - return new ComponentName(ci.packageName, ci.name); + if (settingsActivity == null || owner == null) { + return settingsActivity; } - // old service backed rule - if (ci.metaData != null) { - final String configurationActivity = ci.metaData.getString( - ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY); - if (configurationActivity != null) { - return ComponentName.unflattenFromString(configurationActivity); + try { + int ownerUid = pm.getPackageUid(owner, 0); + int configActivityOwnerUid = pm.getPackageUid(settingsActivity.getPackageName(), 0); + if (ownerUid == configActivityOwnerUid) { + return settingsActivity; + } else { + Log.w(TAG, "Config activity not in owner package for " + rule.getName()); + return null; } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Failed to find config activity"); + return null; } - - return null; } public class RuleNameChangeListener implements ZenRuleNameDialog.PositiveClickListener { diff --git a/src/com/android/settings/notification/zen/ZenRulePreference.java b/src/com/android/settings/notification/zen/ZenRulePreference.java index 1f1283d90c9..24e3296415f 100644 --- a/src/com/android/settings/notification/zen/ZenRulePreference.java +++ b/src/com/android/settings/notification/zen/ZenRulePreference.java @@ -168,7 +168,7 @@ protected void setAttributes(AutomaticZenRule rule) { : isEvent ? ZenModeEventRuleSettings.ACTION : ""; ComponentInfo si = mServiceListing.findService(rule.getOwner()); ComponentName settingsActivity = AbstractZenModeAutomaticRulePreferenceController. - getSettingsActivity(rule, si); + getSettingsActivity(mPm, rule, si); mIntent = AbstractZenModeAutomaticRulePreferenceController.getRuleIntent(action, settingsActivity, mId); if (mIntent.resolveActivity(mPm) == null) { diff --git a/tests/robotests/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceControllerTest.java new file mode 100644 index 00000000000..ae6e1d0c9c6 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceControllerTest.java @@ -0,0 +1,169 @@ +/* + * 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.settings.notification.zen; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.app.AutomaticZenRule; +import android.app.NotificationManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ComponentInfo; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.service.notification.ConditionProviderService; +import android.service.notification.ZenPolicy; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class AbstractZenModeAutomaticRulePreferenceControllerTest { + + @Mock + private PackageManager mPm; + private Context mContext; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + } + + @Test + public void testGetSettingsActivity_configActivity() throws Exception { + AutomaticZenRule rule = new AutomaticZenRule("name", null, + new ComponentName(mContext.getPackageName(), "test"), Uri.EMPTY, + new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + rule.setPackageName(mContext.getPackageName()); + + when(mPm.getPackageUid(null, 0)).thenReturn(-1); + when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1); + + ComponentName actual = AbstractZenModeAutomaticRulePreferenceController + .getSettingsActivity(mPm, rule, null); + + assertThat(actual).isEqualTo(new ComponentName(mContext.getPackageName(), "test")); + } + + @Test + public void testGetSettingsActivity_configActivity_wrongPackage() throws Exception { + AutomaticZenRule rule = new AutomaticZenRule("name", null, + new ComponentName("another", "test"), Uri.EMPTY, + new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + rule.setPackageName(mContext.getPackageName()); + + when(mPm.getPackageUid(null, 0)).thenReturn(-1); + when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1); + + ComponentName actual = AbstractZenModeAutomaticRulePreferenceController + .getSettingsActivity(mPm, rule, null); + + assertThat(actual).isNull(); + } + + @Test + public void testGetSettingsActivity_configActivity_unspecifiedOwner() throws Exception { + AutomaticZenRule rule = new AutomaticZenRule("name", null, + new ComponentName("another", "test"), Uri.EMPTY, + new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + + when(mPm.getPackageUid(null, 0)).thenReturn(-1); + when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1); + + ComponentName actual = AbstractZenModeAutomaticRulePreferenceController + .getSettingsActivity(mPm, rule, null); + + assertThat(actual).isEqualTo(new ComponentName("another", "test")); + } + + @Test + public void testGetSettingsActivity_cps() throws Exception { + AutomaticZenRule rule = new AutomaticZenRule("name", + new ComponentName(mContext.getPackageName(), "service"), null, Uri.EMPTY, + new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + rule.setPackageName(mContext.getPackageName()); + + ComponentInfo ci = new ComponentInfo(); + ci.packageName = mContext.getPackageName(); + ci.metaData = new Bundle(); + ci.metaData.putString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY, + ComponentName.flattenToShortString( + new ComponentName(mContext.getPackageName(), "activity"))); + + when(mPm.getPackageUid(null, 0)).thenReturn(-1); + when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1); + + ComponentName actual = AbstractZenModeAutomaticRulePreferenceController + .getSettingsActivity(mPm, rule, ci); + + assertThat(actual).isEqualTo(new ComponentName(mContext.getPackageName(), "activity")); + } + + @Test + public void testGetSettingsActivity_cps_wrongPackage() throws Exception { + AutomaticZenRule rule = new AutomaticZenRule("name", + new ComponentName(mContext.getPackageName(), "service"), null, Uri.EMPTY, + new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + rule.setPackageName("other"); + + ComponentInfo ci = new ComponentInfo(); + ci.packageName = mContext.getPackageName(); + ci.metaData = new Bundle(); + ci.metaData.putString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY, + ComponentName.flattenToShortString( + new ComponentName(mContext.getPackageName(), "activity"))); + + when(mPm.getPackageUid(null, 0)).thenReturn(-1); + when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1); + + ComponentName actual = AbstractZenModeAutomaticRulePreferenceController + .getSettingsActivity(mPm, rule, ci); + + assertThat(actual).isNull(); + } + + @Test + public void testGetSettingsActivity_cps_unspecifiedPackage() throws Exception { + AutomaticZenRule rule = new AutomaticZenRule("name", + new ComponentName(mContext.getPackageName(), "service"), null, Uri.EMPTY, + new ZenPolicy(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + + ComponentInfo ci = new ComponentInfo(); + ci.packageName = mContext.getPackageName(); + ci.metaData = new Bundle(); + ci.metaData.putString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY, + ComponentName.flattenToShortString( + new ComponentName(mContext.getPackageName(), "activity"))); + + when(mPm.getPackageUid(null, 0)).thenReturn(-1); + when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1); + + ComponentName actual = AbstractZenModeAutomaticRulePreferenceController + .getSettingsActivity(mPm, rule, ci); + + assertThat(actual).isEqualTo(new ComponentName(mContext.getPackageName(), "activity")); + } +} \ No newline at end of file From bf751bb0de5784c1b594d5d90c88a2929bfee121 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Wed, 27 Jul 2022 17:17:51 +0000 Subject: [PATCH 12/35] Revert "Prevent exfiltration of system files via user image settings." This reverts commit 8950a9002402de6e1218bab3da52868a51104a95. Reason for revert: regression if multiple crop system crop handlers are present Change-Id: Ib83dbb2f1109d26b7e85192379291bffef187e77 Merged-In: I15e15ad88b768a5b679de32c5429d921d850a3cb (cherry picked from commit c0742e745da55452a412b4bb7bd28c5ecf3a8cb2) Merged-In: Ib83dbb2f1109d26b7e85192379291bffef187e77 From 8f834ce8433d8a1ef44084114fbd4a2c21e3be97 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Fri, 26 Aug 2022 18:29:16 +0100 Subject: [PATCH 13/35] Prevent exfiltration of system files via avatar picker. This adds mitigations to prevent system files being exfiltrated via the settings content provider when a content URI is provided as a chosen user image. The mitigations are: 1) Copy the image to a new URI rather than the existing takePictureUri prior to cropping. 2) Only allow a system handler to respond to the CROP intent. This is a fixed version of ag/17003629, to address b/239513606. Bug: 187702830 Test: build and check functionality Merged-In: I15e15ad88b768a5b679de32c5429d921d850a3cb Change-Id: I98eea867f926c508456ec9bc654e24eeeffa0e54 (cherry picked from commit f70e351d1a3bc7765da1fa8f9e0bb52d425b27e4) Merged-In: I98eea867f926c508456ec9bc654e24eeeffa0e54 --- .../android/settings/users/EditUserPhotoController.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/users/EditUserPhotoController.java b/src/com/android/settings/users/EditUserPhotoController.java index bd698c2b34b..735a2a8ade3 100644 --- a/src/com/android/settings/users/EditUserPhotoController.java +++ b/src/com/android/settings/users/EditUserPhotoController.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; @@ -268,13 +269,13 @@ private void cropPhoto(final Uri pictureUri) { } private boolean startSystemActivityForResult(Intent intent, int code) { - ActivityInfo info = intent.resolveActivityInfo(mContext.getPackageManager(), - PackageManager.MATCH_SYSTEM_ONLY); - if (info == null) { + List resolveInfos = mContext.getPackageManager() + .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY); + if (resolveInfos.isEmpty()) { Log.w(TAG, "No system package activity could be found for code " + code); return false; } - intent.setPackage(info.packageName); + intent.setPackage(resolveInfos.get(0).activityInfo.packageName); mFragment.startActivityForResult(intent, code); return true; } From 189da2323dc802d30f594d9ea3150351d4418a40 Mon Sep 17 00:00:00 2001 From: Milton Wu Date: Mon, 8 Aug 2022 09:05:00 +0000 Subject: [PATCH 14/35] Add FLAG_SECURE for ChooseLockPassword and Pattern Prevent ChooseLockPassword and ChooseLockPatten being projected to remote views, add FLAG_SECURE for these screens. Bug: 179725730 Test: Check these 2 screens not projected to chromecast Test: robo test for SetupChooseLockPatternTest ChooseLockPatternTest SetupChooseLockPasswordTest ChooseLockPasswordTest Change-Id: I7449a24427c966c1aa4280a7b7e7e70b60997cca --- .../settings/password/ChooseLockPassword.java | 2 ++ .../settings/password/ChooseLockPattern.java | 2 ++ .../password/ChooseLockPasswordTest.java | 16 ++++++++++++++++ .../settings/password/ChooseLockPatternTest.java | 10 ++++++++++ 4 files changed, 30 insertions(+) diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index 19cc9c8018a..6688fe727cb 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -61,6 +61,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.widget.ImeAwareEditText; import android.widget.TextView; @@ -200,6 +201,7 @@ protected void onCreate(Bundle savedInstanceState) { setTitle(msg); findViewById(R.id.content_parent).setFitsSystemWindows(false); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); } public static class ChooseLockPasswordFragment extends InstrumentedFragment diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index 3b60b7532ce..773ccf65c3b 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -35,6 +35,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ScrollView; +import android.view.WindowManager; import android.widget.TextView; import androidx.fragment.app.Fragment; @@ -182,6 +183,7 @@ protected void onCreate(Bundle savedInstanceState) { setTitle(msg); findViewById(R.id.content_parent).setFitsSystemWindows(false); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); } @Override diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java index 5ec6f41abbf..37fbd672f1d 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java @@ -27,6 +27,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static com.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY; import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS; @@ -162,6 +163,21 @@ public void intentBuilder_setProfileToUnify_shouldAddExtras() { .isNotNull(); } + @Test + public void activity_shouldHaveSecureFlag() { + PasswordPolicy policy = new PasswordPolicy(); + policy.quality = PASSWORD_QUALITY_ALPHABETIC; + policy.length = 10; + + Intent intent = createIntentForPasswordValidation( + /* minMetrics */ policy.getMinMetrics(), + /* minComplexity= */ PASSWORD_COMPLEXITY_NONE, + /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC); + ChooseLockPassword activity = buildChooseLockPasswordActivity(intent); + final int flags = activity.getWindow().getAttributes().flags; + assertThat(flags & FLAG_SECURE).isEqualTo(FLAG_SECURE); + } + @Test public void processAndValidatePasswordRequirements_noMinPasswordComplexity() { mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_ALPHABETIC); diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java index 557e7c169c6..1bad44e904c 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java @@ -16,6 +16,8 @@ package com.android.settings.password; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; + import static com.google.common.truth.Truth.assertThat; import static org.robolectric.RuntimeEnvironment.application; @@ -128,6 +130,14 @@ public void smallScreens_shouldHideIcon() { assertThat(iconView.getVisibility()).isEqualTo(View.GONE); } + @Test + public void activity_shouldHaveSecureFlag() { + final ChooseLockPattern activity = Robolectric.buildActivity( + ChooseLockPattern.class, new IntentBuilder(application).build()).setup().get(); + final int flags = activity.getWindow().getAttributes().flags; + assertThat(flags & FLAG_SECURE).isEqualTo(FLAG_SECURE); + } + private ChooseLockPattern createActivity(boolean addFingerprintExtra) { return Robolectric.buildActivity( ChooseLockPattern.class, From 3f64f86220804ca511b3471ab9dc7bfe437bf9e7 Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Thu, 14 Oct 2021 15:06:33 +0000 Subject: [PATCH 15/35] Rephrase dialog message of clear storage dialog for security concern Bug: 193890833 Test: visual Change-Id: I8f0b066de710169ee8b922c44b6519ca21b9c7ef (cherry picked from commit 0c359da620498d536d81cb97d5ae48048201c226) (cherry picked from commit 6024ea553a5f662f4693bd203aedbbcce049a15e) Merged-In:I8f0b066de710169ee8b922c44b6519ca21b9c7ef --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 436571bd5dd..dbb6029f5c7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4488,7 +4488,7 @@ Delete app data? - All this app\u2019s data will be deleted permanently. This includes all files, settings, accounts, databases, etc. + This app\u2019s data will be permanently deleted. This includes files, settings, databases, and other app data. OK From d9118be198a413eca0dbb90bfb773bc918e5dde4 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Wed, 3 Nov 2021 17:46:32 -0700 Subject: [PATCH 16/35] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Merged-In: I5b0f9ac74627cc5ab75cc34e47a4292e6a9543b0 Change-Id: I64fda49900da659363eb4e792cf5b87a9c68202d (cherry picked from commit 6cd48383a10f4d513fbbeffc31309f5ee4a7f381) Merged-In:I64fda49900da659363eb4e792cf5b87a9c68202d --- res/values-af/strings.xml | 2 +- res/values-am/strings.xml | 2 +- res/values-ar/strings.xml | 2 +- res/values-as/strings.xml | 2 +- res/values-az/strings.xml | 2 +- res/values-b+sr+Latn/strings.xml | 2 +- res/values-be/strings.xml | 2 +- res/values-bg/strings.xml | 2 +- res/values-bn/strings.xml | 2 +- res/values-bs/strings.xml | 2 +- res/values-ca/strings.xml | 2 +- res/values-cs/strings.xml | 2 +- res/values-da/strings.xml | 2 +- res/values-de/strings.xml | 2 +- res/values-el/strings.xml | 2 +- res/values-en-rAU/strings.xml | 2 +- res/values-en-rCA/strings.xml | 2 +- res/values-en-rGB/strings.xml | 2 +- res/values-en-rIN/strings.xml | 2 +- res/values-en-rXC/strings.xml | 2 +- res/values-es-rUS/strings.xml | 2 +- res/values-es/strings.xml | 2 +- res/values-et/strings.xml | 2 +- res/values-eu/strings.xml | 2 +- res/values-fa/strings.xml | 2 +- res/values-fi/strings.xml | 2 +- res/values-fr-rCA/strings.xml | 2 +- res/values-fr/strings.xml | 2 +- res/values-gl/strings.xml | 2 +- res/values-gu/strings.xml | 2 +- res/values-hi/strings.xml | 2 +- res/values-hr/strings.xml | 2 +- res/values-hu/strings.xml | 2 +- res/values-hy/strings.xml | 2 +- res/values-in/strings.xml | 2 +- res/values-is/strings.xml | 2 +- res/values-it/strings.xml | 2 +- res/values-iw/strings.xml | 2 +- res/values-ja/strings.xml | 2 +- res/values-ka/strings.xml | 2 +- res/values-kk/strings.xml | 2 +- res/values-km/strings.xml | 2 +- res/values-kn/strings.xml | 2 +- res/values-ko/strings.xml | 2 +- res/values-ky/strings.xml | 2 +- res/values-lo/strings.xml | 2 +- res/values-lt/strings.xml | 2 +- res/values-lv/strings.xml | 2 +- res/values-mk/strings.xml | 2 +- res/values-ml/strings.xml | 2 +- res/values-mn/strings.xml | 2 +- res/values-mr/strings.xml | 2 +- res/values-ms/strings.xml | 2 +- res/values-my/strings.xml | 2 +- res/values-nb/strings.xml | 2 +- res/values-ne/strings.xml | 2 +- res/values-nl/strings.xml | 2 +- res/values-or/strings.xml | 2 +- res/values-pa/strings.xml | 2 +- res/values-pl/strings.xml | 2 +- res/values-pt-rBR/strings.xml | 2 +- res/values-pt-rPT/strings.xml | 2 +- res/values-pt/strings.xml | 2 +- res/values-ro/strings.xml | 2 +- res/values-ru/strings.xml | 2 +- res/values-si/strings.xml | 2 +- res/values-sk/strings.xml | 2 +- res/values-sl/strings.xml | 2 +- res/values-sq/strings.xml | 2 +- res/values-sr/strings.xml | 2 +- res/values-sv/strings.xml | 2 +- res/values-sw/strings.xml | 2 +- res/values-ta/strings.xml | 2 +- res/values-te/strings.xml | 2 +- res/values-th/strings.xml | 2 +- res/values-tl/strings.xml | 2 +- res/values-tr/strings.xml | 2 +- res/values-uk/strings.xml | 2 +- res/values-ur/strings.xml | 2 +- res/values-uz/strings.xml | 4 ++-- res/values-vi/strings.xml | 2 +- res/values-zh-rCN/strings.xml | 2 +- res/values-zh-rHK/strings.xml | 2 +- res/values-zh-rTW/strings.xml | 2 +- res/values-zu/strings.xml | 2 +- 85 files changed, 86 insertions(+), 86 deletions(-) diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index d9c48f7f46d..eebb98d7c26 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -1930,7 +1930,7 @@ "Interne berging" "Herbereken tans grootte…" "Vee programdata uit?" - "Alle data van hierdie program sal permanent uitgevee word. Dit sluit alle lêers, instellings, rekeninge, databasisse ens. in." + "Hierdie program se data sal permanent uitgevee word. Dit sluit lêers, instellings, databasisse en ander programdata in." "OK" "Kanselleer" diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index 68cbc38f9e3..2d53cc24f21 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -1930,7 +1930,7 @@ "የውስጥ ማከማቻ" "መጠን ድጋሚ በማስላት ላይ..." "መተግበሪያ ውሂብ ሰርዝ?" - "የዚህ መተግበሪያ ውሂቦች ሁሉ በቋሚነት ይሰረዛሉ።እነዚህም ፋይሎችን፣ ቅንብሮችን፣ መለያዎችን፣ የውሂብ ጎታዎች እና የመሳሰሉትን ያካትታሉ።" + "የዚህ መተግበሪያ ውሂብ እስከመጨረሻው ይሰረዛል። ይህ ፋይሎችን፣ ቅንብሮችን፣ የውሂብ ጎታን እና ሌላ የመተግበሪያ ውሂብን ያካትታል።" "እሺ" "ይቅር" diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 2fc0e693637..33d950ce59b 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -2026,7 +2026,7 @@ "وحدة التخزين الداخلية" "جارٍ إعادة حساب الحجم..." "هل تريد حذف بيانات التطبيق؟" - "سيتم حذف جميع بيانات هذا التطبيق نهائيًا. ويشمل ذلك جميع الملفات والإعدادات والحسابات وقواعد البيانات وما إلى ذلك." + "سيتم حذف بيانات هذا التطبيق نهائيًا، بما في ذلك الملفات والإعدادات وقواعد البيانات وبيانات التطبيق الأخرى." "حسنًا" "إلغاء" diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml index 69a750833d5..fe064d859ef 100644 --- a/res/values-as/strings.xml +++ b/res/values-as/strings.xml @@ -1930,7 +1930,7 @@ "আভ্যন্তৰীণ সঞ্চয়াগাৰ" "এপৰ আকাৰ পুনঃগণনা কৰা হৈছে…" "এপ্ ডেটা মচিবনে?" - "এই এপটোৰ সকলো ডেটা চিৰদিনৰ বাবে মচা হ\'ব। সেই ডেটাসমূহৰ ভিতৰত ফাইল ছেটিং, একাউণ্ট, ডেটাবেইছ আদিসমূহ অন্তৰ্ভুক্ত।" + "এই এপৰ ডেটাখিনি স্থায়ীভাৱে মচা হ’ব। ইয়াত ফাইল, ছেটিং, ডেটাবে’ছ আৰু অন্য এপৰ ডেটা অন্তৰ্ভুক্ত।" "ঠিক" "বাতিল কৰক" diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml index 629ece2c3ce..2aaae6e6567 100644 --- a/res/values-az/strings.xml +++ b/res/values-az/strings.xml @@ -1930,7 +1930,7 @@ "Daxili yaddaş" "Ölçünü yenidən hesablayır..." "Tətbiq məlumatları silinsin?" - "Bu tətbiq datası həmişəlik silinəcək. Buraya bütün fayllar, ayarlar, hesablar, verilənlər bazası və sairləri aiddir." + "Bu tətbiq datası həmişəlik silinəcək. Buraya fayllar, ayarlar, data bazaları və digər tətbiq datası daxildir." "OK" "Ləğv et" diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml index c75139b82dc..094959c337e 100644 --- a/res/values-b+sr+Latn/strings.xml +++ b/res/values-b+sr+Latn/strings.xml @@ -1954,7 +1954,7 @@ "Interno skladište" "Ponovno izračunavanje veličine..." "Želite li da izbrišete podatke o aplikaciji?" - "Svi podaci ove aplikacije biće trajno izbrisani. To obuhvata sve datoteke, podešavanja, naloge, baze podataka itd." + "Podaci ove aplikacije će se trajno izbrisati. To obuhvata fajlove, podešavanja, baze podataka i druge podatke aplikacija." "Potvrdi" "Otkaži" diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index bb7c72a79cf..6933be26f07 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -1978,7 +1978,7 @@ "Унутраная памяць" "Пераразлік памеру..." "Выдаліць даныя праграмы?" - "Усе даныя гэтай праграмы будуць назаўсёды выдаленыя. Гэта датычыцца ўсiх файлаў, налад, уліковых запісаў, баз даных і г. д." + "Даныя гэтай праграмы (файлы, налады, базы даных і г. д.) будуць выдалены назаўсёды." "ОК" "Скасаваць" diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 01c1c05112b..2f6fce14e3e 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -1930,7 +1930,7 @@ "Вътр. хранилище" "Размерът се преизчислява..." "Да се изтрият ли данните от приложенията?" - "Всички данни на това приложение ще бъдат изтрити за постоянно. Това включва всички файлове, настройки, профили и т.н." + "Данните на приложението ще бъдат изтрити за постоянно. Това включва файловете, настройките, базите от данни и други данни от приложението." "OK" "Отказ" diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml index 424ba555dca..0771c2c93a9 100644 --- a/res/values-bn/strings.xml +++ b/res/values-bn/strings.xml @@ -1930,7 +1930,7 @@ "ইন্টারনাল স্টোরেজ" "আকার আবার গণনা করা হচ্ছে..." "অ্যাপ ডেটা মুছবেন?" - "এই অ্যাপের সমস্ত ডেটা স্থায়ীভাবে মুছে যাবে। সমস্ত ফাইল, সেটিংস, অ্যাকাউন্ট, ডেটাবেস ইত্যাদি সবই।" + "এই অ্যাপের ডেটা স্থায়ীভাবে মুছে ফেলা হবে। এর মধ্যে ফাইল, সেটিংস, ডেটাবেস এবং অন্য অ্যাপ ডেটা আছে।" "ঠিক আছে" "বাতিল" diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml index 36d06e20e29..3fe32bae996 100644 --- a/res/values-bs/strings.xml +++ b/res/values-bs/strings.xml @@ -1954,7 +1954,7 @@ "Unutrašnja pohrana" "Ponovno izračunavanje veličine…" "Izbrisati podatke aplikacija?" - "Svi podaci ove aplikacije će biti trajno izbrisani. To uključuje sve fajlove, postavke, račune, baze podataka itd." + "Ovi podaci aplikacije će se trajno izbrisati. To obuhvata fajlove, postavke, baze podataka i ostale podatke aplikacije." "Uredu" "Otkaži" diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 15919aa7d5f..408a50a5808 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -1930,7 +1930,7 @@ "Emmagatzematge intern" "S\'està tornant a calcular la mida..." "Vols suprimir les dades de l\'aplicació?" - "Se suprimiran totes les dades d\'aquesta aplicació permanentment. Això inclou tots els fitxers, la configuració, els comptes, les bases de dades, etc." + "Les dades d'aquesta aplicació se suprimiran permanentment. Això inclou fitxers, opcions de configuració, bases de dades i altres dades de l'aplicació." "D\'acord" "Cancel·la" diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 0eb6474402e..a79f332eae2 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -1978,7 +1978,7 @@ "Interní úložiště" "Přepočítávání velikosti..." "Vymazat data aplikace?" - "Veškerá data (všechny soubory, nastavení, účty, databáze apod.) této aplikace budou trvale vymazána." + "Data této aplikace budou trvale smazána. To zahrnuje soubory, nastavení, databáze a další data aplikace." "OK" "Zrušit" diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index cc68ed0683e..863dac9d63e 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -1930,7 +1930,7 @@ "Intern lagerplads" "Beregner størrelse igen..." "Vil du slette appdata?" - "Alle data i denne app slettes permanent. Det omfatter alle filer, indstillinger, konti, databaser osv." + "Denne apps data slettes permanent. Det omfatter filer, indstillinger, databaser og andre appdata." "OK" "Annuller" diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index b2acb11e613..f9b4f790a52 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -1931,7 +1931,7 @@ "Interner Speicher" "Größe wird neu berechnet..." "App-Daten löschen?" - "Alle Daten dieser App werden endgültig gelöscht. Dazu zählen alle Dateien, Einstellungen, Konten, Datenbanken usw." + "Die Daten dieser App werden endgültig gelöscht. Dazu gehören Dateien, Einstellungen, Datenbanken und sonstige App-Daten." "Ok" "Abbrechen" diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index e8e2adf4162..f138b8ffb93 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -1930,7 +1930,7 @@ "Εσ. αποθ. χώρος" "Εκ νέου υπολογισμός μεγέθους..." "Διαγραφή δεδομένων εφαρμογής;" - "Όλα τα δεδομένα της εφαρμογής θα διαγραφούν μόνιμα. Αυτό περιλαμβάνει όλα τα αρχεία, τις ρυθμίσεις, τους λογαριασμούς, τις βάσεις δεδομένων κ.λπ." + "Τα δεδομένα αυτής της εφαρμογής θα διαγραφούν οριστικά. Σε αυτά περιλαμβάνονται αρχεία, ρυθμίσεις, βάσεις δεδομένων και άλλα δεδομένα εφαρμογών." "OK" "Ακύρωση" diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml index 819818e7997..524834b5cda 100644 --- a/res/values-en-rAU/strings.xml +++ b/res/values-en-rAU/strings.xml @@ -1930,7 +1930,7 @@ "Internal storage" "Recomputing size…" "Delete app data?" - "All of this app\'s data will be deleted permanently. This includes all files, settings, accounts, databases, etc." + "This app’s data will be permanently deleted. This includes files, settings, databases and other app data." "OK" "Cancel" diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml index bf601b38846..0ba7a7b7fe3 100644 --- a/res/values-en-rCA/strings.xml +++ b/res/values-en-rCA/strings.xml @@ -1930,7 +1930,7 @@ "Internal storage" "Recomputing size…" "Delete app data?" - "All of this app\'s data will be deleted permanently. This includes all files, settings, accounts, databases, etc." + "This app’s data will be permanently deleted. This includes files, settings, databases and other app data." "OK" "Cancel" diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 20c5efccf27..1f21d2092ec 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -1930,7 +1930,7 @@ "Internal storage" "Recomputing size…" "Delete app data?" - "All of this app\'s data will be deleted permanently. This includes all files, settings, accounts, databases, etc." + "This app’s data will be permanently deleted. This includes files, settings, databases and other app data." "OK" "Cancel" diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index 4992f1b39a1..710254e8474 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -1930,7 +1930,7 @@ "Internal storage" "Recomputing size…" "Delete app data?" - "All of this app\'s data will be deleted permanently. This includes all files, settings, accounts, databases, etc." + "This app’s data will be permanently deleted. This includes files, settings, databases and other app data." "OK" "Cancel" diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml index 2581f5dea83..7b32b45754f 100644 --- a/res/values-en-rXC/strings.xml +++ b/res/values-en-rXC/strings.xml @@ -1930,7 +1930,7 @@ "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎Internal storage‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‏‎‎‎‎Recomputing size…‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎Delete app data?‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎All this app’s data will be deleted permanently. This includes all files, settings, accounts, databases, etc.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎This app’s data will be permanently deleted. This includes files, settings, databases, and other app data.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‎‏‎‏‎OK‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎Cancel‎‏‎‎‏‎" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 113855ddf00..4c69c787a28 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -1930,7 +1930,7 @@ "Almacenamiento interno" "Recalculando el tamaño…" "¿Borrar los datos de la app?" - "Se eliminarán de forma permanente todos los datos de esta aplicación, incluidos archivos, ajustes, cuentas, bases de datos, etc." + "Se borrarán de forma permanente los datos de esta app. Se incluyen archivos, parámetros de configuración, bases de datos y otros datos de app." "Aceptar" "Cancelar" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index f055a1d5442..6977d7a9b96 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -1930,7 +1930,7 @@ "Almacenamiento interno" "Recalculando tamaño…" "¿Eliminar datos de la aplicación?" - "Todos los datos de esta aplicación se eliminarán de forma permanente. Esto incluye todos los archivos, ajustes, cuentas, bases de datos, etc." + "Los datos de esta aplicación se eliminarán de forma permanente, incluidos los archivos, ajustes, bases de datos y otros datos relacionados con ella." "Aceptar" "Cancelar" diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index e03dd53d6a8..e6efea35ba8 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -1930,7 +1930,7 @@ "Sisemälu" "Suuruse ümberarvutamine ..." "Kas kustutada rakenduse andmed?" - "Rakenduse kõik andmed kustutatakse lõplikult. See hõlmab kõiki faile, seadeid, kontosid, andmebaase jne." + "Selle rakenduse andmed kustutatakse jäädavalt. See hõlmab faile, seadeid, andmebaase ja muid rakenduse andmeid." "OK" "Tühista" diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index 301626b9e54..a489ef546b2 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -1930,7 +1930,7 @@ "Barneko memoria" "Tamaina berriro kalkulatzen…" "Aplikazioetako datuak ezabatu?" - "Aplikazio honetako datu guztiak betiko ezabatuko dira; besteak beste, fitxategi, ezarpen, kontu, datu-base eta abar guztiak." + "Aplikazio honen datuak betiko ezabatuko dira; besteak beste, fitxategiak, ezarpenak, datu-baseak eta aplikazioko beste batu batzuk." "Ados" "Utzi" diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 59e91d7c7e8..be8749996e2 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -1930,7 +1930,7 @@ "فضای ذخیره‌سازی داخلی" "محاسبه مجدد اندازه…" "داده‌های برنامه حذف شود؟" - "همه داده‌های این برنامه به صورت دائمی حذف می‌شود. این شامل تمام فایل‌ها، تنظیمات، حساب‌ها، پایگاه‌های داده و دیگر موارد می‌شود." + "داده‌های این برنامه به‌طور دائم حذف خواهد شد. این شامل فایل‌ها، تنظیمات، پایگاه‌های داده، و دیگر داده‌های برنامه می‌شود." "تأیید" "لغو" diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index eca056a5ae0..d6fc5d910e2 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -1930,7 +1930,7 @@ "Sisäinen tallennustila" "Lasketaan kokoa uudelleen..." "Poistetaanko sovelluksen tiedot?" - "Kaikki tämän sovelluksen tiedot poistetaan pysyvästi. Tähän sisältyvät kaikki tiedostot, asetukset, tilit, tietokannat jne." + "Sovelluksen data poistetaan pysyvästi. Tämä koskee tiedostoja, asetuksia, tietokantoja ja muuta sovellusdataa." "OK" "Peruuta" diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index 37e2ddf7628..fdfcb6d5039 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -1930,7 +1930,7 @@ "Mémoire de stockage interne" "Calcul de la taille..." "Supprimer les données de l\'application?" - "Toutes les données de cette application seront supprimées définitivement, y compris tous les fichiers, les paramètres, les comptes, les bases de données, etc." + "Les données de cette application seront définitivement supprimées. Cela inclut les fichiers, les paramètres, les bases de données et d'autres données de l'application." "OK" "Annuler" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 42545707e67..99442fd03da 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -1930,7 +1930,7 @@ "Stockage interne" "Calcul de la taille..." "Supprimer les données de l\'application ?" - "Toutes les données de cette application (fichiers, paramètres, comptes, bases de données, etc.) seront définitivement supprimées." + "Les données de cette application (fichiers, paramètres, comptes, bases de données, etc.) seront définitivement supprimées." "OK" "Annuler" diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index aae643f6d94..2e05913a50c 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -1930,7 +1930,7 @@ "Almacenamento interno" "Recalculando o tamaño…" "Eliminar os datos da aplicación?" - "Eliminaranse todos os datos desta aplicación permanentemente. Entre estes inclúense todos os ficheiros, opcións de configuracións, contas, bases de datos etc." + "Os datos desta aplicación (como os ficheiros, a configuración e as bases de datos) eliminaranse de forma permanente." "Aceptar" "Cancelar" diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index 047eca2b271..3a4ab2ec64a 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -1930,7 +1930,7 @@ "આંતરિક સ્ટોરેજ" "કદની ફરીથી ગણના કરી રહ્યું છે…" "ઍપ્લિકેશન ડેટા કાઢી નાખીએ?" - "આ તમામ એપ્લિકેશનનો ડેટા કાયમી રીતે કાઢી નાંખવામાં આવશે. આમાં તમામ ફાઇલો, સેટિંગ્સ, એકાઉન્ટ્સ, ડેટાબેસેસ વગેરે શામેલ છે." + "આ ઍપના ડેટાને કાયમી રીતે કાઢી નાખવામાં આવશે. આમાં ફાઇલો, સેટિંગ, ડેટાબેઝ અને અન્ય ઍપ ડેટા પણ શામેલ હોય છે." "ઓકે" "રદ કરો" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 54582153a3a..64e1af932fe 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -1930,7 +1930,7 @@ "मोबाइल मेमोरी" "आकार फिर से परिकलित कर रहा है…" "ऐप्‍लिकेशन डेटा हटाएं?" - "इस ऐप्लिकेशन का सारा डेटा स्‍थायी रूप से हटा दिया जाएगा. इसमें सभी फ़ाइलें, सेटिंग, खाते, डेटाबेस वगैरह शामिल हैं." + "इस ऐप्लिकेशन का डेटा हमेशा के लिए मिटा दिया जाएगा. इसमें फ़ाइलें, सेटिंग, डेटाबेस, और ऐप्लिकेशन का दूसरा डेटा शामिल है." "ठीक है" "रद्द करें" diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index 5d3b711ca39..9e6dddf2a58 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -1954,7 +1954,7 @@ "Unutarnja pohrana" "Ponovni izračun veličine…" "Izbrisati podatke aplikacije?" - "Svi podaci ove aplikacije bit će trajno izbrisani. To uključuje sve datoteke, postavke, račune, baze podataka itd." + "Podaci aplikacije trajno će se izbrisati. To uključuje datoteke, postavke, baze podataka i druge podatke aplikacije." "U redu" "Odustani" diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 56e39dc4143..209fd6d8c21 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -1930,7 +1930,7 @@ "Belső tárhely" "Méret újraszámítása..." "Törli az alkalmazás adatait?" - "Az alkalmazás minden adatát véglegesen törölni fogja. Ez magában foglalja az összes fájlt, beállítást, fiókot, adatbázist stb." + "Az alkalmazás adatai véglegesen törlődnek. Így törlődni fognak a fájlok, a beállítások, az adatbázisok és az egyéb alkalmazásadatok is." "OK" "Mégse" diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml index 2d84103535f..d7fa1d01413 100644 --- a/res/values-hy/strings.xml +++ b/res/values-hy/strings.xml @@ -1930,7 +1930,7 @@ "Ներքին պահոց" "Չափի վերահաշվարկում…" "Ջնջե՞լ հավելվածի տվյալները" - "Այս հավելվածի բոլոր տվյալներն ընդմիշտ կջնջվեն: Այն կներառի բոլոր ֆայլերը, կարգավորումները, հաշիվները, տվյալների շտեմարանները և այլն:" + "Այս հավելվածի տվյալներն ընդմիշտ կջնջվեն։Դա վերաբերում է ֆայլերին, կարգավորումներին, տվյալների շտեմարաններին և հավելվածի այլ տվյալներին։" "Հաստատել" "Չեղարկել" diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index f2e7999a823..8053d3f3d67 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -1930,7 +1930,7 @@ "Penyimpanan internal" "Menghitung ulang ukuran..." "Hapus data aplikasi?" - "Semua data aplikasi ini akan dihapus secara permanen, termasuk semua file, setelan, akun, basis data, dll." + "Data aplikasi ini akan dihapus secara permanen. Data ini termasuk file, setelan, database, dan data aplikasi lainnya." "Oke" "Batal" diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml index dfc036ca6d8..f66e8b39c11 100644 --- a/res/values-is/strings.xml +++ b/res/values-is/strings.xml @@ -1930,7 +1930,7 @@ "Innbyggð geymsla" "Endurreiknar stærð…" "Eyða forritsgögnum?" - "Öllum gögnum þessa forrits verður eytt fyrir fullt og allt. Í þessu felast allar skrár, stillingar, reikningar, gagnagrunnar o.s.frv." + "Gögnum þessa forrits verður eytt fyrir fullt og allt. Þetta á við um skrár, stillingar, gagnagrunna og önnur forritsgögn." "Í lagi" "Hætta við" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 35fda617ab1..c09536258bf 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -1930,7 +1930,7 @@ "Memoria interna" "Ricalcolo dimensioni…" "Eliminare i dati dell\'app?" - "Tutti i dati dell\'app verranno eliminati definitivamente, inclusi tutti i file, le impostazioni, gli account, i database e così via." + "I dati di questa app verranno eliminati definitivamente, inclusi file, impostazioni, database e altri dati dell'app." "OK" "Annulla" diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 85b23617fce..f7aba18e330 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -1978,7 +1978,7 @@ "אחסון פנימי" "הגודל מחושב מחדש..." "למחוק את נתוני האפליקציה?" - "כל נתוני האפליקציה יימחקו לתמיד. נתונים אלה כוללים את כל הקבצים, ההגדרות, החשבונות, מסדי הנתונים וכדומה." + "נתוני האפליקציה יימחקו באופן סופי. לרבות קבצים, הגדרות, מסדי נתונים ונתונים אחרים מהאפליקציה." "אישור" "ביטול" diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 194ac6946d1..b2ab707b54d 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -1930,7 +1930,7 @@ "内部ストレージ" "サイズを再計算中..." "アプリのデータを削除しますか?" - "このアプリのすべてのデータ(ファイル、設定、アカウント、データベースを含む)が完全に削除されます。" + "このアプリのデータが完全に削除されます。ファイル、設定、データベース、その他のアプリデータが対象になります。" "OK" "キャンセル" diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml index 0be29e6068c..1b328de35d9 100644 --- a/res/values-ka/strings.xml +++ b/res/values-ka/strings.xml @@ -1930,7 +1930,7 @@ "შიდა მეხსიერება" "ზომის გადათვლა…" "წაიშალოს აპის მონაცემები?" - "აპის მონაცემები, მათ შორის ყველა ფაილი, პარამეტრი, ანგარიში, მონაცემთა ბაზა და ა.შ. სამუდამოდ წაიშლება." + "ამ აპის მონაცემები სამუდამოდ წაიშლება. ეს ეხება ფაილებს, პარამეტრებს, მონაცემთა ბაზებსა და აპის სხვა მონაცემებს." "კარგი" "გაუქმება" diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml index 2dc1e009df4..591a3cbe06c 100644 --- a/res/values-kk/strings.xml +++ b/res/values-kk/strings.xml @@ -1930,7 +1930,7 @@ "Ішкі жад" "Өлшемін қайта есептеуде…" "Қолданба деректері жойылсын ба?" - "Бұл қолданбаның барлық деректері мүлдем өшіріледі. Бұған барлық файлдар, параметрлер, есептік жазбалар, дерекқорлар және т.б. кіреді." + "Бұл қолданбаның дерегі біржола жойылады. Оған файлдар, параметрлер, дерекқорлар және тағы басқа қолданба дерегі кіреді." "Жарайды" "Бас тарту" diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml index 3b88cbc4e6a..aebff565c44 100644 --- a/res/values-km/strings.xml +++ b/res/values-km/strings.xml @@ -1930,7 +1930,7 @@ "ឧបករណ៍​ខាង​ក្នុង" "កំពុង​គណនា​ទំហំ​ឡើងវិញ…" "លុប​ទិន្នន័យ​កម្មវិធី?" - "ទិន្នន័យ​របស់​កម្មវិធី​នេះ​ទាំងអស់​នឹង​ត្រូវ​បាន​លុប​ជា​អចិន្ត្រៃយ៍។ ទិន្នន័យទាំងនេះរួមមាន ឯកសារ​ទាំងអស់ ការ​កំណត់ គណនី មូលដ្ឋាន​ទិន្នន័យ ។ល។" + "ទិន្នន័យ​របស់កម្មវិធីនេះ​នឹងត្រូវបានលុប​ជាអចិន្ត្រៃយ៍។ ទិន្នន័យនេះ​រួមមាន​ឯកសារ ការកំណត់ មូលដ្ឋាន​ទិន្នន័យ និង​ទិន្នន័យកម្មវិធី​ផ្សេងទៀត។" "យល់​ព្រម​" "បោះ​បង់​" diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml index 096ef6d8f8c..bd1657ef3eb 100644 --- a/res/values-kn/strings.xml +++ b/res/values-kn/strings.xml @@ -1930,7 +1930,7 @@ "ಆಂತರಿಕ ಸಂಗ್ರಹಣೆ" "ಗಾತ್ರವನ್ನು ಮರುಗಣನೆ ಮಾಡಲಾಗುತ್ತಿದೆ…" "ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾ ಅಳಿಸುವುದೇ?" - "ಈ ಆ್ಯಪ್‍‍ನ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಶಾಶ್ವತವಾಗಿ ಅಳಿಸಲಾಗುತ್ತದೆ. ಇದರಲ್ಲಿ ಎಲ್ಲಾ ಫೈಲ್‌ಗಳು, ಸೆಟ್ಟಿಂಗ್‌ಗಳು, ಖಾತೆಗಳು, ಡೇಟಾಬೇಸ್‌ಗಳು, ಇತ್ಯಾದಿಗಳು ಸೇರಿರುತ್ತವೆ." + "ಈ ಆ್ಯಪ್‌ನ ಡೇಟಾವನ್ನು ಶಾಶ್ವತವಾಗಿ ಅಳಿಸಲಾಗುವುದು. ಇದು ಫೈಲ್‌ಗಳು, ಸೆಟ್ಟಿಂಗ್‌ಗಳು, ಡೇಟಾಬೇಸ್‌ಗಳು ಮತ್ತು ಇತರ ಆ್ಯಪ್ ಡೇಟಾ ಒಳಗೊಂಡಿದೆ." "ಸರಿ" "ರದ್ದುಮಾಡಿ" diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 06830182b2c..4bce00dcc11 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -1930,7 +1930,7 @@ "내부 저장소" "크기 다시 계산 중..." "앱 데이터를 삭제하시겠습니까?" - "앱의 전체 데이터가 영구적으로 삭제됩니다. 여기에는 모든 파일, 설정, 계정, 데이터베이스 등이 포함됩니다." + "이 앱 데이터가 영구적으로 삭제됩니다. 삭제 대상에는 파일, 설정, 데이터베이스, 기타 앱 데이터가 포함됩니다." "확인" "취소" diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml index f581ea8ad8b..40f5e0dbe87 100644 --- a/res/values-ky/strings.xml +++ b/res/values-ky/strings.xml @@ -1930,7 +1930,7 @@ "Ички эстутум" "Өлчөмү кайра эсептелүүдө…" "Колдонмонун дайындарын өчүрөсүзбү?" - "Бул колдонмодогу файлдар, жөндөөлөр, аккаунттар жана маалымат базасы сыяктуу бардык нерселер биротоло өчүрүлөт." + "Бул колдонмодогу маалымат биротоло жок кылынат. Ага файлдар, жөндөөлөр, дайындар базалары жана колдонмонун башка дайындары кирет." "Жарайт" "Жок" diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml index 608e36e3415..483edf6d209 100644 --- a/res/values-lo/strings.xml +++ b/res/values-lo/strings.xml @@ -1930,7 +1930,7 @@ "ພື້ນທີ່ຈັດເກັບຂໍ້ມູນພາຍໃນ" "ກຳລັງຄຳນວນຂະໜາດຄືນໃໝ່..." "ລຶບຂໍ້ມູນແອັບບໍ່?" - "ຂໍ້ມູນທັງໝົດຂອງແອັບນີ້ຈະຖືກລຶບອອກຖາວອນ ເຊິ່ງຮວມເຖິງໄຟລ໌, ການຕັ້ງຄ່າ, ບັນຊີ, ຖານຂໍ້ມູນ ແລະ ອື່ນໆທັງໝົດນຳ." + "ຂໍ້ມູນຂອງແອັບນີ້ຈະຖືກລຶບອອກຖາວອນ. ນີ້ຮວມເຖິງໄຟລ໌, ການຕັ້ງຄ່າ, ຖານຂໍ້ມູນ ແລະ ຂໍ້ມູນແອັບອື່ນໆນຳ" "ຕົກລົງ" "ຍົກເລີກ" diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index f6e07edda68..8de55427368 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -1978,7 +1978,7 @@ "Vidinė atmint." "Iš naujo apskaičiuojamas dydis..." "Ištrinti programos duomenis?" - "Visi šios programos duomenys bus visam laikui ištrinti. Tai taikoma visiems failams, nustatymams, paskyroms, duomenims ir kt." + "Šios programos duomenys bus visam laikui ištrinti. Įtraukiami failai, nustatymai, duomenų bazės ir kiti programos duomenys." "Gerai" "Atšaukti" diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 8db5042b266..10bab07790c 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -1954,7 +1954,7 @@ "Iekšējā krātuve" "Notiek izmēra pārrēķināšana..." "Vai dzēst lietotnes datus?" - "Tiks neatgriezeniski dzēsti visi šīs lietotnes dati, tostarp visi faili, iestatījumi, konti, datu bāzes un citi vienumi." + "Tiks neatgriezeniski dzēsti šīs lietotnes dati, tostarp faili, iestatījumi, datu bāzes un citi lietotnes dati." "Labi" "Atcelt" diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index 81686670e03..39083f40464 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -1930,7 +1930,7 @@ "Внатрешен капацитет" "Повторно пресметување големина..." "Да се избришат податоците на апликацијата?" - "Сите податоци на оваа апликација ќе бидат трајно избришани. Ова ги опфаќа сите датотеки, поставки, сметки, бази на податоци итн." + "Податоците од апликацијава трајно ќе се избришат. Ова вклучува датотеки, поставки, бази на податоци и други податоци од апликацијата." "Во ред" "Откажи" diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml index e8dd9cd0661..80e6fc70f1f 100644 --- a/res/values-ml/strings.xml +++ b/res/values-ml/strings.xml @@ -1930,7 +1930,7 @@ "ആന്തരിക സ്റ്റോറേജ്" "വലുപ്പം വീണ്ടും കണക്കാക്കുന്നു..." "ആപ്പ് ഡാറ്റ ഇല്ലാതാക്കണോ?" - "ഈ ആപ്പിന്‍റെ എല്ലാ ഡാറ്റയും ശാശ്വതമായി ഇല്ലാതാക്കും. ഫയലുകൾ, ക്രമീകരണങ്ങൾ, അക്കൗണ്ടുകൾ, ഡാറ്റാബേസുകൾ തുടങ്ങിയവയെല്ലാം ഇതിൽ ഉൾപ്പെടും." + "ഈ ആപ്പിന്റെ ഡാറ്റ ശാശ്വതമായി ഇല്ലാതാക്കും. ഇതിൽ ഫയലുകളും ക്രമീകരണവും ഡാറ്റാബേസുകളും മറ്റ് ആപ്പ് ഡാറ്റയും ഉൾപ്പെടുന്നു." "ശരി" "റദ്ദാക്കുക" diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml index 3ebb415c3e8..cc352a4073b 100644 --- a/res/values-mn/strings.xml +++ b/res/values-mn/strings.xml @@ -1930,7 +1930,7 @@ "Дотоод сан" "Хэмжээг дахин тооцоолж байна…" "Апп өгөгдлийг устгах уу?" - "Энэ апп-н бүх өгөгдөл бүрмөсөн устах болно. Үүнд бүх файл, тохиргоо, бүртгэл, өгөгдөл гэх мэт орно." + "Энэ аппын өгөгдлийг бүрмөсөн устгана. Үүнд файл, тохиргоо, өгөгдлийн бааз болон бусад аппын өгөгдөл багтана." "OK" "Цуцлах" diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml index 8d930dff9e8..71a0bd7643a 100644 --- a/res/values-mr/strings.xml +++ b/res/values-mr/strings.xml @@ -1931,7 +1931,7 @@ "अंतर्गत स्टोरेज" "आकाराचे पुनर्संगणन करत आहे…" "अ‍ॅप डेटा हटवायचा?" - "या अ‍ॅपचा सर्व डेटा कायमचा हटवला जाईल. यात सर्व फाइल, सेटिंग्ज, खाती, डेटाबेस इ. समाविष्ट असेल." + "या ॲपचा डेटा कायमचा हटवला जाईल. यामध्ये फाइल, सेटिंग्ज, डेटाबेस आणि इतर अ‍ॅप डेटा यांचा समावेश आहे." "ठीक" "रद्द करा" diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index b40ca9707b8..ee861643bed 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -1930,7 +1930,7 @@ "Storan dalaman" "Mengira semula saiz..." "Padamkan data aplikasi?" - "Semua data aplikasi ini akan dipadamkan secara kekal. Ini termasuk semua fail, tetapan, akaun, pangkalan data, dll." + "Data apl ini akan dipadamkan secara kekal. Kandungan ini termasuk fail, tetapan, pangkalan data dan data apl yang lain." "OK" "Batal" diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml index 36b6c845054..8bc6032b55e 100644 --- a/res/values-my/strings.xml +++ b/res/values-my/strings.xml @@ -1930,7 +1930,7 @@ "စက်တွင်း သိုလှောင်ထားမှု" "အရွယ်အစားကို ပြန်လည်တွက်ချက်နေသည်" "အက်ပ်ဒေတာ ဖျက်မလား။" - "ဤအက်ပ်၏ ဒေတာအားလုံးကို အပြီးဖျက်ပါမည်။ ဖိုင်၊ ဆက်တင်၊ အကောင့်၊ ဒေတာဘေ့စ်စသည်တို့ အားလုံးပါဝင်သည်။" + "ဤအက်ပ်၏ ဒေတာကို အပြီးဖျက်ပါမည်။ ၎င်းတွင် ဖိုင်၊ ဆက်တင်၊ ဒေတာဘေ့စ်နှင့် အခြားအက်ပ် ဒေတာများ ပါဝင်သည်။" "OK" "မလုပ်တော့" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 7e8752c8055..2a5f35a06f9 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -1930,7 +1930,7 @@ "Intern lagring" "Beregner størrelse på nytt…" "Vil du slette appdataene?" - "Alle data i appen slettes permanent. Dette omfatter alle filer, innstillinger, kontoer, databaser osv." + "Dataene i denne appen slettes permanent. Dette inkluderer filer, innstillinger, databaser og andre appdata." "OK" "Avbryt" diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml index da6077b436a..b510505442d 100644 --- a/res/values-ne/strings.xml +++ b/res/values-ne/strings.xml @@ -1930,7 +1930,7 @@ "आन्तरिक भण्डारण" "आकार पुनःगणना गर्दै ..." "एप डेटा मेटाउन चाहनुहुन्छ?" - "यस एपका सम्पूर्ण डेटाहरू स्थायी रूपमा मेटाइने छ। यसमा सम्पूर्ण फाइल, सेटिङ, खाताहरू, डेटाबेस आदि पर्दछन्।" + "यो एपका डेटा सदाका लागि मेटाइने छ। यसमा फाइल, सेटिङ, डेटाबेस र एपका अन्य डेटा पर्छन्।" "ठिक छ" "रद्द गर्नुहोस्" diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 42d001080a8..7796625f688 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -1930,7 +1930,7 @@ "Interne opslag" "Grootte opnieuw berekenen..." "Gegevens van app verwijderen?" - "Alle gegevens van deze app worden permanent verwijderd. Dit omvat alle bestanden, instellingen, accounts, databases, enzovoort." + "De gegevens van deze app worden definitief verwijderd. Dit omvat bestanden, instellingen, databases en andere app-gegevens." "OK" "Annuleren" diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml index 55af6693962..4d547ebfda3 100644 --- a/res/values-or/strings.xml +++ b/res/values-or/strings.xml @@ -1930,7 +1930,7 @@ "ଇଣ୍ଟର୍ନଲ୍‌ ଷ୍ଟୋରେଜ୍‌" "ଆକାରକୁ ପୁଣି ଗଣୁଛି…" "ଆପ୍‌ର ଡାଟା ଡିଲିଟ୍‌ କରିବେ?" - "ଏହି ଆପ୍‌ର ସମସ୍ତ ଡାଟା ସ୍ଥାୟୀ ଭାବେ ଡିଲିଟ୍‌ ହୋଇଯିବ। ଏଥିରେ ରହିଛି, ସମସ୍ତ ଫାଇଲ୍‌, ସେଟିଙ୍ଗ, ଆକାଉଣ୍ଟ, ଡାଟାବେସ୍‌ ଆଦି" + "ଏହି ଆପର ଡାଟା ସ୍ଥାୟୀ ଭାବେ ଡିଲିଟ ହୋଇଯିବ। ଏଥିରେ ଫାଇଲ, ସେଟିଂସ, ଡାଟାବେସ ଏବଂ ଅନ୍ୟ ଆପ ଡାଟା ଅନ୍ତର୍ଭୁକ୍ତ।" "ଠିକ୍‌ ଅଛି" "ବାତିଲ କରନ୍ତୁ" diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml index 5a037da2055..069ba050a2c 100644 --- a/res/values-pa/strings.xml +++ b/res/values-pa/strings.xml @@ -1930,7 +1930,7 @@ "ਅੰਦਰੂਨੀ ਸਟੋਰੇਜ" "ਅਕਾਰ ਰੀਕੰਪਿਊਟ ਕਰ ਰਿਹਾ ਹੈ..." "ਕੀ ਐਪ ਡਾਟਾ ਮਿਟਾਉਣਾ ਹੈ?" - "ਇਸ ਐਪ ਦਾ ਸਾਰਾ ਡਾਟਾ ਸਥਾਈ ਤੌਰ ਤੇ ਮਿਟਾਇਆ ਜਾਏਗਾ। ਇਸ ਵਿੱਚ ਸਾਰੀਆਂ ਫ਼ਾਈਲਾਂ, ਸੈਟਿੰਗਾਂ, ਖਾਤੇ, ਡਾਟਾਬੇਸ ਆਦਿ ਸ਼ਾਮਲ ਹਨ।" + "ਇਸ ਐਪ ਦਾ ਡਾਟਾ ਪੱਕੇ ਤੌਰ 'ਤੇ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ। ਇਸ ਵਿੱਚ ਫ਼ਾਈਲਾਂ, ਸੈਟਿੰਗਾਂ, ਡਾਟਾਬੇਸ ਅਤੇ ਹੋਰ ਐਪ ਡਾਟਾ ਸ਼ਾਮਲ ਹੈ।" "ਠੀਕ" "ਰੱਦ ਕਰੋ" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index b6d0cfc5ac4..aef71a40e37 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -1978,7 +1978,7 @@ "Pamięć wewnętrzna" "Przeliczanie rozmiaru..." "Usunąć dane aplikacji?" - "Wszystkie dane tej aplikacji zostaną trwale usunięte. Dotyczy to wszystkich plików, ustawień, kont, baz danych itd." + "Dane tej aplikacji zostaną trwale usunięte. Dotyczy to plików, ustawień, baz danych i innych danych aplikacji." "OK" "Anuluj" diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml index 6da79109494..e0633ba55e9 100644 --- a/res/values-pt-rBR/strings.xml +++ b/res/values-pt-rBR/strings.xml @@ -1930,7 +1930,7 @@ "Espaço interno" "Recalculando o tamanho…" "Excluir os dados do app?" - "Todos os dados deste app serão excluídos permanentemente. Isso inclui todos os arquivos, configurações, contas, bancos de dados e outros." + "Os dados do app serão excluídos permanentemente, incluindo arquivos, configurações, bancos de dados, entre outros." "OK" "Cancelar" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 9586a08c303..823d0bc663c 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -1930,7 +1930,7 @@ "Armaz. interno" "A recalcular tamanho..." "Eliminar dados da aplicação?" - "Todos os dados desta aplicação serão eliminados permanentemente. Isto inclui todos os ficheiros, definições, contas, bases de dados, etc." + "Os dados desta app serão permanentemente eliminados. Estão incluídos ficheiros, definições, bases de dados e outros dados de apps." "OK" "Cancelar" diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index 6da79109494..e0633ba55e9 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -1930,7 +1930,7 @@ "Espaço interno" "Recalculando o tamanho…" "Excluir os dados do app?" - "Todos os dados deste app serão excluídos permanentemente. Isso inclui todos os arquivos, configurações, contas, bancos de dados e outros." + "Os dados do app serão excluídos permanentemente, incluindo arquivos, configurações, bancos de dados, entre outros." "OK" "Cancelar" diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 7c42aad9981..9c822aae08b 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -1954,7 +1954,7 @@ "Stocare internă" "Se recalculează dimensiunea..." "Ștergeți datele aplicației?" - "Toate datele acestei aplicații vor fi șterse definitiv. Aici sunt incluse toate fișierele, setările, conturile, bazele de date etc." + "Datele acestei aplicații vor fi șterse definitiv. Aici sunt incluse fișierele, setările, bazele de date și alte date ale aplicației." "OK" "Anulați" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index addb70c25f1..1fa0cd0aede 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -1978,7 +1978,7 @@ "Внутр. накопитель" "Повторное вычисление размера..." "Удалить данные приложения?" - "Все данные этого приложения будут удалены без возможности восстановления, включая все файлы, базы данных, настройки, аккаунты и т. д." + "Данные этого приложения (включая файлы, базы данных, настройки и т. д.) будут удалены без возможности восстановления." "ОК" "Отмена" diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml index 6a3198f62f2..d64bff9bb5d 100644 --- a/res/values-si/strings.xml +++ b/res/values-si/strings.xml @@ -1930,7 +1930,7 @@ "අභ්‍යන්තර ආචයනය" "විශාලත්වය නැවත ගණනය කරමින්…" "යෙදුම් දත්ත මකන්නද?" - "මෙම යෙදුමේ සියලු දත්ත ස්ථිරව මකා දමනු ඇත. මෙයට සියලු ගොනු, සැකසීම්, ගිණුම්, දත්ත සමූහ සහ තවත් අඩංගුය." + "මෙම යෙදුමේ දත්ත ස්ථිරවම මකනු ඇත. මෙයට ගොනු, සැකසීම්, දත්ත සමුදායන් සහ වෙනත් යෙදුම් දත්ත ඇතුළත් වේ." "හරි" "අවලංගු කරන්න" diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index 08c49185814..9293a4f9c4d 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -1978,7 +1978,7 @@ "Interný ukl. priestor" "Prebieha prepočítanie veľkosti..." "Odstrániť dáta aplikácie?" - "Všetky dáta tejto aplikácie vrátane súborov, nastavení, účtov, databáz atď. budú navždy odstránené." + "Dáta tejto aplikácie budú natrvalo odstránené. Zahrnujú súbory, nastavenia, databázy a ďalšie dáta aplikácie." "OK" "Zrušiť" diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 73f063871d0..115d3b82ac7 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -1978,7 +1978,7 @@ "Notranja shramba" "Preračunavanje velikosti ..." "Želite izbrisati podatke aplikacije?" - "Vsi podatki te aplikacije bodo trajno izbrisani. To med drugim vključuje vse datoteke, nastavitve, račune in podatkovne zbirke." + "Podatki te aplikacije bodo trajno izbrisani. To vključuje datoteke, nastavitve, zbirke podatkov in druge podatke aplikacije." "V redu" "Prekliči" diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml index 2b30106c252..c35f288d419 100644 --- a/res/values-sq/strings.xml +++ b/res/values-sq/strings.xml @@ -1930,7 +1930,7 @@ "Hapësira e brendshme ruajtëse" "Po llogarit përsëri madhësinë…" "Të fshihen të dhënat e aplikacionit?" - "Të gjitha të dhënat e këtij aplikacioni do të fshihen përgjithmonë. Kjo përfshin të gjithë skedarët, cilësimet, llogaritë, bazat e të dhënave etj." + "Të dhënat e këtij aplikacioni do të fshihen përgjithmonë. Këtu përfshihen skedarët, cilësimet, bazat e të dhënave dhe të dhëna të tjera të aplikacionit." "Në rregull" "Anulo" diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 23123cce863..c63989cf4d6 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -1954,7 +1954,7 @@ "Интерно складиште" "Поновно израчунавање величине..." "Желите ли да избришете податке о апликацији?" - "Сви подаци ове апликације биће трајно избрисани. То обухвата све датотеке, подешавања, налоге, базе података итд." + "Подаци ове апликације ће се трајно избрисати. То обухвата фајлове, подешавања, базе података и друге податке апликација." "Потврди" "Откажи" diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index c9a08e79b57..a680802c192 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -1930,7 +1930,7 @@ "Intern lagring" "Räknar om storlek…" "Vill du ta bort appdata?" - "Appens samtliga data tas bort permanent. Det inkluderar alla filer, inställningar, konton, databaser och så vidare." + "Appens data raderas permanent. Detta omfattar filer, inställningar, databaser och annan appdata." "OK" "Avbryt" diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 6a63c8da5df..f6a45ce72b4 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -1930,7 +1930,7 @@ "Hifadhi ya ndani" "Kiwango cha kukadiria upya" "Ungependa kufuta data ya programu?" - "Data yote ya programu hii itafutwa kabisa. Hii inajumuisha faili, mipangilio, akaunti, hifadhidata zote na mengineyo." + "Data iliyo kwenye programu hii itafutwa kabisa. Hii ni pamoja na faili, mipangilio, hifadhidata na data nyingine ya programu." "Sawa" "Ghairi" diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index ab188a67de3..3ad72885d43 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -1930,7 +1930,7 @@ "அகச் சேமிப்பிடம்" "அளவை மீண்டும் கணக்கிடுகிறது…" "ஆப்ஸ் டேட்டாவை நீக்கவா?" - "ஆப்ஸின் எல்லா தகவலும் நிரந்தரமாக நீக்கப்படும். இதில் எல்லா ஃபைல்களும், அமைப்புகளும், கணக்குகளும், தரவுத்தளங்களும், மேலும் பலவும் அடங்கும்." + "இந்த ஆப்ஸின் தரவு நிரந்தரமாக நீக்கப்படும். ஃபைல்கள், அமைப்புகள், தரவுத்தளங்கள், பிற ஆப்ஸ் தரவு ஆகியவை இதிலடங்கும்." "சரி" "ரத்துசெய்" diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index 32e4658c0aa..958d0913f19 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -1930,7 +1930,7 @@ "అంతర్గత నిల్వ" "పరిమాణాన్ని మళ్లీ గణిస్తోంది…" "యాప్ డేటాను తొలగించాలా?" - "ఈ యాప్ డేటా మొత్తం శాశ్వతంగా తొలగించబడుతుంది. ఇందులో అన్ని ఫైల్‌లు, సెట్టింగ్‌లు, ఖాతాలు, డేటాబేస్‌లు మొ. ఉన్నాయి." + "ఈ యాప్ డేటా శాశ్వతంగా తొలగించబడుతుంది. ఇందులో ఫైల్స్, సెట్టింగ్‌లు, డేటాబేస్‌లు, ఇతర యాప్ డేటా ఉంటాయి." "సరే" "రద్దు చేయి" diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index 6d78a3be61a..ea6e3466bb8 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -1930,7 +1930,7 @@ "ที่เก็บข้อมูลภายใน" "กำลังคำนวณขนาดใหม่..." "ลบข้อมูลในแอปหรือไม่" - "ข้อมูลทั้งหมดของแอปนี้จะถูกลบอย่างถาวร ซึ่งรวมถึงไฟล์ การตั้งค่า บัญชี และฐานข้อมูล" + "ระบบจะลบข้อมูลของแอปนี้อย่างถาวร ซึ่งรวมถึงไฟล์ การตั้งค่า ฐานข้อมูล และข้อมูลแอปอื่นๆ" "ตกลง" "ยกเลิก" diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index 3bc46c32a3b..aac076c3ab7 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -1930,7 +1930,7 @@ "Panloob na storage" "Muling kino-compute ang laki…" "I-delete ang data ng app?" - "Permanenteng made-delete ang lahat ng data ng app na ito. Kabilang dito ang lahat ng file, setting, account, database, atbp." + "Permanenteng made-delete ang data ng app na ito. Kasama rito ang mga file, setting, database, at iba pang data ng app." "OK" "Kanselahin" diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 462e9b3322e..d899cace693 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -1930,7 +1930,7 @@ "Dahili Bellek" "Boyut yeniden hesaplanıyor…" "Uygulama verileri silinsin mi?" - "Bu uygulamanın tüm verileri kalıcı olarak silinecek. Bu veriler arasında tüm dosyalar, ayarlar, hesaplar, veritabanları vb. yer alıyor." + "Bu uygulamanın verileri kalıcı olarak silinecek. Buna dosyalar, ayarlar, veritabanları ve diğer uygulama verileri de dahildir." "Tamam" "İptal" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 8649952dde1..e5dbd85a66a 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -1978,7 +1978,7 @@ "Внутр. пам\'ять" "Повт. обчисл. розм…" "Видалити дані додатка?" - "Усі дані цього додатка буде видалено назавжди: файли, налаштування, облікові записи, бази даних тощо." + "Дані цього додатка буде назавжди видалено. До них належать файли, налаштування, бази даних тощо." "OK" "Скасувати" diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml index 499e1f0ed1d..10077b0fcb7 100644 --- a/res/values-ur/strings.xml +++ b/res/values-ur/strings.xml @@ -1930,7 +1930,7 @@ "داخلی اسٹوریج" "سائز کو دوبارہ شمار کر رہا ہے…" "ایپ کا ڈیٹا حذف کریں؟" - "اس ایپ کا سبھی ڈیٹا مستقل طور پر حذف ہو جائے گا۔ اس میں سبھی فائلیں، ترتیبات، اکاؤنٹس، ڈیٹا بیسز وغیرہ شامل ہیں۔" + "اس ایپ کا ڈیٹا مستقل طور پر حذف کر دیا جائے گا۔ اس میں فائلز، ترتیبات، ڈیٹا بیس اور دیگر ایپ کا ڈیٹا شامل ہے۔" "ٹھیک ہے" "منسوخ کریں" diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml index d1f0b8a1380..177e0787800 100644 --- a/res/values-uz/strings.xml +++ b/res/values-uz/strings.xml @@ -1929,8 +1929,8 @@ "Hech narsa topilmadi." "Ichki xotira" "Xajm qayta hisoblanmoqda…" - "Bu ilova maʼlumotlari oʻchirilsinmi?" - "Ushbu ilovaning barcha ma’lumotlari, jumladan, fayllar, ma’lumotlar bazalari, sozlamalar, hisoblar va boshqa narsalar o‘chirib tashlanadi. Keyin ularni qayta tiklab bo‘lmaydi." + "Ilova maʼlumotlari oʻchirilsinmi?" + "Bu ilova maʼlumotlari butunlay oʻchirib tashlanadi. Unga fayllar, sozlamalar, ma’lumotlar bazalari va boshqa ilovaga tegishli maʼlumotlar kiradi" "OK" "Bekor qilish" diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index b59f30320d6..19d11edf33a 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -1930,7 +1930,7 @@ "Bộ nhớ trong" "Đang tính toán lại kích thước…" "Xóa dữ liệu ứng dụng?" - "Tất cả dữ liệu của ứng dụng này sẽ bị xóa vĩnh viễn, bao gồm tất cả các tệp, các tùy chọn cài đặt, tài khoản, cơ sở dữ liệu, v.v." + "Dữ liệu của ứng dụng này sẽ bị xóa vĩnh viễn. Dữ liệu này bao gồm các tệp, chế độ cài đặt, cơ sở dữ liệu và dữ liệu ứng dụng khác." "OK" "Hủy" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 177f6a7fc03..9b77e782299 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -1930,7 +1930,7 @@ "内部存储空间" "正在重新计算大小..." "要删除应用数据吗?" - "系统会永久删除此应用的所有数据。删除的内容包括所有文件、设置、帐号、数据库等。" + "系统将永久删除此应用的数据,其中包括文件、设置、数据库和其他应用数据。" "确定" "取消" diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index 4245842346b..c3a84aea227 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -1931,7 +1931,7 @@ "內部儲存空間" "正在重新計算大小..." "您要刪除應用程式資料嗎?" - "這個應用程式的所有資料都將被永久刪除,包含所有檔案、設定、帳戶、資料庫等。" + "系統會永久刪除此應用程式的資料,包括檔案、設定、資料庫和其他應用程式資料。" "確定" "取消" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 14d5c04b0ff..cd769c3101e 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -1930,7 +1930,7 @@ "內部儲存空間" "重新計算大小…" "你要刪除應用程式資料嗎?" - "系統會永久刪除這個應用程式的所有資料,包含所有檔案、設定、帳戶、資料庫等。" + "系統將永久刪除這個應用程式的資料,包括檔案、設定、資料庫和應用程式的其他資料。" "確定" "取消" diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index a67085e8179..5b1bcc49150 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -1931,7 +1931,7 @@ "Isitoreji sangaphakathi" "Ilungisa kabusha usayizi..." "Ngabe ususa yonke imininingo yohlelo lokusebenza?" - "Yonke le datha yohlelo lokusebenza izosuswa ngokuphelele. Lokhu kuhlanganisa wonke amafayela, izilungiselelo, ama-akhawunti, izizinda zemininingwane nokunye." + "Idatha yale app izosuswa unomphela. Lokhu kuhlanganisa amafayela, amasethingi, isizindalwazi, nenye idatha ye-app." "KULUNGILE" "Khansela" From 2eca3da18e1e4a3eee9409a5fe70963b10c48fa3 Mon Sep 17 00:00:00 2001 From: Alex Johnston Date: Mon, 29 Nov 2021 16:06:38 +0000 Subject: [PATCH 17/35] Add non system overlay flag to InstallCaCertificateWarning Bug: 196969991 Test: Manual testing with Settings Change-Id: Ia9dc251c853526b2ce66c9f8ff595d496b7f1bc4 Merged-In: Ia9dc251c853526b2ce66c9f8ff595d496b7f1bc4 (cherry picked from commit 2f193c81576e2e86cf64470aeb312cab1e76d40d) (cherry picked from commit fca5cb37486fb1072d6233670b2fd66e555b07c1) Merged-In:Ia9dc251c853526b2ce66c9f8ff595d496b7f1bc4 --- .../settings/security/InstallCaCertificateWarning.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/com/android/settings/security/InstallCaCertificateWarning.java b/src/com/android/settings/security/InstallCaCertificateWarning.java index 91faae1f6a1..b5cc6b35c72 100644 --- a/src/com/android/settings/security/InstallCaCertificateWarning.java +++ b/src/com/android/settings/security/InstallCaCertificateWarning.java @@ -16,6 +16,8 @@ package com.android.settings.security; +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + import android.annotation.Nullable; import android.app.Activity; import android.content.Intent; @@ -41,6 +43,8 @@ public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ca_certificate_warning_dialog); + getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + final GlifLayout layout = findViewById(R.id.setup_wizard_layout); final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class); @@ -52,6 +56,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { .setTheme(R.style.SudGlifButton_Secondary) .build() ); + mixin.getSecondaryButtonView().setFilterTouchesWhenObscured(true); mixin.setPrimaryButton( new FooterButton.Builder(this) @@ -61,6 +66,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) { .setTheme(R.style.SudGlifButton_Primary) .build() ); + mixin.getPrimaryButtonView().setFilterTouchesWhenObscured(true); } private View.OnClickListener installCaCertificate() { From d00d6783840816b231c757df76ec440b2691d176 Mon Sep 17 00:00:00 2001 From: changbetty Date: Mon, 7 Nov 2022 07:58:14 +0000 Subject: [PATCH 18/35] RESTRICT AUTOMERGE Make bluetooth switch not discoverable via SliceDeepLinkTrampoline Bug: 244423101 Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothSwitchPreferenceControllerTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothDashboardFragmentTest Test: manual test by test apk Change-Id: I13562d227e06627fac33239a9d21fd405a18d012 (cherry picked from commit 3cc8db3c58355d16956fdfbd6b2c7b030610f22f) Merged-In: I13562d227e06627fac33239a9d21fd405a18d012 --- .../BluetoothSwitchPreferenceController.java | 19 +++++- .../BluetoothDashboardFragment.java | 25 ++++++++ ...uetoothSwitchPreferenceControllerTest.java | 25 +++++++- .../BluetoothDashboardFragmentTest.java | 61 +++++++++++++++++++ 4 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/connecteddevice/BluetoothDashboardFragmentTest.java diff --git a/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java index 5b74ce707a4..d97901355f6 100644 --- a/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java +++ b/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java @@ -45,6 +45,7 @@ public class BluetoothSwitchPreferenceController private SwitchWidgetController mSwitch; private Context mContext; private FooterPreference mFooterPreference; + private boolean mIsAlwaysDiscoverable; @VisibleForTesting AlwaysDiscoverable mAlwaysDiscoverable; @@ -78,7 +79,9 @@ public BluetoothSwitchPreferenceController(Context context, RestrictionUtils res @Override public void onStart() { mBluetoothEnabler.resume(mContext); - mAlwaysDiscoverable.start(); + if (mIsAlwaysDiscoverable) { + mAlwaysDiscoverable.start(); + } if (mSwitch != null) { updateText(mSwitch.isChecked()); } @@ -87,7 +90,19 @@ public void onStart() { @Override public void onStop() { mBluetoothEnabler.pause(); - mAlwaysDiscoverable.stop(); + if (mIsAlwaysDiscoverable) { + mAlwaysDiscoverable.stop(); + } + } + + /** + * Set whether the device can be discovered. By default the value will be {@code false}. + * + * @param isAlwaysDiscoverable {@code true} if the device can be discovered, + * otherwise {@code false} + */ + public void setAlwaysDiscoverable(boolean isAlwaysDiscoverable) { + mIsAlwaysDiscoverable = isAlwaysDiscoverable; } @Override diff --git a/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java b/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java index 3e64de5a473..59de9f07952 100644 --- a/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java @@ -18,12 +18,17 @@ import android.app.settings.SettingsEnums; import android.content.Context; import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController; import com.android.settings.bluetooth.BluetoothSwitchPreferenceController; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.password.PasswordUtils; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.widget.SwitchBar; import com.android.settings.widget.SwitchBarController; @@ -40,6 +45,10 @@ public class BluetoothDashboardFragment extends DashboardFragment { private static final String TAG = "BluetoothDashboardFrag"; private static final String KEY_BLUETOOTH_SCREEN_FOOTER = "bluetooth_screen_footer"; + private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; + private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui"; + private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private FooterPreference mFooterPreference; private SwitchBar mSwitchBar; @@ -80,16 +89,32 @@ public void onAttach(Context context) { @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); + String callingAppPackageName = PasswordUtils.getCallingAppPackageName( + getActivity().getActivityToken()); + String action = getIntent() != null ? getIntent().getAction() : ""; + if (DEBUG) { + Log.d(TAG, "onActivityCreated() calling package name is : " + callingAppPackageName + + ", action : " + action); + } SettingsActivity activity = (SettingsActivity) getActivity(); mSwitchBar = activity.getSwitchBar(); mController = new BluetoothSwitchPreferenceController(activity, new SwitchBarController(mSwitchBar), mFooterPreference); + mController.setAlwaysDiscoverable(isAlwaysDiscoverable(callingAppPackageName, action)); Lifecycle lifecycle = getSettingsLifecycle(); if (lifecycle != null) { lifecycle.addObserver(mController); } } + + @VisibleForTesting + boolean isAlwaysDiscoverable(String callingAppPackageName, String action) { + return TextUtils.equals(SLICE_ACTION, action) ? false + : TextUtils.equals(SETTINGS_PACKAGE_NAME, callingAppPackageName) + || TextUtils.equals(SYSTEMUI_PACKAGE_NAME, callingAppPackageName); + } + /** * For Search. */ diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java index 3c5a91d2188..50c82d3c0d8 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java @@ -18,13 +18,14 @@ import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.content.Context; import android.provider.Settings; - import android.text.TextUtils; + import com.android.settings.R; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.utils.AnnotationSpan; @@ -109,16 +110,34 @@ public void updateText_bluetoothOnScanningOn() { } @Test - public void onStart_shouldStartAlwaysDiscoverable() { + public void onStart_setAlwaysDiscoverableAsTrue_shouldStartAlwaysDiscoverable() { + mController.setAlwaysDiscoverable(true); mController.onStart(); verify(mAlwaysDiscoverable).start(); } @Test - public void onStop_shouldStopAlwaysDiscoverable() { + public void onStart_setAlwaysDiscoverableAsFalse_shouldStartAlwaysDiscoverable() { + mController.setAlwaysDiscoverable(false); + mController.onStart(); + + verify(mAlwaysDiscoverable, never()).start(); + } + + @Test + public void onStop_setAlwaysDiscoverableAsTrue_shouldStopAlwaysDiscoverable() { + mController.setAlwaysDiscoverable(true); mController.onStop(); verify(mAlwaysDiscoverable).stop(); } + + @Test + public void onStop__setAlwaysDiscoverableAsFalse_shouldStopAlwaysDiscoverable() { + mController.setAlwaysDiscoverable(false); + mController.onStop(); + + verify(mAlwaysDiscoverable, never()).stop(); + } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/BluetoothDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/BluetoothDashboardFragmentTest.java new file mode 100644 index 00000000000..2aa2fa8e8df --- /dev/null +++ b/tests/robotests/src/com/android/settings/connecteddevice/BluetoothDashboardFragmentTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 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.settings.connecteddevice; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class BluetoothDashboardFragmentTest { + private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; + private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui"; + private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE"; + private static final String TEST_APP_NAME = "com.testapp.settings"; + private static final String TEST_ACTION = "com.testapp.settings.ACTION_START"; + + private BluetoothDashboardFragment mFragment; + + @Before + public void setUp() { + mFragment = new BluetoothDashboardFragment(); + } + + + @Test + public void isAlwaysDiscoverable_callingAppIsNotFromSystemApp_returnsFalse() { + assertThat(mFragment.isAlwaysDiscoverable(TEST_APP_NAME, TEST_ACTION)).isFalse(); + } + + @Test + public void isAlwaysDiscoverable_callingAppIsFromSettings_returnsTrue() { + assertThat(mFragment.isAlwaysDiscoverable(SETTINGS_PACKAGE_NAME, TEST_ACTION)).isTrue(); + } + + @Test + public void isAlwaysDiscoverable_callingAppIsFromSystemUI_returnsTrue() { + assertThat(mFragment.isAlwaysDiscoverable(SYSTEMUI_PACKAGE_NAME, TEST_ACTION)).isTrue(); + } + + @Test + public void isAlwaysDiscoverable_actionIsFromSlice_returnsFalse() { + assertThat(mFragment.isAlwaysDiscoverable(SYSTEMUI_PACKAGE_NAME, SLICE_ACTION)).isFalse(); + } +} From 901ce0a54302c5a950ba8d51a1ecfa9a70615760 Mon Sep 17 00:00:00 2001 From: Tsung-Mao Fang Date: Mon, 3 Jan 2022 18:25:04 +0800 Subject: [PATCH 19/35] [DO NOT MERGE] FRP bypass defense in the settings app Over the last few years, there have been a number of Factory Reset Protection bypass bugs in the SUW flow. It's unlikely to defense all points from individual apps. Therefore, we decide to block some critical pages when user doesn't complete the SUW flow. Test: Can't open the certain pages in the suw flow. Bug: 258422561 Fix: 200746457 Bug: 202975040 Fix: 213091525 Fix: 213090835 Fix: 201561699 Fix: 213090827 Fix: 213090875 Change-Id: Ia18f367109df5af7da0a5acad7702898a459d32e Merged-In: Ia18f367109df5af7da0a5acad7702898a459d32e (cherry picked from commit ff5bfb40c8b09ab477efaae6a0199911a0d703dd) Merged-In: Ia18f367109df5af7da0a5acad7702898a459d32e --- .../settings/SettingsPreferenceFragment.java | 23 +++++- .../accounts/AccountDashboardFragment.java | 5 ++ .../appinfo/AppInfoDashboardFragment.java | 5 ++ .../DevelopmentSettingsDashboardFragment.java | 5 ++ .../system/ResetDashboardFragment.java | 5 ++ .../SettingsPreferenceFragmentTest.java | 74 +++++++++++++++++++ .../AccountDashboardFragmentTest.java | 5 ++ .../appinfo/AppInfoDashboardFragmentTest.java | 5 ++ ...elopmentSettingsDashboardFragmentTest.java | 5 ++ .../system/ResetDashboardFragmentTest.java | 40 ++++++++++ 10 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 tests/robotests/src/com/android/settings/system/ResetDashboardFragmentTest.java diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java index 659ada4bd40..92df7599b54 100644 --- a/src/com/android/settings/SettingsPreferenceFragment.java +++ b/src/com/android/settings/SettingsPreferenceFragment.java @@ -55,6 +55,8 @@ import com.android.settingslib.search.Indexable; import com.android.settingslib.widget.LayoutPreference; +import com.google.android.setupcompat.util.WizardManagerHelper; + import java.util.UUID; /** @@ -63,7 +65,7 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceFragment implements DialogCreatable, HelpResourceProvider, Indexable { - private static final String TAG = "SettingsPreference"; + private static final String TAG = "SettingsPreferenceFragment"; private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted"; @@ -123,6 +125,15 @@ public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { @VisibleForTesting public boolean mPreferenceHighlighted = false; + @Override + public void onAttach(Context context) { + if (shouldSkipForInitialSUW() && !WizardManagerHelper.isDeviceProvisioned(getContext())) { + Log.w(TAG, "Skip " + getClass().getSimpleName() + " before SUW completed."); + finish(); + } + super.onAttach(context); + } + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -270,6 +281,16 @@ protected boolean isPreferenceExpanded(Preference preference) { || (mAdapter.getPreferenceAdapterPosition(preference) != RecyclerView.NO_POSITION)); } + /** + * Whether UI should be skipped in the initial SUW flow. + * + * @return {@code true} when UI should be skipped in the initial SUW flow. + * {@code false} when UI should not be skipped in the initial SUW flow. + */ + protected boolean shouldSkipForInitialSUW() { + return false; + } + protected void onDataSetChanged() { highlightPreferenceIfNeeded(); updateEmptyView(); diff --git a/src/com/android/settings/accounts/AccountDashboardFragment.java b/src/com/android/settings/accounts/AccountDashboardFragment.java index bc99d44bc7e..c413ec4979a 100644 --- a/src/com/android/settings/accounts/AccountDashboardFragment.java +++ b/src/com/android/settings/accounts/AccountDashboardFragment.java @@ -79,6 +79,11 @@ protected List createPreferenceControllers(Context return buildPreferenceControllers(context, this /* parent */, authorities); } + @Override + protected boolean shouldSkipForInitialSUW() { + return true; + } + private static List buildPreferenceControllers(Context context, SettingsPreferenceFragment parent, String[] authorities) { final List controllers = new ArrayList<>(); diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 2813bd24647..6aeec187655 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -492,6 +492,11 @@ boolean refreshUi() { return true; } + @Override + protected boolean shouldSkipForInitialSUW() { + return true; + } + private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) { stopListeningToPackageRemove(); // Create new intent to launch Uninstaller activity diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index d889e87d961..dbb869571fc 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -241,6 +241,11 @@ private void handleQsTileLongPressActionIfAny() { // Add other qstiles here } + @Override + protected boolean shouldSkipForInitialSUW() { + return true; + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/src/com/android/settings/system/ResetDashboardFragment.java b/src/com/android/settings/system/ResetDashboardFragment.java index 024db146f59..8c376c66975 100644 --- a/src/com/android/settings/system/ResetDashboardFragment.java +++ b/src/com/android/settings/system/ResetDashboardFragment.java @@ -57,6 +57,11 @@ protected List createPreferenceControllers(Context return buildPreferenceControllers(context, getSettingsLifecycle()); } + @Override + protected boolean shouldSkipForInitialSUW() { + return true; + } + private static List buildPreferenceControllers(Context context, Lifecycle lifecycle) { final List controllers = new ArrayList<>(); diff --git a/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java index cb53f69751c..648931134c5 100644 --- a/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java @@ -23,11 +23,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.os.Bundle; +import android.provider.Settings; import android.view.View; import android.widget.FrameLayout; @@ -41,6 +43,7 @@ import com.android.settings.testutils.shadow.ShadowFragment; import com.android.settings.widget.WorkOnlyCategory; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -64,7 +67,9 @@ public class SettingsPreferenceFragmentTest { private PreferenceScreen mPreferenceScreen; private Context mContext; private TestFragment mFragment; + private TestFragment2 mFragment2; private View mEmptyView; + private int mInitDeviceProvisionedValue; @Before public void setUp() { @@ -72,13 +77,24 @@ public void setUp() { FakeFeatureFactory.setupForTest(); mContext = RuntimeEnvironment.application; mFragment = spy(new TestFragment()); + mFragment2 = spy(new TestFragment2()); doReturn(mActivity).when(mFragment).getActivity(); when(mFragment.getContext()).thenReturn(mContext); + when(mFragment2.getContext()).thenReturn(mContext); mEmptyView = new View(mContext); ReflectionHelpers.setField(mFragment, "mEmptyView", mEmptyView); doReturn(ITEM_COUNT).when(mPreferenceScreen).getPreferenceCount(); + + mInitDeviceProvisionedValue = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0); + } + + @After + public void tearDown() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, mInitDeviceProvisionedValue); } @Test @@ -210,8 +226,66 @@ public void hidePinnedHeader_shouldBeInvisible() { assertThat(mFragment.mPinnedHeaderFrameLayout.getVisibility()).isEqualTo(View.INVISIBLE); } + @Test + public void onAttach_shouldNotSkipForSUWAndDeviceIsProvisioned_notCallFinish() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 1); + + mFragment.onAttach(mContext); + + verify(mFragment, never()).finish(); + } + + @Test + public void onAttach_shouldNotSkipForSUWAndDeviceIsNotProvisioned_notCallFinish() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0); + + mFragment.onAttach(mContext); + + verify(mFragment, never()).finish(); + } + + @Test + public void onAttach_shouldSkipForSUWAndDeviceIsDeviceProvisioned_notCallFinish() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 1); + + mFragment2.onAttach(mContext); + + verify(mFragment2, never()).finish(); + } + + @Test + public void onAttach_shouldSkipForSUWAndDeviceProvisioned_notCallFinish() { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0); + + mFragment2.onAttach(mContext); + + verify(mFragment2, times(1)).finish(); + } + public static class TestFragment extends SettingsPreferenceFragment { + @Override + protected boolean shouldSkipForInitialSUW() { + return false; + } + + @Override + public int getMetricsCategory() { + return 0; + } + } + + public static class TestFragment2 extends SettingsPreferenceFragment { + + @Override + protected boolean shouldSkipForInitialSUW() { + return true; + } + @Override public int getMetricsCategory() { return 0; diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java index fe57090827d..921587e837f 100644 --- a/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java @@ -114,4 +114,9 @@ public void searchIndexProvider_hasAccounts_shouldIndex() { assertThat(indexRaws).isNotEmpty(); } + + @Test + public void shouldSkipForInitialSUW_returnTrue() { + assertThat(mFragment.shouldSkipForInitialSUW()).isTrue(); + } } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java index e46cd06afe6..5292c60f869 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java @@ -384,6 +384,11 @@ public void startAppInfoFragment_includesNewAndOldArgs() { .isTrue(); } + @Test + public void shouldSkipForInitialSUW_returnTrue() { + assertThat(mFragment.shouldSkipForInitialSUW()).isTrue(); + } + @Implements(AppUtils.class) public static class ShadowAppUtils { diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java index 101297b8f89..44a7d49ac01 100644 --- a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java @@ -276,6 +276,11 @@ public void onDisableLogPersistDialogRejected_shouldCallControllerDialogRejected verify(controller).onDisableLogPersistDialogRejected(); } + @Test + public void shouldSkipForInitialSUW_returnTrue() { + assertThat(mDashboard.shouldSkipForInitialSUW()).isTrue(); + } + @Implements(EnableDevelopmentSettingWarningDialog.class) public static class ShadowEnableDevelopmentSettingWarningDialog { diff --git a/tests/robotests/src/com/android/settings/system/ResetDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/system/ResetDashboardFragmentTest.java new file mode 100644 index 00000000000..c1d47887a70 --- /dev/null +++ b/tests/robotests/src/com/android/settings/system/ResetDashboardFragmentTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 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.settings.system; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ResetDashboardFragmentTest { + + private ResetDashboardFragment mFragment; + + @Before + public void setup() { + mFragment = new ResetDashboardFragment(); + } + + @Test + public void shouldSkipForInitialSUW_returnTrue() { + assertThat(mFragment.shouldSkipForInitialSUW()).isTrue(); + } +} From 1b7e6861e3f42faf055ad5921d04d368cd70e537 Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Wed, 4 Jan 2023 09:40:38 +0000 Subject: [PATCH 20/35] Add DISALLOW_APPS_CONTROL check into uninstall app for all users Settings App info page supports a "Uninstall for all users" function when multiple users are enabled. It bypasses the restriction of DISALLOW_APPS_CONTROL which breaks the user isolation guideline. To fix this vulnerability, we should check the DISALLOW_APPS_CONTROL restriction to provide the "Uninstall for all users" function. Bug: 258653813 Test: manual & robotests Change-Id: I5d3bbcbaac439c4f7a1e6a9ade7775ff4f2f2ec6 Merged-In: I5d3bbcbaac439c4f7a1e6a9ade7775ff4f2f2ec6 (cherry picked from commit 86914bedc84474c152e4536fb3cfa2fb488030b8) Merged-In: I5d3bbcbaac439c4f7a1e6a9ade7775ff4f2f2ec6 --- .../applications/appinfo/AppInfoDashboardFragment.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) mode change 100755 => 100644 src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java old mode 100755 new mode 100644 index 6aeec187655..1c3b8cf3b4e --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -374,7 +374,13 @@ public void onPrepareOptionsMenu(Menu menu) { return; } super.onPrepareOptionsMenu(menu); - menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(shouldShowUninstallForAll(mAppEntry)); + final MenuItem uninstallAllUsersItem = menu.findItem(UNINSTALL_ALL_USERS_MENU); + uninstallAllUsersItem.setVisible( + shouldShowUninstallForAll(mAppEntry) && !mAppsControlDisallowedBySystem); + if (uninstallAllUsersItem.isVisible()) { + RestrictedLockUtilsInternal.setMenuItemAsDisabledByAdmin(getActivity(), + uninstallAllUsersItem, mAppsControlDisallowedAdmin); + } mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; final MenuItem uninstallUpdatesItem = menu.findItem(UNINSTALL_UPDATES); final boolean uninstallUpdateDisabled = getContext().getResources().getBoolean( From 8f9d4db5952a92ab6f56cb28932ec9fc461e00f9 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 28 Jul 2022 19:42:27 +0800 Subject: [PATCH 21/35] Only primary user is allowed to control secure nfc Bug: 238298970 Test: manual Merged-In: I945490ef1e62af479a732c9a260ed94bdd8bc313 Change-Id: I945490ef1e62af479a732c9a260ed94bdd8bc313 (cherry picked from commit 0e57ff90cdae3575c243d21d490e2b6384d33397) Merged-In: I945490ef1e62af479a732c9a260ed94bdd8bc313 --- src/com/android/settings/nfc/SecureNfcEnabler.java | 2 +- src/com/android/settings/nfc/SecureNfcPreferenceController.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/nfc/SecureNfcEnabler.java b/src/com/android/settings/nfc/SecureNfcEnabler.java index f31a382a571..ad5c4ab7e83 100644 --- a/src/com/android/settings/nfc/SecureNfcEnabler.java +++ b/src/com/android/settings/nfc/SecureNfcEnabler.java @@ -61,7 +61,7 @@ protected void handleNfcStateChanged(int newState) { } private boolean isToggleable() { - if (mUserManager.isGuestUser()) { + if (!mUserManager.isPrimaryUser()) { return false; } return true; diff --git a/src/com/android/settings/nfc/SecureNfcPreferenceController.java b/src/com/android/settings/nfc/SecureNfcPreferenceController.java index 575bab1ca7e..c13d74a7e07 100644 --- a/src/com/android/settings/nfc/SecureNfcPreferenceController.java +++ b/src/com/android/settings/nfc/SecureNfcPreferenceController.java @@ -103,7 +103,7 @@ public void onPause() { } private boolean isToggleable() { - if (mUserManager.isGuestUser()) { + if (!mUserManager.isPrimaryUser()) { return false; } return true; From 6db393ce8f13e3c8f353c23bccf995ee443f51e8 Mon Sep 17 00:00:00 2001 From: Valentin Iftime Date: Mon, 6 Feb 2023 12:44:03 +0100 Subject: [PATCH 22/35] [DO NO MERGE] Enforce INTERACT_ACROSS_USERS_FULL permission for NotificationAccessDetails When using EXTRA_USER_HANDLE, check for INTERACT_ACROSS_USERS_FULL permission on calling package. Bug: 259385017 Test: 1. Build a test app that creates and starts an intent to NOTIFICATION_LISTENER_DETAIL_SETTINGS while setting the intent extra android.intent.extra.user_handle to UserHandle(secondaryUserId). 2. Create and switch to a secondary user Settings > System > Multiple users > Allow multiple users > Add user > Switch to New user 3. Open Settings > Notifications > Device & app notifications and choose an app from the list (uses android.permission.BIND_NOTIFICATION_LISTENER_SERVICE). Enable Device & app notifications for selected app and disable all attributed permissions. 4. Switch back to the Owner user. 5. Get the userId of the secondary user: adb shell pm list users. 6. Open the test app and enter the userId for the secondary user and the component name that uses android.permission.BIND_NOTIFICATION_LISTENER_SERVICE. 8. In the settings window that open, enable all 4 sub-options. 9. Switch to the secondary user and note that the all sub-options for the app are disabled. Change-Id: I875b9f2fc32c252acdcf8374a14067836e0f1ac6 Merged-In: I875b9f2fc32c252acdcf8374a14067836e0f1ac6 (cherry picked from commit on googleplex-android-review.googlesource.com host: 5fb0705664449e2a62c6219a8a417749620bb937) Merged-In: I875b9f2fc32c252acdcf8374a14067836e0f1ac6 --- .../NotificationAccessDetails.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java b/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java index 58a6d7f5956..6a4c22efc7a 100644 --- a/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java +++ b/src/com/android/settings/applications/specialaccess/notificationaccess/NotificationAccessDetails.java @@ -16,6 +16,9 @@ package com.android.settings.applications.specialaccess.notificationaccess; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + +import android.Manifest; import android.app.Activity; import android.app.NotificationManager; import android.app.settings.SettingsEnums; @@ -30,6 +33,7 @@ import android.os.UserManager; import android.provider.Settings; import android.service.notification.NotificationListenerService; +import android.text.TextUtils; import android.util.IconDrawableFactory; import android.util.Log; import android.util.Slog; @@ -42,6 +46,7 @@ import com.android.settings.R; import com.android.settings.applications.AppInfoBase; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.password.PasswordUtils; import com.android.settings.widget.EntityHeaderController; import com.android.settingslib.applications.AppUtils; @@ -139,6 +144,41 @@ protected AlertDialog createDialog(int id, int errorCode) { return null; } + @Override + protected String retrieveAppEntry() { + final Bundle args = getArguments(); + final Intent intent = (args == null) ? + getIntent() : (Intent) args.getParcelable("intent"); + + if (intent != null && intent.hasExtra(Intent.EXTRA_USER_HANDLE)) { + if (!hasInteractAcrossUsersPermission()) { + finish(); + } + } + + return super.retrieveAppEntry(); + } + + private boolean hasInteractAcrossUsersPermission() { + final String callingPackageName = PasswordUtils.getCallingAppPackageName( + getActivity().getActivityToken()); + + if (TextUtils.isEmpty(callingPackageName)) { + Log.w(TAG, "Not able to get calling package name for permission check"); + return false; + } + + if (getContext().getPackageManager().checkPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingPackageName) + != PERMISSION_GRANTED) { + Log.w(TAG, "Package " + callingPackageName + " does not have required permission " + + Manifest.permission.INTERACT_ACROSS_USERS_FULL); + return false; + } + + return true; + } + public void updatePreference(SwitchPreference preference) { final CharSequence label = mPackageInfo.applicationInfo.loadLabel(mPm); preference.setChecked(isServiceEnabled(mComponentName)); From e6fe218cf5f07c56ee55130c580032d9110b6990 Mon Sep 17 00:00:00 2001 From: Hugh Chen Date: Thu, 28 Oct 2021 06:21:37 +0000 Subject: [PATCH 23/35] RESTRICT AUTOMERGE Fix make Bluetooth discoverable without additional permission - Only enable device can be discoverable when the user launch "Connected Devices settings" through settings and systemui Bug: 194695497 Test: make -j42 RunSettingsRoboTests and use test apk to manually test to verify the device is not discoversable when open "Connected settings" through test apk. Change-Id: Ia04ab759b737acf30b782f5c5831dd59f25fb257 (cherry picked from commit d3abbb9821dca627c49b15185109150c79597549) (cherry picked from commit 528d40e4d12bc82bfc48b4c886c177c7b02561a4) Merged-In:Ia04ab759b737acf30b782f5c5831dd59f25fb257 --- .../ConnectedDeviceDashboardFragment.java | 14 ++++++++++ ...iscoverableFooterPreferenceController.java | 19 ++++++++++++-- ...verableFooterPreferenceControllerTest.java | 26 +++++++++++++++++-- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java index 105f4ac1712..22fac305112 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java @@ -53,12 +53,15 @@ import android.net.Uri; import android.provider.DeviceConfig; import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settings.core.SettingsUIDeviceConfig; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.password.PasswordUtils; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.slices.SlicePreferenceController; import com.android.settingslib.search.SearchIndexable; @@ -67,6 +70,9 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { private static final String TAG = "ConnectedDeviceFrag"; + private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; + private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @VisibleForTesting static final String KEY_CONNECTED_DEVICES = "connected_device_list"; @@ -109,6 +115,11 @@ public void onAttach(Context context) { super.onAttach(context); final boolean nearbyEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI, SettingsUIDeviceConfig.BT_NEAR_BY_SUGGESTION_ENABLED, true); + String callingAppPackageName = PasswordUtils.getCallingAppPackageName( + getActivity().getActivityToken()); + if (DEBUG) { + Log.d(TAG, "onAttach() calling package name is : " + callingAppPackageName); + } use(AvailableMediaDeviceGroupController.class).init(this); use(ConnectedDeviceGroupController.class).init(this); use(SavedTwsDeviceGroupController.class).init(this); @@ -116,6 +127,9 @@ public void onAttach(Context context) { use(SlicePreferenceController.class).setSliceUri(nearbyEnabled ? Uri.parse(getString(R.string.config_nearby_devices_slice_uri)) : null); + use(DiscoverableFooterPreferenceController.class).setAlwaysDiscoverable( + TextUtils.equals(SETTINGS_PACKAGE_NAME, callingAppPackageName) + || TextUtils.equals(SYSTEMUI_PACKAGE_NAME, callingAppPackageName)); } /** diff --git a/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java b/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java index 91368bf2a81..5df31bc63a4 100644 --- a/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java +++ b/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceController.java @@ -52,6 +52,7 @@ public class DiscoverableFooterPreferenceController extends BasePreferenceContro private BluetoothAdapter mBluetoothAdapter; private AlwaysDiscoverable mAlwaysDiscoverable; private FooterPreference mPreference; + private boolean mIsAlwaysDiscoverable; public DiscoverableFooterPreferenceController(Context context, String key) { super(context, key); @@ -84,7 +85,9 @@ public void onStart() { } mContext.registerReceiver(mBluetoothChangedReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); - mAlwaysDiscoverable.start(); + if (mIsAlwaysDiscoverable) { + mAlwaysDiscoverable.start(); + } updateFooterPreferenceTitle(mBluetoothAdapter.getState()); } @@ -94,7 +97,19 @@ public void onStop() { return; } mContext.unregisterReceiver(mBluetoothChangedReceiver); - mAlwaysDiscoverable.stop(); + if (mIsAlwaysDiscoverable) { + mAlwaysDiscoverable.stop(); + } + } + + /** + * Set whether the device can be discovered. By default the value will be {@code false}. + * + * @param isAlwaysDiscoverable {@code true} if the device can be discovered, + * otherwise {@code false} + */ + public void setAlwaysDiscoverable(boolean isAlwaysDiscoverable) { + mIsAlwaysDiscoverable = isAlwaysDiscoverable; } private void updateFooterPreferenceTitle(int bluetoothState) { diff --git a/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java index 065b924138c..6510f198de1 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/DiscoverableFooterPreferenceControllerTest.java @@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -104,7 +105,8 @@ public void getAvailabilityStatus_BluetoothFeature_returnAvailableUnsearchable() } @Test - public void onStart_shouldRegisterBluetoothChanged() { + public void onStart_setAlwaysDiscoverableAsTrue_shouldRegisterBluetoothChanged() { + mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(true); mDiscoverableFooterPreferenceController.onStart(); assertThat(getRegisteredBroadcastReceivers()).contains(mBluetoothChangedReceiver); @@ -112,7 +114,8 @@ public void onStart_shouldRegisterBluetoothChanged() { } @Test - public void onStop_shouldUnregisterBluetoothChanged() { + public void onStop_setAlwaysDiscoverableAsTrue_shouldUnregisterBluetoothChanged() { + mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(true); mDiscoverableFooterPreferenceController.onStart(); mDiscoverableFooterPreferenceController.onStop(); @@ -120,6 +123,25 @@ public void onStop_shouldUnregisterBluetoothChanged() { verify(mAlwaysDiscoverable).stop(); } + @Test + public void onStart_setAlwaysDiscoverableAsFalse_shouldNotRegisterBluetoothChanged() { + mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(false); + mDiscoverableFooterPreferenceController.onStart(); + + assertThat(getRegisteredBroadcastReceivers()).contains(mBluetoothChangedReceiver); + verify(mAlwaysDiscoverable, never()).start(); + } + + @Test + public void onStop_setAlwaysDiscoverableAsFalse_shouldNotUnregisterBluetoothChanged() { + mDiscoverableFooterPreferenceController.setAlwaysDiscoverable(false); + mDiscoverableFooterPreferenceController.onStart(); + mDiscoverableFooterPreferenceController.onStop(); + + assertThat(getRegisteredBroadcastReceivers()).doesNotContain(mBluetoothChangedReceiver); + verify(mAlwaysDiscoverable, never()).stop(); + } + @Test public void onBluetoothStateChanged_bluetoothOn_updateTitle() { BluetoothAdapter.getDefaultAdapter().setName(DEVICE_NAME); From 1143c0bad12c56f7c2a95a537db3bb61a106f6d2 Mon Sep 17 00:00:00 2001 From: Hugh Chen Date: Tue, 10 May 2022 09:39:12 +0000 Subject: [PATCH 24/35] RESTRICT AUTOMERGE Make bluetooth not discoverable via SliceDeepLinkTrampoline - Don't let device be discovered when the user launch "Connected Devices settings" through SliceDeepLinkTrampoline. Bug: 228450811 Test: make -j42 RunSettingsRoboTests and use test apk to manually test to verify the device is not discoversable when open "Connected settings" through test apk. Change-Id: I5490b58675b1fd9fc36305766867f65caa6ccb6c (cherry picked from commit 205752dcf2062eb3deeb7f3b7d1eb8af7d8b2634) (cherry picked from commit c44b6fed73668dcdee066ea125e93e48dc31d3ee) Merged-In: I5490b58675b1fd9fc36305766867f65caa6ccb6c --- .../ConnectedDeviceDashboardFragment.java | 17 +++++++++--- .../ConnectedDeviceDashboardFragmentTest.java | 27 +++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java index 22fac305112..63845c355ea 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java @@ -73,6 +73,7 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE"; @VisibleForTesting static final String KEY_CONNECTED_DEVICES = "connected_device_list"; @@ -117,8 +118,10 @@ public void onAttach(Context context) { SettingsUIDeviceConfig.BT_NEAR_BY_SUGGESTION_ENABLED, true); String callingAppPackageName = PasswordUtils.getCallingAppPackageName( getActivity().getActivityToken()); + String action = getIntent() != null ? getIntent().getAction() : ""; if (DEBUG) { - Log.d(TAG, "onAttach() calling package name is : " + callingAppPackageName); + Log.d(TAG, "onAttach() calling package name is : " + callingAppPackageName + + ", action : " + action); } use(AvailableMediaDeviceGroupController.class).init(this); use(ConnectedDeviceGroupController.class).init(this); @@ -127,9 +130,15 @@ public void onAttach(Context context) { use(SlicePreferenceController.class).setSliceUri(nearbyEnabled ? Uri.parse(getString(R.string.config_nearby_devices_slice_uri)) : null); - use(DiscoverableFooterPreferenceController.class).setAlwaysDiscoverable( - TextUtils.equals(SETTINGS_PACKAGE_NAME, callingAppPackageName) - || TextUtils.equals(SYSTEMUI_PACKAGE_NAME, callingAppPackageName)); + use(DiscoverableFooterPreferenceController.class) + .setAlwaysDiscoverable(isAlwaysDiscoverable(callingAppPackageName, action)); + } + + @VisibleForTesting + boolean isAlwaysDiscoverable(String callingAppPackageName, String action) { + return TextUtils.equals(SLICE_ACTION, action) ? false + : TextUtils.equals(SETTINGS_PACKAGE_NAME, callingAppPackageName) + || TextUtils.equals(SYSTEMUI_PACKAGE_NAME, callingAppPackageName); } /** diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java index c4f15874503..091b9445c03 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java @@ -53,16 +53,23 @@ public class ConnectedDeviceDashboardFragmentTest { private static final String KEY_NEARBY_DEVICES = "bt_nearby_slice"; private static final String KEY_DISCOVERABLE_FOOTER = "discoverable_footer"; private static final String KEY_SEE_ALL = "previously_connected_devices_see_all"; + private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; + private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui"; + private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE"; + private static final String TEST_APP_NAME = "com.testapp.settings"; + private static final String TEST_ACTION = "com.testapp.settings.ACTION_START"; @Mock private PackageManager mPackageManager; private Context mContext; + private ConnectedDeviceDashboardFragment mFragment; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); + mFragment = new ConnectedDeviceDashboardFragment(); doReturn(mPackageManager).when(mContext).getPackageManager(); doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); } @@ -86,6 +93,26 @@ public void nonIndexableKeys_existInXmlLayout() { KEY_NEARBY_DEVICES, KEY_DISCOVERABLE_FOOTER, KEY_SEE_ALL); } + @Test + public void isAlwaysDiscoverable_callingAppIsNotFromSystemApp_returnsFalse() { + assertThat(mFragment.isAlwaysDiscoverable(TEST_APP_NAME, TEST_ACTION)).isFalse(); + } + + @Test + public void isAlwaysDiscoverable_callingAppIsFromSettings_returnsTrue() { + assertThat(mFragment.isAlwaysDiscoverable(SETTINGS_PACKAGE_NAME, TEST_ACTION)).isTrue(); + } + + @Test + public void isAlwaysDiscoverable_callingAppIsFromSystemUI_returnsTrue() { + assertThat(mFragment.isAlwaysDiscoverable(SYSTEMUI_PACKAGE_NAME, TEST_ACTION)).isTrue(); + } + + @Test + public void isAlwaysDiscoverable_actionIsFromSlice_returnsFalse() { + assertThat(mFragment.isAlwaysDiscoverable(SYSTEMUI_PACKAGE_NAME, SLICE_ACTION)).isFalse(); + } + @Test public void getPreferenceControllers_containSlicePrefController() { final List controllers = From eee68f931765dffb5320c1be64c8afae5e9cc5df Mon Sep 17 00:00:00 2001 From: Edgar Wang Date: Thu, 6 Jan 2022 20:53:48 +0800 Subject: [PATCH 25/35] Fix bypass CALL_PRIVILEGED permission in AppRestrictionsFragment In onReceive of AppRestrictionsFragment.java, there is a possible way to start a phone call without permissions due to a confused deputy. This could lead to local escalation of privilege with no additional execution privileges needed. We should not allow the restrictionsIntent to startActivity simply because it resolves to multiple activities. Instead, we should call resolveActivity and check the result's package name is same as current package name, then it is safe to startActivity. Bug: 200688991 Test: manual verify Change-Id: Iaa2d3a9497c3266babe0789961befc9776a4db7a Merged-In: Iaa2d3a9497c3266babe0789961befc9776a4db7a (cherry picked from commit 359512cd9553c940af3c9045b856647b7529731a) (cherry picked from commit dc44d01a16461027ace52eb30faa9281e102ed3a) Merged-In:Iaa2d3a9497c3266babe0789961befc9776a4db7a --- .../users/AppRestrictionsFragment.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java index 9f6a2b656de..1d3d9eb13b6 100644 --- a/src/com/android/settings/users/AppRestrictionsFragment.java +++ b/src/com/android/settings/users/AppRestrictionsFragment.java @@ -18,6 +18,7 @@ import android.app.Activity; import android.app.settings.SettingsEnums; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -37,6 +38,7 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; +import android.util.EventLog; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; @@ -641,7 +643,15 @@ public void onReceive(Context context, Intent intent) { } else if (restrictionsIntent != null) { preference.setRestrictions(restrictions); if (invokeIfCustom && AppRestrictionsFragment.this.isResumed()) { - assertSafeToStartCustomActivity(restrictionsIntent); + try { + assertSafeToStartCustomActivity(restrictionsIntent); + } catch (ActivityNotFoundException | SecurityException e) { + // return without startActivity + Log.e(TAG, "Cannot start restrictionsIntent " + e); + EventLog.writeEvent(0x534e4554, "200688991", -1 /* UID */, ""); + return; + } + int requestCode = generateCustomActivityRequestCode( RestrictionsResultReceiver.this.preference); AppRestrictionsFragment.this.startActivityForResult( @@ -655,14 +665,14 @@ private void assertSafeToStartCustomActivity(Intent intent) { if (intent.getPackage() != null && intent.getPackage().equals(packageName)) { return; } - // Activity can be started if intent resolves to multiple activities - List resolveInfos = AppRestrictionsFragment.this.mPackageManager - .queryIntentActivities(intent, 0 /* no flags */); - if (resolveInfos.size() != 1) { - return; + ResolveInfo resolveInfo = mPackageManager.resolveActivity( + intent, PackageManager.MATCH_DEFAULT_ONLY); + + if (resolveInfo == null) { + throw new ActivityNotFoundException("No result for resolving " + intent); } // Prevent potential privilege escalation - ActivityInfo activityInfo = resolveInfos.get(0).activityInfo; + ActivityInfo activityInfo = resolveInfo.activityInfo; if (!packageName.equals(activityInfo.packageName)) { throw new SecurityException("Application " + packageName + " is not allowed to start activity " + intent); From ee3da90e34a781ccc50da1a213e06f126ba00979 Mon Sep 17 00:00:00 2001 From: Edgar Wang Date: Wed, 6 Apr 2022 17:30:27 +0800 Subject: [PATCH 26/35] Fix LaunchAnyWhere in AppRestrictionsFragment If the intent's package equals to the app's package, this intent will be allowed to startActivityForResult. But this check is unsafe, because if the component of this intent is set, the package field will just be ignored. So if we set the component to any activity we like and set package to the app's package, it will pass the assertSafeToStartCustomActivity check and now we can launch anywhere. Bug: 223578534 Test: robotest and manual verify Change-Id: I40496105bae313fe5cff2a36dfe329c1e2b5bbe4 (cherry picked from commit 90e095dbe372f29823ad4788c0cc2d781ae3bb24) (cherry picked from commit aeb36e5c282ac9cdfb34e87f68b8d8a5067d644d) Merged-In: I40496105bae313fe5cff2a36dfe329c1e2b5bbe4 --- src/com/android/settings/users/AppRestrictionsFragment.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java index 1d3d9eb13b6..51624ca63b4 100644 --- a/src/com/android/settings/users/AppRestrictionsFragment.java +++ b/src/com/android/settings/users/AppRestrictionsFragment.java @@ -661,10 +661,7 @@ public void onReceive(Context context, Intent intent) { } private void assertSafeToStartCustomActivity(Intent intent) { - // Activity can be started if it belongs to the same app - if (intent.getPackage() != null && intent.getPackage().equals(packageName)) { - return; - } + EventLog.writeEvent(0x534e4554, "223578534", -1 /* UID */, ""); ResolveInfo resolveInfo = mPackageManager.resolveActivity( intent, PackageManager.MATCH_DEFAULT_ONLY); From 779cb7193798697909a4d0730f36f91ab0ef7015 Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Thu, 18 Nov 2021 10:27:34 +0800 Subject: [PATCH 27/35] [Settings] Move display of VPN version into summary text Move the display of version text within VPN into summary part of the display, and limit the height of summary area. Bug: 205460459 Test: install apk from b/205460459#comment3 and verify (cherry picked from commit 144f295d7aa66bae8556ba030553a49615eab0b2) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:dddd74a491a206178feb10d5ef983d5cd273504d) Merged-In: I666b9db356feeebf04e3be688897c2d9110a5275 Change-Id: I666b9db356feeebf04e3be688897c2d9110a5275 --- res/values/strings.xml | 2 +- res/values/styles.xml | 10 ++++ res/xml/vpn_app_management.xml | 14 ++++- .../settings/vpn2/AppManagementFragment.java | 51 +++++++++++++++++-- 4 files changed, 71 insertions(+), 6 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index dbb6029f5c7..34c0a549ec3 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6807,7 +6807,7 @@ Disconnect - Version %s + Version Forget VPN diff --git a/res/values/styles.xml b/res/values/styles.xml index c59887839be..d5c8e2eea8b 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -235,6 +235,16 @@ @android:style/TextAppearance.DeviceDefault.Small + + + +