From 858e6ff3d5136601ed9bc75b48c9d2df26c5b970 Mon Sep 17 00:00:00 2001 From: Hugh Chen Date: Thu, 14 Apr 2022 10:34:04 +0000 Subject: [PATCH 1/6] RESTRICT AUTOMERGE Implement advanced vpn ui in vpn settings Bug: 220684478 Test: atest -c VpnSettingsTest Change-Id: If89de16d02cb8b1f387b8f388f8fcf82ad39066b --- res/values/config.xml | 3 + res/xml/vpn_settings2.xml | 5 + .../settings/overlay/FeatureFactory.java | 6 + .../settings/overlay/FeatureFactoryImpl.java | 11 ++ .../vpn2/AdvancedVpnFeatureProvider.java | 45 ++++++ .../vpn2/AdvancedVpnFeatureProviderImpl.java | 44 ++++++ .../android/settings/vpn2/VpnSettings.java | 85 +++++++++- .../testutils/FakeFeatureFactory.java | 8 + .../testutils/FakeFeatureFactory.java | 8 + .../settings/vpn2/VpnSettingsTest.java | 146 ++++++++++++++++++ 10 files changed, 353 insertions(+), 8 deletions(-) create mode 100644 src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java create mode 100644 src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java create mode 100644 tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java diff --git a/res/values/config.xml b/res/values/config.xml index c7ef595e3ae..fb1859c85b1 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -617,4 +617,7 @@ false + + + false diff --git a/res/xml/vpn_settings2.xml b/res/xml/vpn_settings2.xml index 08075a6c8b1..0d374c75518 100644 --- a/res/xml/vpn_settings2.xml +++ b/res/xml/vpn_settings2.xml @@ -16,4 +16,9 @@ + + + diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java index aff7197e274..c59b3854599 100644 --- a/src/com/android/settings/overlay/FeatureFactory.java +++ b/src/com/android/settings/overlay/FeatureFactory.java @@ -45,6 +45,7 @@ import com.android.settings.security.SecurityFeatureProvider; import com.android.settings.security.SecuritySettingsFeatureProvider; import com.android.settings.slices.SlicesFeatureProvider; import com.android.settings.users.UserFeatureProvider; +import com.android.settings.vpn2.AdvancedVpnFeatureProvider; import com.android.settings.wifi.WifiTrackerLibProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -177,6 +178,11 @@ public abstract class FeatureFactory { */ public abstract AccessibilityMetricsFeatureProvider getAccessibilityMetricsFeatureProvider(); + /** + * Retrieves implementation for advanced vpn feature. + */ + public abstract AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider(); + public static final class FactoryNotFoundException extends RuntimeException { public FactoryNotFoundException(Throwable throwable) { super("Unable to create factory. Did you misconfigure Proguard?", throwable); diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java index 89f74de8233..593b8666c02 100644 --- a/src/com/android/settings/overlay/FeatureFactoryImpl.java +++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java @@ -71,6 +71,8 @@ import com.android.settings.slices.SlicesFeatureProvider; import com.android.settings.slices.SlicesFeatureProviderImpl; import com.android.settings.users.UserFeatureProvider; import com.android.settings.users.UserFeatureProviderImpl; +import com.android.settings.vpn2.AdvancedVpnFeatureProvider; +import com.android.settings.vpn2.AdvancedVpnFeatureProviderImpl; import com.android.settings.wifi.WifiTrackerLibProvider; import com.android.settings.wifi.WifiTrackerLibProviderImpl; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -106,6 +108,7 @@ public class FeatureFactoryImpl extends FeatureFactory { private SecuritySettingsFeatureProvider mSecuritySettingsFeatureProvider; private AccessibilitySearchFeatureProvider mAccessibilitySearchFeatureProvider; private AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider; + private AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider; @Override public SupportFeatureProvider getSupportFeatureProvider(Context context) { @@ -334,4 +337,12 @@ public class FeatureFactoryImpl extends FeatureFactory { } return mAccessibilityMetricsFeatureProvider; } + + @Override + public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() { + if (mAdvancedVpnFeatureProvider == null) { + mAdvancedVpnFeatureProvider = new AdvancedVpnFeatureProviderImpl(); + } + return mAdvancedVpnFeatureProvider; + } } diff --git a/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java b/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java new file mode 100644 index 00000000000..c5702a26378 --- /dev/null +++ b/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java @@ -0,0 +1,45 @@ +/* + * 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.vpn2; + +import android.content.Context; + +/** + * Feature Provider used in vpn usage + */ +public interface AdvancedVpnFeatureProvider { + + /** + * Returns package name of advanced vpn. + */ + String getAdvancedVpnPackageName(); + + /** + * Returns {@code true} advanced vpn is supported. + */ + boolean isAdvancedVpnSupported(Context context); + + /** + * Returns the title of advanced vpn preference group. + */ + String getAdvancedVpnPreferenceGroupTitle(Context context); + + /** + * Returns the title of vpn preference group. + */ + String getVpnPreferenceGroupTitle(Context context); +} diff --git a/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java b/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java new file mode 100644 index 00000000000..0bfaf646ba7 --- /dev/null +++ b/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java @@ -0,0 +1,44 @@ +/* + * 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.vpn2; + +import android.content.Context; + +/** + * Feature provider implementation for advanced vpn. + */ +public class AdvancedVpnFeatureProviderImpl implements AdvancedVpnFeatureProvider { + @Override + public String getAdvancedVpnPackageName() { + return null; + } + + @Override + public boolean isAdvancedVpnSupported(Context context) { + return false; + } + + @Override + public String getAdvancedVpnPreferenceGroupTitle(Context context) { + return null; + } + + @Override + public String getVpnPreferenceGroupTitle(Context context) { + return null; + } +} diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java index e89785fe535..5712b3fd1cd 100644 --- a/src/com/android/settings/vpn2/VpnSettings.java +++ b/src/com/android/settings/vpn2/VpnSettings.java @@ -42,6 +42,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.security.Credentials; import android.security.LegacyVpnProfileStore; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -52,6 +53,7 @@ import android.view.MenuItem; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceGroup; +import androidx.preference.PreferenceScreen; import com.android.internal.annotations.GuardedBy; import com.android.internal.net.LegacyVpnInfo; @@ -59,6 +61,7 @@ import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.settings.R; import com.android.settings.RestrictedSettingsFragment; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.GearPreference; import com.android.settings.widget.GearPreference.OnGearClickListener; import com.android.settingslib.RestrictedLockUtilsInternal; @@ -79,9 +82,12 @@ import java.util.Set; public class VpnSettings extends RestrictedSettingsFragment implements Handler.Callback, Preference.OnPreferenceClickListener { private static final String LOG_TAG = "VpnSettings"; + private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG); private static final int RESCAN_MESSAGE = 0; private static final int RESCAN_INTERVAL_MS = 1000; + private static final String ADVANCED_VPN_GROUP_KEY = "advanced_vpn_group"; + private static final String VPN_GROUP_KEY = "vpn_group"; private static final NetworkRequest VPN_REQUEST = new NetworkRequest.Builder() .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) @@ -102,6 +108,9 @@ public class VpnSettings extends RestrictedSettingsFragment implements private LegacyVpnInfo mConnectedLegacyVpn; private boolean mUnavailable; + private AdvancedVpnFeatureProvider mFeatureProvider; + private PreferenceScreen mPreferenceScreen; + private boolean mIsAdvancedVpnSupported; public VpnSettings() { super(UserManager.DISALLOW_CONFIG_VPN); @@ -119,11 +128,14 @@ public class VpnSettings extends RestrictedSettingsFragment implements mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); mVpnManager = (VpnManager) getSystemService(Context.VPN_MANAGEMENT_SERVICE); + mFeatureProvider = FeatureFactory.getFactory(getContext()).getAdvancedVpnFeatureProvider(); + mIsAdvancedVpnSupported = mFeatureProvider.isAdvancedVpnSupported(getContext()); mUnavailable = isUiRestricted(); setHasOptionsMenu(!mUnavailable); addPreferencesFromResource(R.xml.vpn_settings2); + mPreferenceScreen = getPreferenceScreen(); } @Override @@ -265,7 +277,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements private final VpnSettings mSettings; - public UpdatePreferences(VpnSettings settings) { + UpdatePreferences(VpnSettings settings) { mSettings = settings; } @@ -332,7 +344,14 @@ public class VpnSettings extends RestrictedSettingsFragment implements } // Trim out deleted VPN preferences - mSettings.setShownPreferences(updates); + if (DEBUG) { + Log.d(LOG_TAG, "isAdvancedVpnSupported() : " + mSettings.mIsAdvancedVpnSupported); + } + if (mSettings.mIsAdvancedVpnSupported) { + mSettings.setShownAdvancedPreferences(updates); + } else { + mSettings.setShownPreferences(updates); + } } } @@ -343,12 +362,61 @@ public class VpnSettings extends RestrictedSettingsFragment implements @VisibleForTesting @UiThread public void setShownPreferences(final Collection updates) { + retainAllPreference(updates); + + final PreferenceGroup vpnGroup = getPreferenceScreen(); + updatePreferenceGroup(vpnGroup, updates); + + // Show all new preferences on the screen + for (Preference pref : updates) { + vpnGroup.addPreference(pref); + } + } + + @VisibleForTesting @UiThread + void setShownAdvancedPreferences(final Collection updates) { + retainAllPreference(updates); + + PreferenceGroup advancedVpnGroup = mPreferenceScreen.findPreference(ADVANCED_VPN_GROUP_KEY); + PreferenceGroup vpnGroup = mPreferenceScreen.findPreference(VPN_GROUP_KEY); + advancedVpnGroup.setTitle( + mFeatureProvider.getAdvancedVpnPreferenceGroupTitle(getContext())); + vpnGroup.setTitle(mFeatureProvider.getVpnPreferenceGroupTitle(getContext())); + updatePreferenceGroup(advancedVpnGroup, updates); + updatePreferenceGroup(vpnGroup, updates); + + // Show all new preferences on the screen + for (Preference pref : updates) { + String packageName = ""; + if (pref instanceof LegacyVpnPreference) { + LegacyVpnPreference legacyPref = (LegacyVpnPreference) pref; + packageName = legacyPref.getPackageName(); + } else if (pref instanceof AppPreference) { + AppPreference appPref = (AppPreference) pref; + packageName = appPref.getPackageName(); + } + if (DEBUG) { + Log.d(LOG_TAG, "setShownAdvancedPreferences() package name : " + packageName); + } + if (TextUtils.equals(packageName, mFeatureProvider.getAdvancedVpnPackageName())) { + advancedVpnGroup.addPreference(pref); + } else { + vpnGroup.addPreference(pref); + } + } + + advancedVpnGroup.setVisible(advancedVpnGroup.getPreferenceCount() > 0); + vpnGroup.setVisible(vpnGroup.getPreferenceCount() > 0); + } + + private void retainAllPreference(Collection updates) { mLegacyVpnPreferences.values().retainAll(updates); mAppPreferences.values().retainAll(updates); + } + private void updatePreferenceGroup(PreferenceGroup vpnGroup, Collection updates) { // Change {@param updates} in-place to only contain new preferences that were not already // added to the preference screen. - final PreferenceGroup vpnGroup = getPreferenceScreen(); for (int i = vpnGroup.getPreferenceCount() - 1; i >= 0; i--) { Preference p = vpnGroup.getPreference(i); if (updates.contains(p)) { @@ -357,11 +425,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements vpnGroup.removePreference(p); } } - - // Show any new preferences on the screen - for (Preference pref : updates) { - vpnGroup.addPreference(pref); - } } @Override @@ -562,4 +625,10 @@ public class VpnSettings extends RestrictedSettingsFragment implements } return result; } + + @VisibleForTesting + void init(PreferenceScreen preferenceScreen, AdvancedVpnFeatureProvider featureProvider) { + mPreferenceScreen = preferenceScreen; + mFeatureProvider = featureProvider; + } } diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java index 518aee9d23a..2f248320ae5 100644 --- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java +++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java @@ -47,6 +47,7 @@ import com.android.settings.security.SecurityFeatureProvider; import com.android.settings.security.SecuritySettingsFeatureProvider; import com.android.settings.slices.SlicesFeatureProvider; import com.android.settings.users.UserFeatureProvider; +import com.android.settings.vpn2.AdvancedVpnFeatureProvider; import com.android.settings.wifi.WifiTrackerLibProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -87,6 +88,7 @@ public class FakeFeatureFactory extends FeatureFactory { public SecuritySettingsFeatureProvider securitySettingsFeatureProvider; public AccessibilitySearchFeatureProvider mAccessibilitySearchFeatureProvider; public AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider; + public AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider; /** * Call this in {@code @Before} method of the test class to use fake factory. @@ -136,6 +138,7 @@ public class FakeFeatureFactory extends FeatureFactory { securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class); mAccessibilitySearchFeatureProvider = mock(AccessibilitySearchFeatureProvider.class); mAccessibilityMetricsFeatureProvider = mock(AccessibilityMetricsFeatureProvider.class); + mAdvancedVpnFeatureProvider = mock(AdvancedVpnFeatureProvider.class); } @Override @@ -272,4 +275,9 @@ public class FakeFeatureFactory extends FeatureFactory { public AccessibilityMetricsFeatureProvider getAccessibilityMetricsFeatureProvider() { return mAccessibilityMetricsFeatureProvider; } + + @Override + public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() { + return mAdvancedVpnFeatureProvider; + } } diff --git a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java index 717de791c55..f565075736d 100644 --- a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java +++ b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java @@ -45,6 +45,7 @@ import com.android.settings.security.SecurityFeatureProvider; import com.android.settings.security.SecuritySettingsFeatureProvider; import com.android.settings.slices.SlicesFeatureProvider; import com.android.settings.users.UserFeatureProvider; +import com.android.settings.vpn2.AdvancedVpnFeatureProvider; import com.android.settings.wifi.WifiTrackerLibProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -82,6 +83,7 @@ public class FakeFeatureFactory extends FeatureFactory { public SecuritySettingsFeatureProvider securitySettingsFeatureProvider; public AccessibilitySearchFeatureProvider mAccessibilitySearchFeatureProvider; public AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider; + public AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider; /** * Call this in {@code @Before} method of the test class to use fake factory. @@ -122,6 +124,7 @@ public class FakeFeatureFactory extends FeatureFactory { securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class); mAccessibilitySearchFeatureProvider = mock(AccessibilitySearchFeatureProvider.class); mAccessibilityMetricsFeatureProvider = mock(AccessibilityMetricsFeatureProvider.class); + mAdvancedVpnFeatureProvider = mock(AdvancedVpnFeatureProvider.class); } @Override @@ -258,4 +261,9 @@ public class FakeFeatureFactory extends FeatureFactory { public AccessibilityMetricsFeatureProvider getAccessibilityMetricsFeatureProvider() { return mAccessibilityMetricsFeatureProvider; } + + @Override + public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() { + return mAdvancedVpnFeatureProvider; + } } diff --git a/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java b/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java new file mode 100644 index 00000000000..1b3b49c63c3 --- /dev/null +++ b/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java @@ -0,0 +1,146 @@ +/* + * 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.vpn2; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Looper; +import android.os.UserHandle; +import android.util.ArraySet; + +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceGroup; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.test.annotation.UiThreadTest; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.settings.testutils.FakeFeatureFactory; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +public class VpnSettingsTest { + private static final String ADVANCED_VPN_GROUP_KEY = "advanced_vpn_group"; + private static final String VPN_GROUP_KEY = "vpn_group"; + private static final String ADVANCED_VPN_GROUP_TITLE = "advanced_vpn_group_title"; + private static final String VPN_GROUP_TITLE = "vpn_group_title"; + private static final String FAKE_PACKAGE_NAME = "com.fake.package.name"; + private static final String ADVANCED_VPN_GROUP_PACKAGE_NAME = "com.advanced.package.name"; + private static final int USER_ID_1 = UserHandle.USER_NULL; + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + private VpnSettings mVpnSettings; + private Context mContext; + private PreferenceManager mPreferenceManager; + private PreferenceScreen mPreferenceScreen; + private PreferenceGroup mAdvancedVpnGroup; + private PreferenceGroup mVpnGroup; + private FakeFeatureFactory mFakeFeatureFactory; + + @Before + @UiThreadTest + public void setUp() throws PackageManager.NameNotFoundException { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + mVpnSettings = spy(new VpnSettings()); + mContext = spy(ApplicationProvider.getApplicationContext()); + mAdvancedVpnGroup = spy(new PreferenceCategory(mContext)); + mVpnGroup = spy(new PreferenceCategory(mContext)); + mAdvancedVpnGroup.setKey(ADVANCED_VPN_GROUP_KEY); + mVpnGroup.setKey(VPN_GROUP_KEY); + mPreferenceManager = new PreferenceManager(mContext); + mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext); + mPreferenceScreen.addPreference(mAdvancedVpnGroup); + mPreferenceScreen.addPreference(mVpnGroup); + mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); + mVpnSettings.init(mPreferenceScreen, mFakeFeatureFactory.getAdvancedVpnFeatureProvider()); + + when(mVpnSettings.getContext()).thenReturn(mContext); + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider + .getAdvancedVpnPreferenceGroupTitle(mContext)).thenReturn(ADVANCED_VPN_GROUP_TITLE); + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getVpnPreferenceGroupTitle(mContext)) + .thenReturn(VPN_GROUP_TITLE); + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getAdvancedVpnPackageName()) + .thenReturn(ADVANCED_VPN_GROUP_PACKAGE_NAME); + doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt()); + doReturn(mContext).when(mContext).createPackageContextAsUser(any(), anyInt(), any()); + doReturn(mPreferenceManager).when(mVpnGroup).getPreferenceManager(); + doReturn(mPreferenceManager).when(mAdvancedVpnGroup).getPreferenceManager(); + } + + @Test + public void setShownAdvancedPreferences_hasGeneralVpn_returnsVpnCountAs1() { + Set updates = new ArraySet<>(); + AppPreference pref = + spy(new AppPreference(mContext, USER_ID_1, FAKE_PACKAGE_NAME)); + updates.add(pref); + + mVpnSettings.setShownAdvancedPreferences(updates); + + assertThat(mVpnGroup.getPreferenceCount()).isEqualTo(1); + assertThat(mVpnGroup.isVisible()).isTrue(); + assertThat(mAdvancedVpnGroup.isVisible()).isFalse(); + } + + @Test + public void setShownAdvancedPreferences_hasAdvancedVpn_returnsAdvancedVpnCountAs1() { + Set updates = new ArraySet<>(); + AppPreference pref = + spy(new AppPreference(mContext, USER_ID_1, ADVANCED_VPN_GROUP_PACKAGE_NAME)); + updates.add(pref); + + mVpnSettings.setShownAdvancedPreferences(updates); + + assertThat(mAdvancedVpnGroup.getPreferenceCount()).isEqualTo(1); + assertThat(mAdvancedVpnGroup.isVisible()).isTrue(); + assertThat(mVpnGroup.isVisible()).isFalse(); + } + + @Test + public void setShownAdvancedPreferences_noVpn_returnsEmpty() { + Set updates = new ArraySet<>(); + + mVpnSettings.setShownAdvancedPreferences(updates); + + assertThat(mAdvancedVpnGroup.getPreferenceCount()).isEqualTo(0); + assertThat(mVpnGroup.getPreferenceCount()).isEqualTo(0); + assertThat(mAdvancedVpnGroup.isVisible()).isFalse(); + assertThat(mVpnGroup.isVisible()).isFalse(); + } +} From f5166f46e8bc6cdfcc76a52742e4c9c36a14af14 Mon Sep 17 00:00:00 2001 From: Hugh Chen Date: Mon, 23 May 2022 05:45:28 +0000 Subject: [PATCH 2/6] RESTRICT AUTOMERGE Make VPN by Google One always appear in VPN settings Bug: 233559781 Test: manually test Change-Id: I175ab126ff92f773ab25a1fa64e4262b324fd353 --- .../vpn2/AdvancedVpnFeatureProvider.java | 5 + .../vpn2/AdvancedVpnFeatureProviderImpl.java | 5 + .../settings/vpn2/AppManagementFragment.java | 22 +++- .../android/settings/vpn2/VpnSettings.java | 23 +++- .../vpn2/AppManagementFragmentTest.java | 102 ++++++++++++++++++ .../settings/vpn2/VpnSettingsTest.java | 39 +++++++ 6 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 tests/unit/src/com/android/settings/vpn2/AppManagementFragmentTest.java diff --git a/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java b/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java index c5702a26378..cb56c351448 100644 --- a/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java +++ b/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java @@ -42,4 +42,9 @@ public interface AdvancedVpnFeatureProvider { * Returns the title of vpn preference group. */ String getVpnPreferenceGroupTitle(Context context); + + /** + * Returns {@code true} advanced vpn is removable. + */ + boolean isAdvancedVpnRemovable(); } diff --git a/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java b/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java index 0bfaf646ba7..c5bc69c042d 100644 --- a/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java +++ b/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java @@ -41,4 +41,9 @@ public class AdvancedVpnFeatureProviderImpl implements AdvancedVpnFeatureProvide public String getVpnPreferenceGroupTitle(Context context) { return null; } + + @Override + public boolean isAdvancedVpnRemovable() { + return true; + } } diff --git a/src/com/android/settings/vpn2/AppManagementFragment.java b/src/com/android/settings/vpn2/AppManagementFragment.java index d4ee5b9c476..d2fa5fccbfc 100644 --- a/src/com/android/settings/vpn2/AppManagementFragment.java +++ b/src/com/android/settings/vpn2/AppManagementFragment.java @@ -48,6 +48,7 @@ import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedPreference; @@ -71,6 +72,7 @@ public class AppManagementFragment extends SettingsPreferenceFragment private PackageManager mPackageManager; private DevicePolicyManager mDevicePolicyManager; private VpnManager mVpnManager; + private AdvancedVpnFeatureProvider mFeatureProvider; // VPN app info private final int mUserId = UserHandle.myUserId(); @@ -122,6 +124,7 @@ public class AppManagementFragment extends SettingsPreferenceFragment mPackageManager = getContext().getPackageManager(); mDevicePolicyManager = getContext().getSystemService(DevicePolicyManager.class); mVpnManager = getContext().getSystemService(VpnManager.class); + mFeatureProvider = FeatureFactory.getFactory(getContext()).getAdvancedVpnFeatureProvider(); mPreferenceAlwaysOn = (RestrictedSwitchPreference) findPreference(KEY_ALWAYS_ON_VPN); mPreferenceLockdown = (RestrictedSwitchPreference) findPreference(KEY_LOCKDOWN_VPN); @@ -283,7 +286,16 @@ public class AppManagementFragment extends SettingsPreferenceFragment } } - private void updateRestrictedViews() { + @VisibleForTesting + void updateRestrictedViews() { + if (mFeatureProvider.isAdvancedVpnSupported(getContext()) + && !mFeatureProvider.isAdvancedVpnRemovable() + && TextUtils.equals(mPackageName, mFeatureProvider.getAdvancedVpnPackageName())) { + mPreferenceForget.setVisible(false); + } else { + mPreferenceForget.setVisible(true); + } + if (isAdded()) { mPreferenceAlwaysOn.checkRestrictionAndSetDisabled(UserManager.DISALLOW_CONFIG_VPN, mUserId); @@ -314,6 +326,14 @@ public class AppManagementFragment extends SettingsPreferenceFragment } } + @VisibleForTesting + void init(String packageName, AdvancedVpnFeatureProvider featureProvider, + RestrictedPreference preference) { + mPackageName = packageName; + mFeatureProvider = featureProvider; + mPreferenceForget = preference; + } + private String getAlwaysOnVpnPackage() { return mVpnManager.getAlwaysOnVpnPackageForUser(mUserId); } diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java index 5712b3fd1cd..43805956b6e 100644 --- a/src/com/android/settings/vpn2/VpnSettings.java +++ b/src/com/android/settings/vpn2/VpnSettings.java @@ -241,7 +241,8 @@ public class VpnSettings extends RestrictedSettingsFragment implements // Run heavy RPCs before switching to UI thread final List vpnProfiles = loadVpnProfiles(); - final List vpnApps = getVpnApps(context, /* includeProfiles */ true); + final List vpnApps = getVpnApps(context, /* includeProfiles */ true, + mFeatureProvider); final Map connectedLegacyVpns = getConnectedLegacyVpns(); final Set connectedAppVpns = getConnectedAppVpns(); @@ -571,7 +572,15 @@ public class VpnSettings extends RestrictedSettingsFragment implements return result; } - static List getVpnApps(Context context, boolean includeProfiles) { + static List getVpnApps(Context context, boolean includeProfiles, + AdvancedVpnFeatureProvider featureProvider) { + return getVpnApps(context, includeProfiles, featureProvider, + context.getSystemService(AppOpsManager.class)); + } + + @VisibleForTesting + static List getVpnApps(Context context, boolean includeProfiles, + AdvancedVpnFeatureProvider featureProvider, AppOpsManager aom) { List result = Lists.newArrayList(); final Set profileIds; @@ -584,8 +593,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements profileIds = Collections.singleton(UserHandle.myUserId()); } - // Fetch VPN-enabled apps from AppOps. - AppOpsManager aom = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); List apps = aom.getPackagesForOps(new int[] {OP_ACTIVATE_VPN, OP_ACTIVATE_PLATFORM_VPN}); if (apps != null) { @@ -603,7 +610,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements allowed = true; } } - if (allowed) { + if (allowed || isAdvancedVpn(featureProvider, pkg.getPackageName(), context)) { result.add(new AppVpnInfo(userId, pkg.getPackageName())); } } @@ -613,6 +620,12 @@ public class VpnSettings extends RestrictedSettingsFragment implements return result; } + private static boolean isAdvancedVpn(AdvancedVpnFeatureProvider featureProvider, + String packageName, Context context) { + return featureProvider.isAdvancedVpnSupported(context) + && TextUtils.equals(packageName, featureProvider.getAdvancedVpnPackageName()); + } + private static List loadVpnProfiles() { final ArrayList result = Lists.newArrayList(); diff --git a/tests/unit/src/com/android/settings/vpn2/AppManagementFragmentTest.java b/tests/unit/src/com/android/settings/vpn2/AppManagementFragmentTest.java new file mode 100644 index 00000000000..80bb39372c0 --- /dev/null +++ b/tests/unit/src/com/android/settings/vpn2/AppManagementFragmentTest.java @@ -0,0 +1,102 @@ +/* + * 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.vpn2; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.Looper; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settingslib.RestrictedPreference; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +@RunWith(AndroidJUnit4.class) +public class AppManagementFragmentTest { + private static final String FAKE_PACKAGE_NAME = "com.fake.package.name"; + private static final String ADVANCED_VPN_GROUP_PACKAGE_NAME = "com.advanced.package.name"; + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + private AppManagementFragment mFragment; + private Context mContext; + private FakeFeatureFactory mFakeFeatureFactory; + private RestrictedPreference mPreferenceForget; + + @Before + @UiThreadTest + public void setUp() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + mFragment = spy(new AppManagementFragment()); + mContext = spy(ApplicationProvider.getApplicationContext()); + mPreferenceForget = new RestrictedPreference(mContext); + + mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); + mFragment.init(ADVANCED_VPN_GROUP_PACKAGE_NAME, + mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), mPreferenceForget); + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getAdvancedVpnPackageName()) + .thenReturn(ADVANCED_VPN_GROUP_PACKAGE_NAME); + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnSupported(any())) + .thenReturn(true); + } + + @Test + public void updateRestrictedViews_isAdvancedVpn_hidesForgetPreference() { + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnRemovable()) + .thenReturn(false); + mFragment.updateRestrictedViews(); + assertThat(mPreferenceForget.isVisible()).isFalse(); + } + + @Test + public void updateRestrictedViews_isNotAdvancedVpn_showsForgetPreference() { + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnRemovable()) + .thenReturn(false); + mFragment.init(FAKE_PACKAGE_NAME, + mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), mPreferenceForget); + mFragment.updateRestrictedViews(); + assertThat(mPreferenceForget.isVisible()).isTrue(); + } + + @Test + public void updateRestrictedViews_isAdvancedVpnRemovable_showsForgetPreference() { + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnRemovable()) + .thenReturn(true); + mFragment.init(FAKE_PACKAGE_NAME, + mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), mPreferenceForget); + mFragment.updateRestrictedViews(); + assertThat(mPreferenceForget.isVisible()).isTrue(); + } +} diff --git a/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java b/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java index 1b3b49c63c3..86bd1e741a2 100644 --- a/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java +++ b/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.os.Looper; @@ -45,9 +46,12 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.ArrayList; +import java.util.List; import java.util.Set; @RunWith(AndroidJUnit4.class) @@ -63,6 +67,9 @@ public class VpnSettingsTest { @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Mock + private AppOpsManager mAppOpsManager; + private VpnSettings mVpnSettings; private Context mContext; private PreferenceManager mPreferenceManager; @@ -98,6 +105,8 @@ public class VpnSettingsTest { .thenReturn(VPN_GROUP_TITLE); when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getAdvancedVpnPackageName()) .thenReturn(ADVANCED_VPN_GROUP_PACKAGE_NAME); + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnSupported(any())) + .thenReturn(true); doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt()); doReturn(mContext).when(mContext).createPackageContextAsUser(any(), anyInt(), any()); doReturn(mPreferenceManager).when(mVpnGroup).getPreferenceManager(); @@ -143,4 +152,34 @@ public class VpnSettingsTest { assertThat(mAdvancedVpnGroup.isVisible()).isFalse(); assertThat(mVpnGroup.isVisible()).isFalse(); } + + @Test + public void getVpnApps_isAdvancedVpn_returnsOne() { + int uid = 1111; + List opEntries = new ArrayList<>(); + List apps = new ArrayList<>(); + AppOpsManager.PackageOps packageOps = + new AppOpsManager.PackageOps(ADVANCED_VPN_GROUP_PACKAGE_NAME, uid, opEntries); + apps.add(packageOps); + when(mAppOpsManager.getPackagesForOps((int[]) any())).thenReturn(apps); + + assertThat(VpnSettings.getVpnApps(mContext, /* includeProfiles= */ false, + mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), + mAppOpsManager).size()).isEqualTo(1); + } + + @Test + public void getVpnApps_isNotAdvancedVpn_returnsEmpty() { + int uid = 1111; + List opEntries = new ArrayList<>(); + List apps = new ArrayList<>(); + AppOpsManager.PackageOps packageOps = + new AppOpsManager.PackageOps(FAKE_PACKAGE_NAME, uid, opEntries); + apps.add(packageOps); + when(mAppOpsManager.getPackagesForOps((int[]) any())).thenReturn(apps); + + assertThat(VpnSettings.getVpnApps(mContext, /* includeProfiles= */ false, + mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), + mAppOpsManager)).isEmpty(); + } } From 7087e5c45701ce9756e4901cbe52cde2c59e2c3f Mon Sep 17 00:00:00 2001 From: Amy Hsu Date: Thu, 30 Jun 2022 15:06:34 +0800 Subject: [PATCH 3/6] [RRS] Activate investigation of screen_resolution in settingsstats Define a setting string for putting data for suez/settingstats. Bug: 234035619 Test: Manually check ScreenResolution ap in Settings can work normally. Merged-In: Ib4622490b0f63139b47f242ebcae916edf291cea Change-Id: Ib4622490b0f63139b47f242ebcae916edf291cea --- .../display/ScreenResolutionFragment.java | 26 ++++++++++++++----- .../display/ScreenResolutionFragmentTest.java | 8 +++--- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/com/android/settings/display/ScreenResolutionFragment.java b/src/com/android/settings/display/ScreenResolutionFragment.java index bc825149c9c..914d4be568a 100644 --- a/src/com/android/settings/display/ScreenResolutionFragment.java +++ b/src/com/android/settings/display/ScreenResolutionFragment.java @@ -26,6 +26,7 @@ import android.content.res.Resources; import android.graphics.Point; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; +import android.provider.Settings; import android.text.TextUtils; import android.view.Display; @@ -56,6 +57,7 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment { private Resources mResources; private static final int FHD_INDEX = 0; private static final int QHD_INDEX = 1; + private static final String RESOLUTION_METRIC_SETTING_KEY = "user_selected_resolution"; private Display mDefaultDisplay; private String[] mScreenResolutionOptions; private Set mResolutions; @@ -157,6 +159,17 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment { @VisibleForTesting public void setDisplayMode(final int width) { mDisplayObserver.startObserve(); + + /** For store settings globally. */ + /** TODO(b/238061217): Moving to an atom with the same string */ + Settings.System.putString( + getContext().getContentResolver(), + RESOLUTION_METRIC_SETTING_KEY, + getPreferMode(width).getPhysicalWidth() + + "x" + + getPreferMode(width).getPhysicalHeight()); + + /** Apply the resolution change. */ mDefaultDisplay.setUserPreferredDisplayMode(getPreferMode(width)); } @@ -186,7 +199,7 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment { protected boolean setDefaultKey(final String key) { int width = getWidthForResoluitonKey(key); if (width < 0) { - return false; + return false; } setDisplayMode(width); @@ -200,9 +213,8 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment { String selectedKey = selected.getKey(); int selectedWidth = getWidthForResoluitonKey(selectedKey); if (!mDisplayObserver.setPendingResolutionChange(selectedWidth)) { - return; + return; } - super.onRadioButtonClicked(selected); } @@ -318,7 +330,7 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment { } if (!isDensityChanged() || !isResolutionChangeApplied()) { - return; + return; } restoreDensity(); @@ -353,10 +365,10 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment { int currentWidth = getCurrentWidth(); if (selectedWidth == currentWidth) { - return false; + return false; } if (mPreviousWidth.get() != -1 && !isResolutionChangeApplied()) { - return false; + return false; } mPreviousWidth.set(currentWidth); @@ -366,7 +378,7 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment { private boolean isResolutionChangeApplied() { if (mPreviousWidth.get() == getCurrentWidth()) { - return false; + return false; } return true; diff --git a/tests/unit/src/com/android/settings/display/ScreenResolutionFragmentTest.java b/tests/unit/src/com/android/settings/display/ScreenResolutionFragmentTest.java index b7d37df0d19..4e674d271cb 100644 --- a/tests/unit/src/com/android/settings/display/ScreenResolutionFragmentTest.java +++ b/tests/unit/src/com/android/settings/display/ScreenResolutionFragmentTest.java @@ -27,15 +27,12 @@ import android.view.Display; import androidx.test.annotation.UiThreadTest; import androidx.test.core.app.ApplicationProvider; -import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.settingslib.widget.SelectorWithWidgetPreference; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) public class ScreenResolutionFragmentTest { private Context mContext; @@ -56,6 +53,7 @@ public class ScreenResolutionFragmentTest { public void getDefaultKey_FHD() { Display.Mode mode = new Display.Mode(0, FHD_WIDTH, 0, 0); doReturn(mode).when(mFragment).getDisplayMode(); + doReturn(mContext).when(mFragment).getContext(); mFragment.onAttach(mContext); assertThat(mFragment.getDefaultKey()).isEqualTo(mFragment.getKeyForResolution(FHD_WIDTH)); @@ -66,6 +64,7 @@ public class ScreenResolutionFragmentTest { public void getDefaultKey_QHD() { Display.Mode mode = new Display.Mode(0, QHD_WIDTH, 0, 0); doReturn(mode).when(mFragment).getDisplayMode(); + doReturn(mContext).when(mFragment).getContext(); mFragment.onAttach(mContext); assertThat(mFragment.getDefaultKey()).isEqualTo(mFragment.getKeyForResolution(QHD_WIDTH)); @@ -74,6 +73,7 @@ public class ScreenResolutionFragmentTest { @Test @UiThreadTest public void setDefaultKey_FHD() { + doReturn(mContext).when(mFragment).getContext(); mFragment.onAttach(mContext); mFragment.setDefaultKey(mFragment.getKeyForResolution(FHD_WIDTH)); @@ -84,6 +84,7 @@ public class ScreenResolutionFragmentTest { @Test @UiThreadTest public void setDefaultKey_QHD() { + doReturn(mContext).when(mFragment).getContext(); mFragment.onAttach(mContext); mFragment.setDefaultKey(mFragment.getKeyForResolution(QHD_WIDTH)); @@ -94,6 +95,7 @@ public class ScreenResolutionFragmentTest { @Test @UiThreadTest public void bindPreferenceExtra_setSummary() { + doReturn(mContext).when(mFragment).getContext(); mFragment.onAttach(mContext); SelectorWithWidgetPreference preference = new SelectorWithWidgetPreference(mContext); ScreenResolutionFragment.ScreenResolutionCandidateInfo candidates = From e39ecafa1f11070aad95ca17d0074d55b2e741b5 Mon Sep 17 00:00:00 2001 From: Kuan Wang Date: Fri, 8 Jul 2022 14:43:04 +0800 Subject: [PATCH 4/6] Add function getBatteryHistorySinceLastFullCharge, used to replace getBatteryHistory in BatteryHistoryLoader. getBatteryHistory couldn't be changed directly as it needs to be kept for other features. Bug: 236101687 Test: make RunSettingsRoboTests Change-Id: I3e3cdd3a0225228bf76f6750f6a56f031666720f Merged-In: I3e3cdd3a0225228bf76f6750f6a56f031666720f --- .../settings/fuelgauge/PowerUsageFeatureProvider.java | 5 +++++ .../settings/fuelgauge/PowerUsageFeatureProviderImpl.java | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index ee53d7f6b6e..83d7a33287a 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -149,6 +149,11 @@ public interface PowerUsageFeatureProvider { */ Map> getBatteryHistory(Context context); + /** + * Returns battery history data since last full charge with corresponding timestamp key. + */ + Map> getBatteryHistorySinceLastFullCharge(Context context); + /** * Returns {@link Uri} to monitor battery history data is update. */ diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index 8c8fd96965d..12626414e44 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -165,6 +165,12 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider return null; } + @Override + public Map> getBatteryHistorySinceLastFullCharge( + Context context) { + return null; + } + @Override public Uri getBatteryHistoryUri() { return null; From 764d513d00122e9402364e370bed634df7323d81 Mon Sep 17 00:00:00 2001 From: ykhung Date: Sun, 10 Jul 2022 23:47:42 +0800 Subject: [PATCH 5/6] Support multi-user privacy for battery usage chart When there are multiple accounts in the devices, the battery usage list is shared in the current design. We will aggregate other users usage data into a single item to support multi-user privacy requirements Screenshot: https://screenshot.googleplex.com/AkFTUtNvnoxcuGR Bug: 202119550 Test: make RunSettingsRoboTests Change-Id: I6cb55f0d50a4caca83212a0a54410530a032c089 --- res/values/strings.xml | 2 + .../settings/fuelgauge/BatteryUtils.java | 2 + .../batteryusage/BatteryDiffEntry.java | 14 ++++ .../fuelgauge/batteryusage/ConvertUtils.java | 61 ++++++++++++++- .../fuelgauge/BatteryBackupHelperTest.java | 11 ++- .../batteryusage/BatteryDiffEntryTest.java | 41 ++++++---- .../batteryusage/ConvertUtilsTest.java | 76 +++++++++++++++++++ 7 files changed, 191 insertions(+), 16 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index b7007c4b69c..fde4f262b59 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6646,6 +6646,8 @@ No usage for past 24 hr + + Other users Battery left estimate is based on your device usage diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 3f6c1657165..a6c48a48d6b 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -69,6 +69,8 @@ public class BatteryUtils { public static final int UID_REMOVED_APPS = -4; /** Special UID value for data usage by tethering. */ public static final int UID_TETHERING = -5; + /** Special UID for aggregated other users. */ + public static final long UID_OTHER_USERS = Long.MIN_VALUE; @Retention(RetentionPolicy.SOURCE) @IntDef({StatusType.SCREEN_USAGE, diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java index 8b995c859f9..d4d7a00fdc2 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java @@ -113,6 +113,9 @@ public class BatteryDiffEntry { /** Gets the app label name for this entry. */ public String getAppLabel() { + if (isOtherUsers()) { + return mContext.getString(R.string.battery_usage_other_users); + } loadLabelAndIcon(); // Returns default applicationn label if we cannot find it. return mAppLabel == null || mAppLabel.length() == 0 @@ -122,6 +125,9 @@ public class BatteryDiffEntry { /** Gets the app icon {@link Drawable} for this entry. */ public Drawable getAppIcon() { + if (isOtherUsers()) { + return mContext.getDrawable(R.drawable.ic_power_system); + } loadLabelAndIcon(); return mAppIcon != null && mAppIcon.getConstantState() != null ? mAppIcon.getConstantState().newDrawable() @@ -156,6 +162,9 @@ public class BatteryDiffEntry { /** Whether the current BatteryDiffEntry is system component or not. */ public boolean isSystemEntry() { + if (isOtherUsers()) { + return true; + } switch (mBatteryHistEntry.mConsumerType) { case ConvertUtils.CONSUMER_TYPE_USER_BATTERY: case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY: @@ -175,6 +184,11 @@ public class BatteryDiffEntry { return false; } + private boolean isOtherUsers() { + return mBatteryHistEntry.mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY + && mBatteryHistEntry.mUid == BatteryUtils.UID_OTHER_USERS; + } + void loadLabelAndIcon() { if (mIsLoaded) { return; diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java index 76f9419ac41..168fe0f5383 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java +++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java @@ -21,6 +21,7 @@ import android.content.Context; import android.os.BatteryUsageStats; import android.os.LocaleList; import android.os.UserHandle; +import android.os.UserManager; import android.text.format.DateFormat; import android.text.format.DateUtils; import android.util.ArraySet; @@ -28,6 +29,8 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; +import com.android.settings.Utils; +import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.overlay.FeatureFactory; import java.lang.annotation.Retention; @@ -265,17 +268,55 @@ public final class ConvertUtils { } } insert24HoursData(BatteryChartView.SELECTED_INDEX_ALL, resultMap); + resolveMultiUsersData(context, resultMap); if (purgeLowPercentageAndFakeData) { purgeLowPercentageAndFakeData(context, resultMap); } return resultMap; } + @VisibleForTesting + static void resolveMultiUsersData( + final Context context, + final Map> indexedUsageMap) { + final int currentUserId = context.getUserId(); + final UserHandle userHandle = + Utils.getManagedProfile(context.getSystemService(UserManager.class)); + final int workProfileUserId = + userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE; + // Loops for all BatteryDiffEntry in the different slots. + for (List entryList : indexedUsageMap.values()) { + double consumePowerFromOtherUsers = 0f; + double consumePercentageFromOtherUsers = 0f; + final Iterator iterator = entryList.iterator(); + while (iterator.hasNext()) { + final BatteryDiffEntry entry = iterator.next(); + final BatteryHistEntry batteryHistEntry = entry.mBatteryHistEntry; + if (batteryHistEntry.mConsumerType != CONSUMER_TYPE_UID_BATTERY) { + continue; + } + // Whether the BatteryHistEntry represents the current user data? + if (batteryHistEntry.mUserId == currentUserId + || batteryHistEntry.mUserId == workProfileUserId) { + continue; + } + // Removes and aggregates non-current users data from the list. + iterator.remove(); + consumePowerFromOtherUsers += entry.mConsumePower; + consumePercentageFromOtherUsers += entry.getPercentOfTotal(); + } + if (consumePercentageFromOtherUsers != 0) { + entryList.add(createOtherUsersEntry(context, consumePowerFromOtherUsers, + consumePercentageFromOtherUsers)); + } + } + } + private static void insert24HoursData( final int desiredIndex, final Map> indexedUsageMap) { final Map resultMap = new HashMap<>(); - double totalConsumePower = 0.0; + double totalConsumePower = 0f; // Loops for all BatteryDiffEntry and aggregate them together. for (List entryList : indexedUsageMap.values()) { for (BatteryDiffEntry entry : entryList) { @@ -361,4 +402,22 @@ public final class ConvertUtils { return locales != null && !locales.isEmpty() ? locales.get(0) : Locale.getDefault(); } + + private static BatteryDiffEntry createOtherUsersEntry( + Context context, double consumePower, double consumePercentage) { + final ContentValues values = new ContentValues(); + values.put(BatteryHistEntry.KEY_UID, BatteryUtils.UID_OTHER_USERS); + values.put(BatteryHistEntry.KEY_USER_ID, BatteryUtils.UID_OTHER_USERS); + values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, CONSUMER_TYPE_UID_BATTERY); + // We will show the percentage for the "other users" item only, the aggregated + // running time information is useless for users to identify individual apps. + final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry( + context, + /*foregroundUsageTimeInMs=*/ 0, + /*backgroundUsageTimeInMs=*/ 0, + consumePower, + new BatteryHistEntry(values)); + batteryDiffEntry.setTotalConsumePower(100 * consumePower / consumePercentage); + return batteryDiffEntry; + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java index 14bbeea7187..283df7bcc43 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java @@ -70,6 +70,7 @@ import org.robolectric.annotation.Resetter; import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; @RunWith(RobolectricTestRunner.class) @@ -343,9 +344,17 @@ public final class BatteryBackupHelperTest { private void verifyBackupData(String expectedResult) throws Exception { final byte[] expectedBytes = expectedResult.getBytes(); + final ArgumentCaptor captor = ArgumentCaptor.forClass(byte[].class); + final Set expectedResultSet = + Set.of(expectedResult.split(BatteryBackupHelper.DELIMITER)); + verify(mBackupDataOutput).writeEntityHeader( BatteryBackupHelper.KEY_OPTIMIZATION_LIST, expectedBytes.length); - verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length); + verify(mBackupDataOutput).writeEntityData(captor.capture(), eq(expectedBytes.length)); + final String actualResult = new String(captor.getValue()); + final Set actualResultSet = + Set.of(actualResult.split(BatteryBackupHelper.DELIMITER)); + assertThat(actualResultSet).isEqualTo(expectedResultSet); } private void createTestingData( diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java index bb19b5a53dc..683f0fd2df4 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java @@ -138,7 +138,7 @@ public final class BatteryDiffEntryTest { // Generates fake testing data. final ContentValues values = getContentValuesWithType( ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY); - values.put("drainType", + values.put(BatteryHistEntry.KEY_DRAIN_TYPE, Integer.valueOf(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY)); final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); @@ -164,7 +164,7 @@ public final class BatteryDiffEntryTest { // Generates fake testing data. final ContentValues values = getContentValuesWithType( ConvertUtils.CONSUMER_TYPE_USER_BATTERY); - values.put("userId", Integer.valueOf(1001)); + values.put(BatteryHistEntry.KEY_USER_ID, Integer.valueOf(1001)); final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); @@ -189,8 +189,8 @@ public final class BatteryDiffEntryTest { final String fakePackageName = "com.fake.google.com"; final ContentValues values = getContentValuesWithType( ConvertUtils.CONSUMER_TYPE_UID_BATTERY); - values.put("uid", /*invalid uid*/ 10001); - values.put("packageName", fakePackageName); + values.put(BatteryHistEntry.KEY_UID, /*invalid uid*/ 10001); + values.put(BatteryHistEntry.KEY_PACKAGE_NAME, fakePackageName); doReturn(mMockAppInfo).when(mMockPackageManager) .getApplicationInfo(fakePackageName, 0); doReturn(expectedAppLabel).when(mMockPackageManager) @@ -233,7 +233,7 @@ public final class BatteryDiffEntryTest { final String expectedAppLabel = "fake app label"; final ContentValues values = getContentValuesWithType( ConvertUtils.CONSUMER_TYPE_UID_BATTERY); - values.put("appLabel", expectedAppLabel); + values.put(BatteryHistEntry.KEY_APP_LABEL, expectedAppLabel); final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); final BatteryDiffEntry entry = createBatteryDiffEntry(10, batteryHistEntry); @@ -391,8 +391,8 @@ public final class BatteryDiffEntryTest { final String fakePackageName = "com.fake.google.com"; final ContentValues values = getContentValuesWithType( ConvertUtils.CONSUMER_TYPE_UID_BATTERY); - values.put("uid", /*invalid uid*/ 10001); - values.put("packageName", fakePackageName); + values.put(BatteryHistEntry.KEY_UID, /*invalid uid*/ 10001); + values.put(BatteryHistEntry.KEY_PACKAGE_NAME, fakePackageName); final BatteryDiffEntry entry = createBatteryDiffEntry(10, new BatteryHistEntry(values)); @@ -424,7 +424,7 @@ public final class BatteryDiffEntryTest { final String expectedPackageName = "com.fake.google.com"; final ContentValues values = getContentValuesWithType( ConvertUtils.CONSUMER_TYPE_UID_BATTERY); - values.put("packageName", expectedPackageName); + values.put(BatteryHistEntry.KEY_PACKAGE_NAME, expectedPackageName); final BatteryDiffEntry entry = createBatteryDiffEntry(10, new BatteryHistEntry(values)); @@ -437,7 +437,7 @@ public final class BatteryDiffEntryTest { final ContentValues values = getContentValuesWithType( ConvertUtils.CONSUMER_TYPE_UID_BATTERY); values.put( - "packageName", + BatteryHistEntry.KEY_PACKAGE_NAME, expectedPackageName + ":privileged_process0"); final BatteryDiffEntry entry = createBatteryDiffEntry(10, new BatteryHistEntry(values)); @@ -445,11 +445,24 @@ public final class BatteryDiffEntryTest { assertThat(entry.getPackageName()).isEqualTo(expectedPackageName); } + @Test + public void getAppLabel_withOtherUsersUid_returnExpectedLabel() { + final ContentValues values = getContentValuesWithType( + ConvertUtils.CONSUMER_TYPE_UID_BATTERY); + values.put(BatteryHistEntry.KEY_UID, BatteryUtils.UID_OTHER_USERS); + + final BatteryDiffEntry batteryDiffEntry = createBatteryDiffEntry( + /*consumePower=*/ 0, new BatteryHistEntry(values)); + + assertThat(batteryDiffEntry.getAppLabel()) + .isEqualTo(mContext.getString(R.string.battery_usage_other_users)); + } + private BatteryDiffEntry createBatteryDiffEntry( int consumerType, long uid, boolean isHidden) { final ContentValues values = getContentValuesWithType(consumerType); - values.put("isHidden", isHidden); - values.put("uid", uid); + values.put(BatteryHistEntry.KEY_IS_HIDDEN, isHidden); + values.put(BatteryHistEntry.KEY_UID, uid); return new BatteryDiffEntry( mContext, /*foregroundUsageTimeInMs=*/ 0, @@ -472,15 +485,15 @@ public final class BatteryDiffEntryTest { private static ContentValues getContentValuesWithType(int consumerType) { final ContentValues values = new ContentValues(); - values.put("consumerType", Integer.valueOf(consumerType)); + values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, Integer.valueOf(consumerType)); return values; } private BatteryDiffEntry createBatteryDiffEntry(Drawable drawable) throws Exception { final ContentValues values = getContentValuesWithType( ConvertUtils.CONSUMER_TYPE_UID_BATTERY); - values.put("uid", 1001); - values.put("packageName", "com.a.b.c"); + values.put(BatteryHistEntry.KEY_UID, 1001); + values.put(BatteryHistEntry.KEY_PACKAGE_NAME, "com.a.b.c"); final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(values); doReturn(drawable).when(mMockPackageManager).getDefaultActivityIcon(); doReturn(null).when(mMockPackageManager).getApplicationInfo("com.a.b.c", 0); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java index 0b8a98a742d..c1f981539c1 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java @@ -27,6 +27,7 @@ import android.os.BatteryUsageStats; import android.os.LocaleList; import android.os.UserHandle; +import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.PowerUsageFeatureProvider; import com.android.settings.testutils.FakeFeatureFactory; @@ -39,6 +40,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.util.Arrays; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -371,6 +373,71 @@ public final class ConvertUtilsTest { assertThat(ConvertUtils.getLocale(mContext)).isEqualTo(Locale.getDefault()); } + @Test + public void resolveMultiUsersData_replaceOtherUsersItemWithExpectedEntry() { + final int currentUserId = mContext.getUserId(); + final Map> entryMap = new HashMap<>(); + // Without other users time slot. + entryMap.put(0, Arrays.asList( + createBatteryDiffEntry( + currentUserId, + ConvertUtils.CONSUMER_TYPE_UID_BATTERY, + /*consumePercentage=*/ 50))); + // With other users time slot. + final List withOtherUsersList = new ArrayList<>(); + entryMap.put(1, withOtherUsersList); + withOtherUsersList.add( + createBatteryDiffEntry( + currentUserId + 1, + ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, + /*consumePercentage=*/ 20)); + withOtherUsersList.add( + createBatteryDiffEntry( + currentUserId + 2, + ConvertUtils.CONSUMER_TYPE_UID_BATTERY, + /*consumePercentage=*/ 30)); + withOtherUsersList.add( + createBatteryDiffEntry( + currentUserId + 3, + ConvertUtils.CONSUMER_TYPE_UID_BATTERY, + /*consumePercentage=*/ 40)); + + ConvertUtils.resolveMultiUsersData(mContext, entryMap); + + assertThat(entryMap.get(0).get(0).getPercentOfTotal()).isEqualTo(50); + // Asserts with other users items. + final List entryList = entryMap.get(1); + assertThat(entryList).hasSize(2); + assertBatteryDiffEntry( + entryList.get(0), + currentUserId + 1, + /*uid=*/ 0, + ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, + /*consumePercentage=*/ 20); + assertBatteryDiffEntry( + entryList.get(1), + BatteryUtils.UID_OTHER_USERS, + BatteryUtils.UID_OTHER_USERS, + ConvertUtils.CONSUMER_TYPE_UID_BATTERY, + /*consumePercentage=*/ 70); + } + + private BatteryDiffEntry createBatteryDiffEntry( + long userId, int counsumerType, double consumePercentage) { + final ContentValues values = new ContentValues(); + values.put(BatteryHistEntry.KEY_USER_ID, userId); + values.put(BatteryHistEntry.KEY_CONSUMER_TYPE, counsumerType); + final BatteryDiffEntry batteryDiffEntry = + new BatteryDiffEntry( + mContext, + /*foregroundUsageTimeInMs=*/ 0, + /*backgroundUsageTimeInMs=*/ 0, + /*consumePower=*/ consumePercentage, + new BatteryHistEntry(values)); + batteryDiffEntry.setTotalConsumePower(100f); + return batteryDiffEntry; + } + private static BatteryHistEntry createBatteryHistEntry( String packageName, String appLabel, double consumePower, long uid, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) { @@ -389,6 +456,15 @@ public final class ConvertUtilsTest { return new BatteryHistEntry(values); } + private static void assertBatteryDiffEntry( + BatteryDiffEntry entry, long userId, long uid, int counsumerType, + double consumePercentage) { + assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid); + assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId); + assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(counsumerType); + assertThat(entry.getPercentOfTotal()).isEqualTo(consumePercentage); + } + private static void assertBatteryDiffEntry( BatteryDiffEntry entry, int percentOfTotal, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) { From 3d4eb4f4b9a5f331f60576b5cc2d2a2124d0640c Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Mon, 11 Jul 2022 11:59:15 -0700 Subject: [PATCH 6/6] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I043b44e648cce2709d66ea0b0cdc4c367de844d6 --- res/values-am/strings.xml | 6 ++-- res/values-ca/strings.xml | 6 ++-- res/values-de/strings.xml | 2 +- res/values-es-rUS/strings.xml | 2 +- res/values-eu/strings.xml | 6 ++-- res/values-fa/strings.xml | 6 ++-- res/values-fr-rCA/strings.xml | 2 +- res/values-fr/strings.xml | 4 +-- res/values-hi/strings.xml | 4 +-- res/values-it/strings.xml | 2 +- res/values-ja/strings.xml | 4 +-- res/values-kn/strings.xml | 4 +-- res/values-nb/strings.xml | 10 +++--- res/values-nl/strings.xml | 8 ++--- res/values-or/strings.xml | 66 +++++++++++++++++------------------ res/values-pa/strings.xml | 8 ++--- res/values-ro/strings.xml | 2 +- res/values-sk/strings.xml | 2 +- res/values-uk/strings.xml | 2 +- res/values-uz/strings.xml | 2 +- res/values-vi/strings.xml | 10 +++--- res/values-zh-rCN/strings.xml | 2 +- 22 files changed, 80 insertions(+), 80 deletions(-) diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index 6c290a6c92f..73657ca1ace 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -2422,8 +2422,8 @@ "ጥቅም ላይ በማይውልበት ጊዜ ይደበዝዛል" "ከጥቂት ሰከንዶች በኋላ ይደበዝዛል ስለዚህ ማያ ገጽዎን ማየት ይበልጥ ቀላል ነው" "ጥቅም ላይ በማይውልበት ጊዜ ግልፅነት" - "ግልጽ" - "ግልጽ አይደልም" + "ግልፅ" + "ግልፅ አይደልም" "ከፍተኛ ንጽጽር ጽሁፍ" "የጽሑፍ ቀለም ወደ ጥቁር ወይም ነጭ ይቀይሩ። ከዳራ ንፅፅርን ከፍ ያደርገዋል።" "ማጉላትን በራስ-አዘምን" @@ -4611,7 +4611,7 @@ "ይህን መተግበሪያ እየተጠቀሙ ባሉ ሌሎች መተግበሪያዎች ላይ እንዲያሳይ ይፍቀዱለት። ይህ መተግበሪያ የት መታ እንደሚያደርጉ ማየት ወይም በማያ ገጽ ላይ የሚታየውን ነገር መቀየር ይችላል።" "የሁሉም ፋይሎች መዳረሻ" "ሁሉንም ፋይሎች ለማስተዳደር መዳረሻ ፍቀድ" - "ይህ መተግበሪያ በዚህ መሣሪያ ላይ ወይም በማናቸውም የተገናኙ የማከማቻ መጠኖች ላይ ሁሉንም ፋይሎች እንዲያነብ፣ እንዲያሻሽል እና እንዲሰርዝ ይፍቀዱ። ፈቃድ ከተሰጠ፣ መተግበሪያ ያለ የእርስዎ ግልጽ የሆነ ዕውቀት ፋይሎችን መድረስ ይችላል።" + "ይህ መተግበሪያ በዚህ መሣሪያ ላይ ወይም በማናቸውም የተገናኙ የማከማቻ መጠኖች ላይ ሁሉንም ፋይሎች እንዲያነብ፣ እንዲያሻሽል እና እንዲሰርዝ ይፍቀዱ። ፈቃድ ከተሰጠ፣ መተግበሪያ ያለ የእርስዎ ግልፅ የሆነ ዕውቀት ፋይሎችን መድረስ ይችላል።" "ሁሉንም ፋይሎች መድረስ ይችላል" "የሚዲያ አስተዳደር መተግበሪያዎች" "መተግበሪያው ሚዲያን እንዲያቀናብር ፍቀድ" diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 1c923f12987..38f4f7d3612 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -438,7 +438,7 @@ "Configura l\'empremta digital" "Permet desbloqueig amb empremta" "Utilitzar l\'empremta digital" - "Utilitza l\'empremta digital per desbloquejar la tauleta o verificar la teva identitat, com ara quan inicies la sessió en aplicacions o aproves una compra." + "Utilitza l\'empremta digital per desbloquejar la tauleta o verificar que ets tu, com ara quan inicies la sessió en aplicacions o aproves una compra." "Utilitza l\'empremta digital per desbloquejar el dispositiu o verificar la teva identitat, com ara quan inicies la sessió en aplicacions o aproves una compra." "Utilitza l\'empremta digital per desbloquejar el telèfon o verificar la teva identitat, com ara quan inicies la sessió en aplicacions o aproves una compra." "Permet que el teu fill utilitzi l\'empremta digital per desbloquejar el telèfon o verificar la seva identitat. Ho podrà fer quan iniciï la sessió en aplicacions, aprovi una compra, etc." @@ -476,7 +476,7 @@ "Aixeca el dit quan notis una vibració" "Ves a un lloc menys il·luminat i torna-ho a provar" "Has arribat al nombre màxim d\'intents" - "Utilitza l\'empremta digital per desbloquejar la tauleta o verificar la teva identitat, com quan inicies la sessió en aplicacions" + "Utilitza l\'empremta digital per desbloquejar la tauleta o verificar que ets tu, com quan inicies la sessió en aplicacions" "Utilitza l\'empremta digital per desbloquejar el dispositiu o verificar la teva identitat, com quan inicies la sessió en aplicacions" "Utilitza l\'empremta digital per desbloquejar el telèfon o verificar la teva identitat, com quan inicies la sessió en aplicacions" "Desbloqueig facial i amb empremta digital" @@ -531,7 +531,7 @@ "Això ajuda a capturar millor l\'empremta digital" "Registre de l\'empremta digital %d per cent" "S\'ha afegit l\'empremta digital" - "La funció Desbloqueig amb empremta digital millora com més la utilitzes per desbloquejar la tauleta o verificar la teva identitat en aplicacions" + "La funció Desbloqueig amb empremta digital millora com més la utilitzes per desbloquejar la tauleta o verificar que ets tu en aplicacions" "La funció Desbloqueig amb empremta digital millora com més la utilitzes per desbloquejar el dispositiu o verificar la teva identitat en aplicacions" "La funció Desbloqueig amb empremta digital millora com més la utilitzes per desbloquejar el telèfon o verificar la teva identitat en aplicacions" "Fes-ho més tard" diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 2b1886414b3..563cc952125 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -5151,7 +5151,7 @@ "Belegter Speicherplatz" "(für Nutzer %s deinstalliert)" "(für Nutzer %s deaktiviert)" - "Dienst für automatisches Ausfüllen" + "Autofill-Service" "Passwörter" %1$d Passwörter diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 07b5f80a94c..18aab99e249 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -476,7 +476,7 @@ "Levanta el dedo cuando sientas una vibración" "Ve a un lugar donde la luz sea menos brillante y vuelve a intentarlo" "Alcanzaste la cantidad máxima de intentos" - "Usa tu huella dactilar para desbloquear la tablet o verificar tu identidad, por ejemplo, cuando accedes a apps" + "Usa tu huella dactilar para desbloquear la tablet o verificar tu identidad, por ejemplo, cuando accedes a apps." "Usa tu huella dactilar para desbloquear el dispositivo o verificar tu identidad, por ejemplo, cuando accedes a apps" "Usa tu huella dactilar para desbloquear el teléfono o verificar tu identidad, como cuando accedes a apps" "Desbloqueo facial y con huellas dactilares" diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index b6b9f1461f0..59e3ae4541b 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -738,7 +738,7 @@ "Aldatu desblokeatzeko eredua" "Aldatu desblokeo PINa" "Aldatu desblokeatzeko pasahitza" - "%1$s aplikazioak PIN edo pasahitz seguru bat erabiltzea gomendatzen du, eta baliteke ez funtzionatzea behar bezala halakorik gabe" + "%1$s aplikazioak PIN edo pasahitz konplexu bat erabiltzea gomendatzen du, eta baliteke ez funtzionatzea behar bezala halakorik gabe" "%1$s aplikazioak beste PIN edo pasahitz bat erabiltzea gomendatzen du, eta baliteke ez funtzionatzea behar bezala halakorik gabe" "%1$s aplikazioak beste eredu, PIN edo pasahitz bat erabiltzea gomendatzen du, eta baliteke ez funtzionatzea behar bezala halakorik gabe" "%1$s aplikazioak pantailaren beste blokeo bat erabiltzea gomendatzen du" @@ -2047,9 +2047,9 @@ "Galdetu IKT saileko administratzaileari" "PINa, eredua edo pasahitza berrezartzen lagunduko dizu" - "Tabletak eta datu pertsonalek aplikazio ezezagunen erasoak jaso ditzakete. Iturburu honetako aplikazioak instalatzen badituzu, onartu egingo duzu haiek erabiltzeagatik tabletari gerta dakizkiokeen kalteen edo datu-galeren erantzulea zeu zarela." + "Baliteke tabletak eta datu pertsonalek aplikazio ezezagunen erasoak jasatea. Iturburu honetako aplikazioak instalatzen badituzu, onartu egingo duzu haiek erabiltzeagatik tabletari agian gertatuko zaizkion kalteen edo datu-galeren erantzulea zeu zarela." "Baliteke telefonoak eta datu pertsonalek aplikazio ezezagunen erasoak jasatea. Iturburu honetako aplikazioak instalatzen badituzu, onartu egingo duzu zeu zarela haiek erabiltzeagatik telefonoari agian gertatuko zaizkion kalteen edo datu-galeren erantzulea." - "Gailuak eta datu pertsonalek aplikazio ezezagunen erasoak jaso ditzakete. Iturburu honetako aplikazioak instalatzen badituzu, onartu egingo duzu haiek erabiltzeagatik gailuari agian gertatuko zaizkion kalteen edo datu-galeren erantzulea zeu izango zarela." + "Baliteke gailuak eta datu pertsonalek aplikazio ezezagunen erasoak jasatea. Iturburu honetako aplikazioak instalatzen badituzu, onartu egingo duzu haiek erabiltzeagatik gailuari agian gertatuko zaizkion kalteen edo datu-galeren erantzulea zeu izango zarela." "Ezarpen aurreratuak" "Gaitu ezarpenen aukera gehiago" "Aplikazioen informazioa" diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 006f953d292..51f4f43b6c3 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -1473,7 +1473,7 @@ "تنظیمات قفل سیم کارت" "قفل سیم کارت" "خاموش" - "قفل شد" + "قفل‌شده" "قفل سیم کارت" "قفل کردن سیم کارت" "درخواست پین برای استفاده از رایانهٔ لوحی" @@ -3683,8 +3683,8 @@ "‏اشتراک‌گذاری اینترنت با USB، اتصال اینترنت به بلوتوث تلفن همراه، نقطه اتصال Wi-Fi" "لمس، لرزیدن، لرزش" "لمسی، لرزش، صفحه نمایش، حساسیت" - "لمس، لرزش، تلفن، تماس، حساسیت، به صدا در آوردن زنگ" - "لمس، لرزش، تلفن، تماس، به صدا در آوردن زنگ، به‌تدریج" + "لمس، لرزش، تلفن، تماس، حساسیت، زنگ" + "لمس، لرزش، تلفن، تماس، زنگ، به‌تدریج" "لمس، لرزش، حساسیت، اعلان" "لمس، لرزش، حساسیت، هشدار" "لمس، لرزش، حساسیت، رسانه" diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index a86ef6f1958..0ac9f2af0e8 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -479,7 +479,7 @@ "Utilisez votre empreinte digitale pour déverrouiller votre tablette ou vérifier que c\'est bien vous" "Utilisez votre empreinte digitale pour déverrouiller votre appareil ou vérifier que c\'est bien vous" "Utilisez votre empreinte digitale pour déverrouiller votre téléphone ou vérifier que c\'est bien vous" - "Déverrouillage par reconnaissance faciale et empreinte digitale" + "Déverrouillage par recon. faciale et empreinte digitale" "Touchez pour configurer" "Empreintes digitales et visage ajoutés" "Empreinte digitale et visage ajoutés" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 4d025a79bdd..868569defa1 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -417,7 +417,7 @@ "Toujours demander confirmation" "Toujours confirmer le déverrouillage par reco. faciale dans applis" "Supprimer l\'empreinte faciale" - "Configurer déverr. par reconn. faciale." + "Configurer déverr. par reconn. faciale" "Utilisez votre visage pour déverrouiller votre téléphone ou valider votre identité dans les applis (pour vous connecter ou approuver un achat, par exemple).\n\nÀ savoir :\nVous ne pouvez configurer qu\'un seul visage à la fois. Supprimez le visage actuel pour en ajouter un.\n\nVous pouvez déverrouiller votre téléphone sans le vouloir, en le regardant.\n\nUne autre personne peut le déverrouiller en le tenant devant votre visage.\n\nQuelqu\'un qui vous ressemble beaucoup, comme votre jumeau/jumelle, peut aussi déverrouiller votre téléphone." "Utilisez votre visage pour déverrouiller votre téléphone ou valider votre identité dans les applis (pour vous connecter ou approuver un achat, par exemple).\n\nÀ savoir :\nVous ne pouvez configurer qu\'un seul visage à la fois. Supprimez le visage actuel pour en ajouter un.\n\nVous pouvez déverrouiller votre téléphone sans le vouloir, en le regardant.\n\nUne autre personne peut le déverrouiller en le tenant devant votre visage, même si vous fermez les yeux.\n\nQuelqu\'un qui vous ressemble beaucoup, comme votre jumeau/jumelle, peut aussi déverrouiller votre téléphone." "Supprimer l\'empreinte faciale ?" @@ -479,7 +479,7 @@ "Utilisez votre empreinte digitale pour déverrouiller votre tablette ou confirmer votre identité, par exemple pour vous connecter à des applis" "Utilisez votre empreinte digitale pour déverrouiller votre appareil ou confirmer votre identité, par exemple pour vous connecter à des applis" "Utilisez votre empreinte digitale pour déverrouiller votre téléphone ou confirmer votre identité, par exemple pour vous connecter à des applis" - "Déverrouillage par reconnaissance faciale et empreinte digitale" + "Déverrouillage par reco. faciale et empreinte digitale" "Appuyer pour configurer" "Visage et empreintes digitales ajoutés" "Reconnaissance faciale et empreinte digitale ajoutées" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 923e9d2f510..70b4d022057 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -3940,7 +3940,7 @@ "स्क्रीन लॉक होने पर वर्क प्रोफ़ाइल का संवेदनशील कॉन्टेंट दिखाएं" "सारी सूचनाएं दिखाएं" "संवेदनशील कॉन्टेंट को अनलॉक होने पर ही दिखाएं" - "सूचनाएं बिल्कुल न दिखाएं" + "सूचनाएं बिलकुल न दिखाएं" "आपकी लॉक स्क्रीन कैसी दिखनी चाहिए?" "लॉक स्क्रीन" "ऑफ़िस के काम से जुड़ी सभी सूचनाएं दिखाएं" @@ -4651,7 +4651,7 @@ "P" "नमस्ते पीट!" "क्यों न आज मिलकर कॉफ़ी पिएं और बातें करें?" - "हां बिल्कुल. मुझे एक अच्छी जगह भी मालूम है और वह यहां से बहुत दूर भी नहीं है." + "हां बिलकुल. मुझे एक अच्छी जगह भी मालूम है और वह यहां से बहुत दूर भी नहीं है." "बढ़िया!" "मंगलवार शाम 6:00 बजे" "मंगलवार शाम 6:01 बजे" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 0e7b5a38f2b..3a315ca2485 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -5148,7 +5148,7 @@ "Spazio occupato" "(disinstallato per l\'utente %s)" "(disattivato per l\'utente %s)" - "Compilazione automatica" + "Servizio di compilazione automatica" "Password" %1$d password diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index d9ccf2a4585..316790d473f 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -438,7 +438,7 @@ "指紋の設定" "指紋認証によるロック解除の許可" "指紋の使用" - "指紋を使ってタブレットのロック解除や本人確認(アプリへのログインや購入の承認など)を行えるようにします。" + "指紋を使ってタブレットのロック解除や本人確認(アプリへのログインや購入の承認など)を行えるようになります。" "指紋を使ってデバイスのロック解除や本人確認(アプリへのログインや購入の承認など)を行えるようにします。" "指紋を使ってスマートフォンのロック解除や本人確認(アプリへのログインや購入の承認など)を行えるようにします。" "お子様に、指紋を使ってスマートフォンのロック解除や本人確認を行うことを許可します。アプリへのログインや購入の承認などに顔を使用できるようになります。" @@ -476,7 +476,7 @@ "振動を感じるまで指を離さないでください" "もっと明るい場所に移動してもう一度お試しください" "試行回数の上限を超えました" - "指紋を使ってタブレットのロック解除や本人確認(アプリへのログインなど)を行えるようにします。" + "指紋を使ってタブレットのロック解除や本人確認(アプリへのログインなど)を行えるようになります。" "指紋を使ってデバイストのロック解除や本人確認(アプリへのログインなど)を行えるようにします。" "指紋を使ってスマートフォンのロック解除や本人確認(アプリへのログインなど)を行えるようにします。" "顔認証と指紋認証によるロック解除" diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml index 6ce82ef149f..cb25677fbe0 100644 --- a/res/values-kn/strings.xml +++ b/res/values-kn/strings.xml @@ -477,8 +477,8 @@ "ಕಡಿಮೆ ಬೆಳಕಿನ ಸ್ಥಳಕ್ಕೆ ಸರಿಸಿ ಹಾಗೂ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ" "ನೀವು ಗರಿಷ್ಠ ಸಂಖ್ಯೆಯ ಪ್ರಯತ್ನಗಳ ಮಿತಿಯನ್ನು ತಲುಪಿದ್ದೀರಿ" "ನೀವು ಆ್ಯಪ್‌ಗಳಿಗೆ ಸೈನ್ ಇನ್ ಮಾಡುವಂತೆಯೇ, ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಅಥವಾ ನಿಮ್ಮ ಗುರುತನ್ನು ದೃಢೀಕರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ನೀವು ಬಳಸಿ" - "ನೀವು ಆ್ಯಪ್‌ಗಳಿಗೆ ಸೈನ್ ಇನ್ ಮಾಡುವಂತೆಯೇ, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಅಥವಾ ನಿಮ್ಮ ಗುರುತನ್ನು ದೃಢೀಕರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ನೀವು ಬಳಸಿ" - "ನೀವು ಆ್ಯಪ್‌ಗಳಿಗೆ ಸೈನ್ ಇನ್ ಮಾಡುವಂತೆಯೇ, ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಅಥವಾ ನಿಮ್ಮ ಗುರುತನ್ನು ದೃಢೀಕರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ನೀವು ಬಳಸಿ" + "ನೀವು ಆ್ಯಪ್‌ಗಳಿಗೆ ಸೈನ್ ಇನ್ ಮಾಡುವಂತೆಯೇ, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಅಥವಾ ನಿಮ್ಮ ಗುರುತನ್ನು ದೃಢೀಕರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ಬಳಸಿ" + "ನೀವು ಆ್ಯಪ್‌ಗಳಿಗೆ ಸೈನ್ ಇನ್ ಮಾಡುವಂತೆಯೇ, ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಅಥವಾ ನಿಮ್ಮ ಗುರುತನ್ನು ದೃಢೀಕರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ಬಳಸಿ" "ಫೇಸ್ ಮತ್ತು ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್‌ಲಾಕ್" "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ" "ಫೇಸ್ ಮತ್ತು ಫಿಂಗರ್‌‍‍‍ಪ್ರಿಂಟ್‌ಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 1dd8febe2ca..a32d706403b 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -5088,20 +5088,20 @@ "installere apper fra utenfor Play-butikken" "starte enheten din på nytt i sikker modus" "legge til flere brukere på enheten din" - "Endre dato, klokkeslett og tidssoner" + "endre dato, klokkeslett og tidssoner" "bruke utvikleralternativer" "Kredittleverandøren din kan" - "Tilgang til IMEI-nummeret ditt" + "tilgang til IMEI-nummeret ditt" "tilbakestille enheten til fabrikkstandard" "Hvis enheten din er låst, kan du bare bruke den til å" "starte nødanrop" "se systeminformasjon som dato, klokkeslett, nettverksstatus og batteri" "slå enheten din på eller av" "se varsler og SMS-er" - "Tilgang til apper som tillates av kredittleverandøren" + "tilgang til apper som tillates av kredittleverandøren" "Når du har betalt hele beløpet:" - "Alle begrensninger fjernes fra enheten" - "Du kan ikke avinstallere kreditorappen" + "alle begrensninger fjernes fra enheten" + "du kan ikke avinstallere kreditorappen" Kamera-apper Kamera-app diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 09b4fcc0a5f..12465481b6b 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -476,7 +476,7 @@ "Til je vinger op zodra je een trilling voelt" "Ga naar een plek met zachter licht en probeer het opnieuw" "Je hebt het maximale aantal pogingen bereikt" - "Gebruik je vingerafdruk om je tablet te ontgrendelen of te bevestigen dat jij het bent als je inlogt bij apps" + "Gebruik je vingerafdruk om je tablet te ontgrendelen of te bevestigen dat jij het bent als je bijvoorbeeld inlogt bij apps" "Gebruik je vingerafdruk om je apparaat te ontgrendelen of te bevestigen dat jij het bent als je inlogt bij apps" "Gebruik je vingerafdruk om je telefoon te ontgrendelen of te bevestigen dat jij het bent als je inlogt bij apps" "Ontgrendelen via gezichtsherkenning en vingerafdruk" @@ -1581,7 +1581,7 @@ "Foto\'s, video\'s" "Audio (muziek, ringtones, podcasts, enzovoort)" "Andere bestanden" - "Gegevens in het cachegeheugen" + "Gecachete gegevens" "Gedeelde opslag ontkoppelen" "SD-kaart ontkoppelen" "Interne USB-opslag ontkoppelen" @@ -5100,8 +5100,8 @@ "Meldingen en sms-berichten bekijken" "Toegang krijgen tot apps die zijn toegestaan door de kredietverstrekker" "Nadat je het volledige bedrag hebt betaald:" - "Alle beperkingen voor het apparaat worden ingetrokken" - "Je kunt de app van de kredietverstrekker verwijderen" + "worden alle beperkingen voor het apparaat ingetrokken." + "kun je de app van de kredietverstrekker verwijderen." Camera-apps Camera-app diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml index 26e52951f77..ed83c708efa 100644 --- a/res/values-or/strings.xml +++ b/res/values-or/strings.xml @@ -152,7 +152,7 @@ "ଡିଭାଇସକୁ ରିଷ୍ଟାର୍ଟ କରିବେ?" "ଏହି ସେଟିଂ ବଦଳାଇବାକୁ ଆପଣଙ୍କୁ ଆପଣଙ୍କ ଡିଭାଇସ ରିଷ୍ଟାର୍ଟ କରିବାକୁ ହେବ।" "ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ" - "ବାତିଲ୍ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" "ବ୍ଲୁଟୁଥ LE ଅଡିଓକୁ ସକ୍ଷମ କରନ୍ତୁ" "ଯଦି ଡିଭାଇସ LE ଅଡିଓ ହାର୍ଡୱେର କ୍ଷମତାକୁ ସମର୍ଥନ କରେ ତେବେ ବ୍ଲୁଟୁଥ LE ଅଡିଓ ଫିଚରକୁ ସକ୍ଷମ କରେ।" "ମିଡିଆ ଡିଭାଇସ୍‌ଗୁଡ଼ିକ" @@ -246,7 +246,7 @@ "USB ଷ୍ଟୋରେଜ୍‌" "SD କାର୍ଡ" "ପ୍ରକ୍ସି ସେଟିଂସ" - "ବାତିଲ୍" + "ବାତିଲ" "ଠିକ୍‌ ଅଛି" "ଭୁଲିଯାଆନ୍ତୁ" "ସେଭ୍‌ କରନ୍ତୁ" @@ -360,7 +360,7 @@ - "ବାତିଲ୍" + "ବାତିଲ" "ନାହିଁ, ଧନ୍ୟବାଦ" "ମୁଁ ରାଜି ଅଛି" "ଅଧିକ" @@ -449,7 +449,7 @@ "ଏକ ଦୃଢ଼ ପାଟର୍ନ କିମ୍ବା PINଠାରୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ କମ୍ ସୁରକ୍ଷିତ ହୋଇପାରେ।" "ଉନ୍ନତ ଟିପଚିହ୍ନ ମଡେଲଗୁଡ଼ିକୁ ତିଆରି କରିବା ପାଇଁ ଆପଣଙ୍କର ଫୋନ୍ ବେଳେବେଳେ ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ଟିପଚିହ୍ନ ଛବିଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବ।" "ଫୋନ୍‌କୁ ଅନ୍‌ଲକ୍‌ କରିବା କିମ୍ୱା କିଣାକିଣିକୁ ଅନୁମୋଦନ କରିବା ପାଇଁ ନିଜ ଟିପଚିହ୍ନର ବ୍ୟବହାର କରନ୍ତୁ।\n\nଧ୍ୟାନଦିଅନ୍ତୁ: ଏହି ଡିଭାଇସ୍‌ ଅନଲକ୍‌ କରିବାକୁ ଆପଣ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରିପାରିବେ ନାହିଁ। ଅଧିକ ସୂଚନା ପାଇଁ, ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।" - "ବାତିଲ୍‌" + "ବାତିଲ" "ନା, ଧନ୍ୟବାଦ" "ମୁଁ ରାଜି" "ଟିପଚିହ୍ନ ବାଦ୍ ଦେବେ?" @@ -504,7 +504,7 @@ "ଯେ କୌଣସି ଭାବେ ବାଦ୍ ଦିଅନ୍ତୁ" "ପଛକୁ ଫେରନ୍ତୁ" "ବାଦ୍ ଦିଅନ୍ତୁ" - "ବାତିଲ୍ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" "ସେନ୍ସରକୁ ସ୍ପର୍ଶ କରନ୍ତୁ" "ଆପଣଙ୍କ ଟିପଚିହ୍ନ କିପରି ସେଟ୍ ଅପ୍ କରିବେ" "ଏହା ଆପଣଙ୍କ ଫୋନ୍‌ର ପଛରେ ଅଛି। ନିଜ ପ୍ରଥମ ଆଙ୍ଗୁଠିର ବ୍ୟବହାର କରନ୍ତୁ।" @@ -807,10 +807,10 @@ "ଏକ ସମ୍ପ୍ରତି ପାସ୍‌ୱର୍ଡ ବ୍ୟବହାର କରିବାକୁ ଡିଭାଇସ୍‌ ଆଡମିନ୍‌ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ" "ସଂଖ୍ୟାର କ୍ରମବୃଦ୍ଧି, କ୍ରମହ୍ରାସ, କିମ୍ବା ପୁନରାବୃତ୍ତ କ୍ରମ ଅନୁମୋଦିତ ନୁହେଁ" "ନିଶ୍ଚିତ କରନ୍ତୁ" - "ବାତିଲ୍‌ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" "ଖାଲି କରନ୍ତୁ" "ପୂର୍ବରୁ ସ୍କ୍ରିନ୍‍ ଲକ୍‌ ପରିବର୍ତ୍ତନ କରାଯାଇଥିଲା। ନୂତନ ସ୍କ୍ରିନ୍ ଲକ୍‌କୁ ଚେଷ୍ଟା କରନ୍ତୁ।" - "ବାତିଲ୍‌" + "ବାତିଲ" "ଆଗକୁ" "ସେଟଅପ୍‌ ସମ୍ପୂର୍ଣ୍ଣ।" "ଡିଭାଇସ୍‌ ଆଡମିନ୍‌ ଆପ୍‌" @@ -1136,7 +1136,7 @@ "ନେଟ୍‌ୱର୍କ ଭୁଲିଯିବାରେ ବିଫଳ ହେଲା" "ସେଭ୍‍ କରନ୍ତୁ" "ନେଟୱାର୍କ୍‌ ସେଭ୍‌ କରି ପାରିଲା ନାହିଁ" - "ବାତିଲ୍‌" + "ବାତିଲ" "ନେଟୱର୍କକୁ ଭୁଲିଯିବେ?" "ଏହି ନେଟ୍‌ୱର୍କ ପାଇଁ ଥିବା ସବୁ ପାସ୍‌ୱର୍ଡକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ" @@ -1168,7 +1168,7 @@ "IP ସେଟିଂସ" "ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ୱାଇ-ଫାଇର ଉନ୍ନତ ସେଟିଂସ ଉପଲବ୍ଧ ନାହିଁ" "ସେଭ୍‌ କରନ୍ତୁ" - "ବାତିଲ୍‌ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" "ଏକ ବୈଧ IP ଠିକଣା ଟାଇପ୍‌ କରନ୍ତୁ" "ଏକ ମାନ୍ୟ ଗେଟ୍‌ୱେ ଠିକଣା ଟାଇପ୍‌ କରନ୍ତୁ" "ଏକ ବୈଧ DNS ଠିକଣା ଟାଇପ୍‌ କରନ୍ତୁ।" @@ -1190,8 +1190,8 @@ "ବିଚ୍ଛିନ୍ନ କରିବେ?" "ଯଦି ଆପଣ ବିଚ୍ଛିନ୍ନ କରନ୍ତି, %1$s ସହ ଆପଣଙ୍କ ସଂଯୋଗ ଶେଷ ହୋଇଯିବ।" "ଯଦି ଆପଣ ବିଚ୍ଛିନ୍ନ କରନ୍ତି, %1$s ଏବଂ %2$s ଟି ଅନ୍ୟ ଡିଭାଇସ୍‌ ସହ ଆପଣଙ୍କ ସଂଯୋଜନା ଶେଷ ହେବ।" - "ନିମନ୍ତ୍ରଣକୁ ବାତିଲ୍‌ କରିବେ?" - "%1$s ସହ ସଂଯୋଗ କରିବାକୁ ନିମନ୍ତ୍ରଣକୁ ଆପଣ ବାତିଲ୍‌ କରିବାକୁ ଚାହାଁନ୍ତି କି?" + "ନିମନ୍ତ୍ରଣକୁ ବାତିଲ କରିବେ?" + "%1$s ସହ ସଂଯୋଗ କରିବାକୁ ନିମନ୍ତ୍ରଣକୁ ଆପଣ ବାତିଲ କରିବାକୁ ଚାହାଁନ୍ତି କି?" "ଏହି ଗ୍ରୁପ୍‌କୁ ଭୁଲିଯିବେ?" "ୱାଇ-ଫାଇ ହଟସ୍ପଟ୍‌" "ଅନ୍ୟ ଡିଭାଇସଗୁଡ଼ିକ‌ ସହ ଇଣ୍ଟରନେଟ୍‌ କିମ୍ବା ବିଷୟବସ୍ତୁ ସେୟାର୍ କରୁନାହିଁ" @@ -1496,7 +1496,7 @@ "PIN ଅକ୍ଷମ କରିହେବ ନାହିଁ।" "PIN ସକ୍ଷମ କରିହେବ ନାହିଁ।" "ଠିକ ଅଛି" - "ବାତିଲ୍‌ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" "ଏକାଧିକ ସିମ୍‌ ମିଳିଛି" "ମୋବାଇଲ୍‌ ଡାଟା ପାଇଁ ନିଜ ପସନ୍ଦର SIM ବାଛନ୍ତୁ।" "ମୋବାଇଲ୍ ଡାଟା ପାଇଁ %1$s ବ୍ୟବହାର କରିବେ?" @@ -1681,7 +1681,7 @@ "ଡାଟା ନେବାକୁ ଆପଣଙ୍କୁ ଉପଯୋଗକର୍ତ୍ତା ^1 ଅନଲକ୍‌ କରିବା ଆବଶ୍ୟକ।" "^1 ଚଳାଉଛି…" "ଘୁଞ୍ଚାଇବାବେଳେ ^1କୁ କାଢ଼ନ୍ତୁ ନାହିଁ। \n\nଏହି ଡିଭାଇସ୍‌ରେ ଥିବା ^2 ଆପ୍‌, ଏହି କାର୍ଯ୍ୟ ନସରିବା ପର୍ଯ୍ୟନ୍ତ କାମ କରିବ ନାହିଁ।" - "ଘୁଞ୍ଚାଇବା କ୍ୟାନ୍ସଲ୍‌ କରନ୍ତୁ" + "ଘୁଞ୍ଚାଇବା ବାତିଲ କରନ୍ତୁ" "ଏହି ^1 ଧୀର ଥିବା ପରି ଜଣାପଡୁଛି। \n\nଆପଣ ଜାରିରଖିପାରିବେ, କିନ୍ତୁ ଏହି ଅବସ୍ଥାନକୁ ଚଳାଯାଇଥିବା ଆପ୍‌ଗୁଡ଼ିକ ରହି ରହି ଚାଲିପାରେ ଏବଂ ଡାଟା ସ୍ଥାନାନ୍ତର ବହୁତ ସମୟ ନେଇପାରେ। \n\nଉନ୍ନତ କାର୍ଯ୍ୟଦକ୍ଷତା ପାଇଁ ଏକ ଦ୍ରୁତତ୍ତମ ^1 ପାଇଁ ବିବେଚନା କରନ୍ତୁ।" "ଆପଣ କିପରି ଏହି ^1କୁ ବ୍ୟବହାର କରିବେ?" "ଅତିରିକ୍ତ ଟାବଲେଟ୍ ଷ୍ଟୋରେଜ୍ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ" @@ -1751,7 +1751,7 @@ "APN ଡିଲିଟ୍‌ କରନ୍ତୁ" "ନୂଆ APN" "ସେଭ୍‌ କରନ୍ତୁ" - "ବାତିଲ୍ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" "ନାମ ସ୍ଥାନ ଶୂନ୍ୟ ରହିପାରିବ ନାହିଁ।" "APNକୁ ଖାଲି ରଖାଯାଇପାରିବ ନାହିଁ।" @@ -1768,7 +1768,7 @@ "ଏହା:\n\n"
  • "ୱାଇ-ଫାଇ"
  • \n
  • "ମୋବାଇଲ ଡାଟା"
  • \n
  • "ବ୍ଲୁଟୁଥ୍‍"
  • " ସମେତ ସମସ୍ତ ନେଟୱାର୍କ ସେଟିଂସକୁ ରିସେଟ କରିବ"
    "ଖାଲି କରନ୍ତୁ" "ଡାଉନଲୋଡ୍ ହୋଇଥିବା SIMକୁ ଖାଲି କରନ୍ତୁ" - "ଏହା କୌଣସି ମୋବାଇଲ ସେବା ପ୍ଲାନକୁ ବାତିଲ୍ କରିବ ନାହିଁ। ରିପ୍ଲେସମେଣ୍ଟ SIMଗୁଡ଼ିକୁ ଡାଉନଲୋଡ କରିବା ପାଇଁ ଆପଣଙ୍କ କ୍ୟାରିଅର ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।" + "ଏହା କୌଣସି ମୋବାଇଲ ସେବା ପ୍ଲାନକୁ ବାତିଲ କରିବ ନାହିଁ। ରିପ୍ଲେସମେଣ୍ଟ SIMଗୁଡ଼ିକୁ ଡାଉନଲୋଡ କରିବା ପାଇଁ ଆପଣଙ୍କ କ୍ୟାରିଅର ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।" "ସେଟିଂସ ରିସେଟ କରନ୍ତୁ" "ସମସ୍ତ ନେଟୱାର୍କ ସେଟିଂସ ରିସେଟ କରିବେ? ଏହାକୁ ଆପଣ ଆଉ ପୂର୍ବବତ୍ କରିପାରିବେ ନାହିଁ।" "ସମସ୍ତ ନେଟୱାର୍କ ସେଟିଂସ ରିସେଟ ଏବଂ ଡାଉନଲୋଡ ହୋଇଥିବା SIMକୁ ଖାଲି କରିବେ କି? ଆପଣ ଏହି କାର୍ଯ୍ୟକୁ ପୂର୍ବବତ୍ କରିପାରିବେ ନାହିଁ।" @@ -1786,7 +1786,7 @@ \n\n"ଏହି ଡିଭାଇସରେ ଅନ୍ୟ ଉପଯୋଗକର୍ତ୍ତା ଅଛନ୍ତି।\n"
  • "ସଙ୍ଗୀତ"
  • \n
  • "ଫଟୋ"
  • \n
  • "ଅନ୍ୟ ଉପଯୋଗକର୍ତ୍ତା ଡାଟା"
  • "eSIMs"
  • - \n\n"ଏହା ଆପଣଙ୍କ ମୋବାଇଲ ସେବା ପ୍ଲାନକୁ ବାତିଲ୍ କରିବ ନାହିଁ।" + \n\n"ଏହା ଆପଣଙ୍କ ମୋବାଇଲ ସେବା ପ୍ଲାନକୁ ବାତିଲ କରିବ ନାହିଁ।" \n\n"ସଙ୍ଗୀତ, ଛବି ଓ ଅନ୍ୟ ଉପଯୋଗକର୍ତ୍ତା ଡାଟାକୁ ଖାଲି କରିବାକୁ ""USB ଷ୍ଟୋରେଜ୍""କୁ ଖାଲି କରିବା ଆବଶ୍ୟକ।" \n\n"ସଙ୍ଗୀତ, ଛବି ଓ ଅନ୍ୟ ଉପଯୋଗକର୍ତ୍ତା ଡାଟାକୁ ଖାଲି କରିବାକୁ ""SD କାର୍ଡ""କୁ ଖାଲି କରିବା ଆବଶ୍ୟକ।" "USB ଷ୍ଟୋରେଜ୍‌କୁ ଲିଭାନ୍ତୁ" @@ -1896,7 +1896,7 @@ "ଡିଭାଇସର ଲୋକେସନ୍ ଆବଶ୍ୟକ" "ଆପଣଙ୍କ ଲୋକେସନ ବ୍ୟବହାର କରି ଟାଇମ ଜୋନ ସେଟ କରିବାକୁ ଲୋକେସନ ଚାଲୁ କରନ୍ତୁ, ତା\'ପରେ ଟାଇମ ଜୋନ ସେଟିଂସ ଅପଡେଟ କରନ୍ତୁ" "ଲୋକେସନ ସେଟିଂସ" - "ବାତିଲ୍ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" "ସ୍ୱଚାଳିତ ଟାଇମ୍ ଜୋନ୍ ବନ୍ଦ ଅଛି" "ଲୋକେସନ୍ ଟାଇମ୍ ଜୋନ୍ ଚିହ୍ନଟକରଣ ଅକ୍ଷମ କରାଯାଇଛି" "ଲୋକେସନ୍ ଟାଇମ୍ ଜୋନ୍ ଚିହ୍ନଟକରଣ ସମର୍ଥିତ ନୁହେଁ" @@ -2340,7 +2340,7 @@ "ଏହା ଆପଣଙ୍କ କୀବୋର୍ଡକୁ ଧୀର କରିପାରେ" "ଆପଣଙ୍କ ସ୍କ୍ରିନର ଅଂଶକୁ ମ୍ୟାଗ୍ନିଫାଏ କରିବା ପାଇଁ ତିନିଥର-ଟାପ ବିକଳ୍ପକୁ ବ୍ୟବହାର କରିବା ସମୟରେ, ଆପଣ କୀବୋର୍ଡରେ ସମସ୍ୟାଗୁଡ଼ିକୁ ନୋଟିସ କରିପାରନ୍ତି।\n\nଏହାକୁ ଏଡ଼ାଇବା ପାଇଁ, ଆପଣ ଆପଣଙ୍କ ମ୍ୟାଗ୍ନିଫିକେସନ ସର୍ଟକଟକୁ ତିନିଥର-ଟାପରୁ ଅନ୍ୟ ଏକ ବିକଳ୍ପକୁ ପରିବର୍ତ୍ତନ କରିପାରିବେ।\n""ସେଟିଂ ପରିବର୍ତ୍ତନ କରନ୍ତୁ" "ଯେ କୌଣସି ମତେ ଜାରି ରଖନ୍ତୁ" - "ବାତିଲ୍ କର" + "ବାତିଲ କର" "ମାଗ୍ନିଫିକେସନ ସେଟିଂସ" "ଟ୍ରିପଲ୍‌-ଟାପ୍‌ ଦ୍ୱାରା ମାଗ୍ନିଫାଏ କରନ୍ତୁ" "ସର୍ଟକଟ୍ ସାହାଯ୍ୟରେ ମାଗ୍ନିଫାଏ କରନ୍ତୁ" @@ -2625,7 +2625,7 @@ "ଅନୁମତି" "ଅଗ୍ରାହ୍ୟ" "ବନ୍ଦ କରନ୍ତୁ" - "ବାତିଲ୍" + "ବାତିଲ" "%1$sକୁ ବନ୍ଦ କରିବେ?" "%1$sକୁ ଟାପ୍‍ କରିବା ଦ୍ୱାରା %2$s ବନ୍ଦ ହୋଇଯିବ।" "କୌଣସି ସେବା ସଂସ୍ଥାପିତ ହୋଇନାହିଁ" @@ -2676,7 +2676,7 @@ "ପ୍ରିଣ୍ଟ ଜବ୍‌" "ପ୍ରିଣ୍ଟ ଜବ୍‌" "ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ" - "ବାତିଲ୍‌" + "ବାତିଲ" "%1$s\n%2$s" "%1$s କନଫିଗର୍‌ କରାଯାଉଛି" "%1$s ପ୍ରିଣ୍ଟ ହେଉଛି" @@ -2792,7 +2792,7 @@ "ପ୍ରତିବନ୍ଧକ ହଟାଇ ଦେବେ?" "ଏହି ଆପ୍‌ ବ୍ୟାକ୍‌ଗ୍ରାଉଣ୍ଡରେ ବ୍ୟାଟେରୀ ବ୍ୟବହାର କରିପାରିବ। ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ଅନୁମାନ କରିଥିବା ସମୟର ପୂର୍ବରୁ ହିଁ ସରିଯାଇପାରେ।" "କାଢ଼ିଦିଅନ୍ତୁ" - "ବାତିଲ୍" + "ବାତିଲ" "ଆପଣଙ୍କର ଆପ୍ସ ସାଧାରଣ ଭାବେ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରୁଛି। ଯଦି ଆପ୍ସ ଅଧିକ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରେ, ତେବେ ଆପଣଙ୍କ ଫୋନ୍ ପଦକ୍ଷେପ ନେବା ପାଇଁ ଆପଣଙ୍କୁ ପରାମର୍ଶ ଦେବ। \n\n ବ୍ୟାଟେରୀ ଅଧିକ ଖର୍ଚ୍ଚ ହେଉଥିଲେ ଆପଣ ସର୍ବଦା ବ୍ୟାଟେରୀ ସେଭର୍‌କୁ ଚାଲୁ କରିପାରିବେ।" "ଆପଣଙ୍କର ଆପଗୁଡ଼ିକ ସାଧାରଣ ଭାବେ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରୁଛନ୍ତି। ଯଦି ଆପଗୁଡ଼ିକ ଅଧିକ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରନ୍ତି, ତେବେ ଆପଣଙ୍କ ଟାବଲେଟ୍ ପଦକ୍ଷେପ ନେବା ପାଇଁ ଆପଣଙ୍କୁ ପରାମର୍ଶ ଦେବ। \n\n ବ୍ୟାଟେରୀ ଅଧିକ ଖର୍ଚ୍ଚ ହେଉଥିଲେ ଆପଣ ସର୍ବଦା ବ୍ୟାଟେରୀ ସେଭର୍‌କୁ ଚାଲୁ କରିପାରିବେ।" "ଆପଣଙ୍କର ଆପ୍ ସାଧାରଣ ଭାବେ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରୁଛି। ଯଦି ଆପ୍ ଅଧିକ ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କରନ୍ତି, ତେବେ ଡିଭାଇସ୍ ପଦକ୍ଷେପ ନେବା ପାଇଁ ଆପଣଙ୍କୁ ପରାମର୍ଶ ଦେବ। \n\n ବ୍ୟାଟେରୀ ଅଧିକ ଖର୍ଚ୍ଚ ହେଉଥିଲେ ଆପଣ ସର୍ବଦା ବ୍ୟାଟେରୀ ସେଭର୍‌କୁ ଚାଲୁ କରିପାରିବେ।" @@ -3032,7 +3032,7 @@ "Voices ଇନ୍‌ଷ୍ଟଲ୍‍ କରନ୍ତୁ" "ଭଏସ୍‌ ଇନ୍‌ଷ୍ଟଲ୍‌ କରିବାକୁ %s ଆପ୍‌ ଜାରି ରଖନ୍ତୁ" "ଆପ୍‌ ଖୋଲନ୍ତୁ" - "ବାତିଲ୍‌" + "ବାତିଲ" "ରିସେଟ୍‌ କରନ୍ତୁ" "ଚଲାନ୍ତୁ" "VPN" @@ -3162,7 +3162,7 @@ "ବ୍ୟାକଅପ ସେଟିଂସ" "ମୋ ସେଟିଂସର ବ୍ୟାକଅପ ନିଅ" "ବର୍ତ୍ତମାନ ସିଙ୍କ କରନ୍ତୁ" - "ସିଙ୍କ୍‌ ବାତିଲ୍‌‌ କରନ୍ତୁ" + "ସିଙ୍କ୍‌ ବାତିଲ କରନ୍ତୁ" " %1$s ବର୍ତ୍ତମାନ ସିଙ୍କ କରିବାକୁ ଟାପ୍‌ କରନ୍ତୁ" "Gmail" @@ -3302,7 +3302,7 @@ "ସର୍ବଦା-ଅନ୍‌ VPN ପାଇଁ ଏକ DNS ସର୍ଭର ଉଲ୍ଲେଖ କରିବା ଜରୁରୀ" "ସର୍ବଦା ଚାଲୁଥିବା VPN ପାଇଁ DNS ସର୍ଭର୍ ଠିକଣା ସଂଖ୍ୟା ବିଶିଷ୍ଟ ହୋଇଥିବା ଦରକାର" "ଏଣ୍ଟର୍‌ କରାଯାଇଥିବା ସୂଚନା ସର୍ବଦା-ଅନ୍‌ VPNକୁ ସପୋର୍ଟ କରେ ନାହିଁ" - "ବାତିଲ୍‌ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" "ଖାରଜ" "ସେଭ୍‌ କରନ୍ତୁ" "ସଂଯୋଗ କରନ୍ତୁ" @@ -3899,7 +3899,7 @@ "ଡିଭାଇସ୍ ପାଇଁ ବବଲ୍ ଚାଲୁ କରିବେ?" "ଏହି ଆପ୍ ପାଇଁ ବବଲ୍ ଚାଲୁ କଲେ ଆପଣଙ୍କ ଡିଭାଇସ୍ ପାଇଁ ମଧ୍ୟ ବବଲଗୁଡ଼ିକ ଚାଲୁ ହୋଇଯିବ।\n\n ଏହା ବବଲକୁ ଅନୁମତି ଦେଇ ଥିବା ଅନ୍ୟ ଆପ୍ କିମ୍ବା ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକୁ ପ୍ରଭାବିତ କରେ।" "ଚାଲୁ କରନ୍ତୁ" - "ବାତିଲ୍ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" "ଚାଲୁ ଅଛି / ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଫ୍ଲୋଟିଂ ଆଇକନଗୁଡ଼ିକ ଭାବେ ଦେଖାଯାଇପାରିବ" "ବବଲଗୁଡ଼ିକ ଦେଖାଇବାକୁ ଆପଗୁଡ଼ିକୁ ଅନୁମତି ଦିଅନ୍ତୁ" "ଅନ୍ୟ ଆପଗୁଡ଼ିକର ଶୀର୍ଷରେ କିଛି ବାର୍ତ୍ତାଳାପ ଫ୍ଲୋଟିଂ ଆଇକନ୍ ପରି ଦେଖାଯିବ" @@ -4042,7 +4042,7 @@ "ଏହା \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\"କୁ ଚାଲୁ କିମ୍ବା ବନ୍ଦ କରିପାରିବ ଏବଂ ସମ୍ବନ୍ଧିତ ସେଟିଂସକୁ ପରିବର୍ତ୍ତନ କରିପାରିବ।" "%1$s ପାଇଁ ଯଦି ଆପଣ ବିଜ୍ଞପ୍ତି ଆକ୍ସେସ୍‌କୁ ବନ୍ଦ କରୁଛନ୍ତି, ତେବେ \"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ବିକଳ୍ପ ଆକ୍ସେସ୍‌ ମଧ୍ୟ ବନ୍ଦ ହୋଇଯାଇପାରେ।" "ବନ୍ଦ କରନ୍ତୁ" - "ବାତିଲ୍" + "ବାତିଲ" "ଅନୁମତି ଦିଆଯାଇଥିବା ବିଜ୍ଞପ୍ତିର ପ୍ରକାର" "ରିଅଲ୍-ଟାଇମ୍" "ବ୍ୟବହାରରେ ଥିବା ଆପ୍, ନାଭିଗେସନ୍, ଫୋନ୍ କଲ୍ ଏବଂ ଆହୁରି ଅନେକ କିଛିରୁ ଚାଲୁଥିବା କମ୍ୟୁନିକେସନ୍" @@ -4371,7 +4371,7 @@ "ଠିକ୍ ଅଛି" "ଯାଞ୍ଚ କରାଯାଇଥିବା ଲିଙ୍କଗୁଡ଼ିକର ତାଲିକା ଦେଖାନ୍ତୁ" "ଅନ୍ୟ ସମର୍ଥିତ ଲିଙ୍କଗୁଡ଼ିକ ପାଇଁ ଯାଞ୍ଚ କରାଯାଉଛି…" - "ବାତିଲ୍ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" %dଟି ସମର୍ଥିତ ଲିଙ୍କ୍ %dଟି ସମର୍ଥିତ ଲିଙ୍କ୍ @@ -5360,7 +5360,7 @@ "ଏହି SIMକୁ ଅକ୍ଷମ କରିବା ପାଇଁ SIM କାର୍ଡକୁ କାଢ଼ି ଦିଅନ୍ତୁ" "%1$sକୁ ସକ୍ରିୟ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ" "%1$sରେ ସ୍ବିଚ୍ କରିବେ କି?" - "ଏକ ସମୟରେ କେବଳ ଗୋଟିଏ ଡାଉନଲୋଡ୍ ହୋଇଥିବା SIM ସକ୍ରିୟ ହୋଇପାରିବ।\n\n %1$sକୁ ସ୍ୱିଚ୍ କରିବା ଦ୍ୱାରା ଆପଣଙ୍କର %2$s ସେବା ବାତିଲ୍ ହୋବ ନାହିଁ।" + "ଏକ ସମୟରେ କେବଳ ଗୋଟିଏ ଡାଉନଲୋଡ ହୋଇଥିବା SIM ସକ୍ରିୟ ହୋଇପାରିବ।\n\n %1$sକୁ ସ୍ୱିଚ୍ କରିବା ଦ୍ୱାରା ଆପଣଙ୍କର %2$s ସେବା ବାତିଲ ହୋବ ନାହିଁ।" "%1$sକୁ ଯାଆନ୍ତୁ" "SIM ଖାଲି କରନ୍ତୁ" "SIMକୁ ଖାଲି କରିହେବ ନାହିଁ" @@ -5394,13 +5394,13 @@ "%1$sକୁ ସ୍ୱିଚ୍ କରିବେ?" "SIM କାର୍ଡ ବ୍ୟବହାର କରିବାକୁ ସ୍ୱିଚ୍ କରିବେ?" "%1$s ବ୍ୟବହାର କରିବେ?" - "ଥରକେ କେବଳ ଗୋଟିଏ SIMକୁ ସକ୍ରିୟ କରାଯାଇପାରିବ।\n\n%1$sକୁ ସ୍ୱିଚ୍ କରିବା ଦ୍ୱାରା ଆପଣଙ୍କର %2$s ସେବା ବାତିଲ୍ ହେବ ନାହିଁ।" - "ଥରକେ କେବଳ ଗୋଟିଏ ଡାଉନଲୋଡ୍ କରାଯାଇଥିବା SIMକୁ ସକ୍ରିୟ କରାଯାଇପାରିବ।\n\n %1$sକୁ ସ୍ୱିଚ୍ କରିବା ଦ୍ୱାରା ଆପଣଙ୍କର %2$s ସେବା ବାତିଲ୍ ହେବ ନାହିଁ।" - "ଥରକେ କେବଳ ଗୋଟିଏ SIMକୁ ସକ୍ରିୟ କରାଯାଇପାରିବ।\n\nସ୍ୱିଚ୍ କରିବା ଦ୍ୱାରା ଆପଣଙ୍କର %1$s ସେବା ବାତିଲ୍ ହେବ ନାହିଁ।" + "ଥରକେ କେବଳ ଗୋଟିଏ SIMକୁ ସକ୍ରିୟ କରାଯାଇପାରିବ।\n\n%1$sକୁ ସ୍ୱିଚ୍ କରିବା ଦ୍ୱାରା ଆପଣଙ୍କର %2$s ସେବା ବାତିଲ ହେବ ନାହିଁ।" + "ଥରକେ କେବଳ ଗୋଟିଏ ଡାଉନଲୋଡ କରାଯାଇଥିବା SIMକୁ ସକ୍ରିୟ କରାଯାଇପାରିବ।\n\n %1$sକୁ ସ୍ୱିଚ୍ କରିବା ଦ୍ୱାରା ଆପଣଙ୍କର %2$s ସେବା ବାତିଲ ହେବ ନାହିଁ।" + "ଥରକେ କେବଳ ଗୋଟିଏ SIMକୁ ସକ୍ରିୟ କରାଯାଇପାରିବ।\n\nସ୍ୱିଚ୍ କରିବା ଦ୍ୱାରା ଆପଣଙ୍କର %1$s ସେବା ବାତିଲ ହେବ ନାହିଁ।" "ଆପଣ ଥରକେ 2ଟି SIM ବ୍ୟବହାର କରିପାରିବେ। %1$s ବ୍ୟବହାର କରିବା ପାଇଁ, ଅନ୍ୟ ଏକ SIM ବନ୍ଦ କରନ୍ତୁ।" "%1$sକୁ ସ୍ୱିଚ୍ କରନ୍ତୁ" "%1$s ବନ୍ଦ କରନ୍ତୁ" - "ଏକ SIMକୁ ବନ୍ଦ କରିବା ଫଳରେ ଆପଣଙ୍କ ସେବା ବାତିଲ୍ ହେବ ନାହିଁ" + "ଏକ SIMକୁ ବନ୍ଦ କରିବା ଫଳରେ ଆପଣଙ୍କ ସେବା ବାତିଲ ହେବ ନାହିଁ" "ନେଟୱାର୍କ ସହ ସଂଯୋଗ କରାଯାଉଛି…" "କଲ ଏବଂ ମେସେଜଗୁଡ଼ିକ ପାଇଁ %1$sକୁ ସ୍ୱିଚ କରାଯାଉଛି…" "କ୍ୟାରିଅରକୁ ସ୍ୱିଚ୍ କରାଯାଇପାରିବ ନାହିଁ" @@ -5418,7 +5418,7 @@ "ହଁ" "ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ" "ନା, ଧନ୍ୟବାଦ" - "ବାତିଲ୍ କରନ୍ତୁ" + "ବାତିଲ କରନ୍ତୁ" "ସ୍ୱିଚ୍ କରନ୍ତୁ" "SIMକୁ ସକ୍ରିୟ କରାଯାଇପାରିବ ନାହିଁ" "SIMକୁ କାଢ଼ି ପୁଣି ଭର୍ତ୍ତି କରନ୍ତୁ। ଯଦି ସମସ୍ୟା ଜାରି ରହେ, ତେବେ ଆପଣଙ୍କ ଡିଭାଇସକୁ ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ।" diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml index 2b2bc44cb73..308a1b0d1a6 100644 --- a/res/values-pa/strings.xml +++ b/res/values-pa/strings.xml @@ -2813,8 +2813,8 @@ "ਐਪਾਂ ਵੱਲੋਂ ਜ਼ਿਆਦਾ ਬੈਟਰੀ ਵਰਤੇ ਜਾਣ ਦਾ ਪਤਾ ਲਗਾਇਆ ਜਾ ਰਿਹਾ ਹੈ" "ਬੰਦ" - %1$d ਐਪ ਪ੍ਰਤੀਬੰਧਿਤ - %1$d ਐਪਾਂ ਪ੍ਰਤੀਬੰਧਿਤ + %1$d ਐਪ ਪ੍ਰਤਿਬੰਧਿਤ + %1$d ਐਪਾਂ ਪ੍ਰਤਿਬੰਧਿਤ "^1"" ""%""" "ਬੈਟਰੀ ਮੀਟਰ ਨੂੰ ਪੜ੍ਹਨ ਵਿੱਚ ਸਮੱਸਿਆ ਹੋ ਰਹੀ ਹੈ।" @@ -4863,8 +4863,8 @@ "ਓਵਰਲੇ ਨੂੰ ਲਾਗੂ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ" "ਵਿਸ਼ੇਸ਼ ਐਪ ਪਹੁੰਚ" - %d ਐਪ ਅਣ-ਪ੍ਰਤੀਬੰਧਿਤ ਡਾਟੇ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀ ਹੈ - %d ਐਪਾਂ ਅਣ-ਪ੍ਰਤੀਬੰਧਿਤ ਡਾਟੇ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ + %d ਐਪ ਅਣ-ਪ੍ਰਤਿਬੰਧਿਤ ਡਾਟੇ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀ ਹੈ + %d ਐਪਾਂ ਅਣ-ਪ੍ਰਤਿਬੰਧਿਤ ਡਾਟੇ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ "ਹੋਰ ਦੇਖੋ" "ShortcutManager ਰੇਟ-ਲਿਮਿਟਿੰਗ ਰੀਸੈੱਟ ਕਰੋ" diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 0bee990eee3..a94e4fc4a90 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -3369,7 +3369,7 @@ "Adăugați un profil VPN" "Editați profilul" "Ștergeți profilul" - "Rețea VPN activată permanent" + "VPN activat permanent" "Nicio rețea VPN adăugată" "Mențineți conexiunea la rețelele VPN" "Nu este acceptată de această aplicație" diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index be5ec87b34e..932821dd913 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -484,7 +484,7 @@ "Keď zacítite vibráciu, zdvihnite prst" "Prejdite na miesto s jemnejším osvetlením a skúste to znova" "Dosiahli ste maximálny počet pokusov" - "Odomykajte tablet alebo overujte svoju totožnosť odtlačkom prsta, napríklad pri prihlasovaní do aplikácií" + "Odtlačkom prsta môžete odomknúť tablet alebo overiť svoju totožnosť, napríklad pri prihlasovaní do nejakej aplikácie" "Odomykajte zariadenie alebo overujte svoju totožnosť odtlačkom prsta, napríklad pri prihlasovaní do aplikácií" "Odomykajte telefón alebo overujte svoju totožnosť odtlačkom prsta, napríklad pri prihlasovaní do aplikácií" "Odomknutie tvárou a odtlačkom prsta" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 1b697b39e10..a4125812a6c 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -5958,7 +5958,7 @@ "Ліміт швидкості завантаження в мережі" "Налаштуйте ліміт вхідної пропускної спроможності мережі, який застосовуватиметься до всіх мереж, що забезпечують інтернет-з’єднання." "Налаштувати ліміт швидкості завантаження в мережі" - "Немає ліміту" + "Немає обмеження" "Трансляція" "Змінити додаток для трансляції на %1$s" "Слухайте трансляції з пристроїв поблизу" diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml index 310dd620098..2bfc4c2487c 100644 --- a/res/values-uz/strings.xml +++ b/res/values-uz/strings.xml @@ -476,7 +476,7 @@ "Barmoqni tebranishni sezganda oling" "Yoriqroq joyga borib, qaytadan urining" "Urinishlar soni qolmadi" - "Planshetni qulfdan chiqarish yoki ilovalarga hisobingiz bilan kirishda shaxsingizni tasdiqlash uchun barmoq izingizdan foydalaning" + "Planshetingiz qulfini ochish yoki ilovalarga hisobingiz bilan kirishda shaxsingizni tasdiqlash uchun barmoq izingizdan foydalaning" "Qurilmani qulfdan chiqarish yoki ilovalarga hisobingiz bilan kirishda shaxsingizni tasdiqlash uchun barmoq izingizdan foydalaning" "Telefonni qulfdan chiqarish yoki ilovalarga hisobingiz bilan kirishda shaxsingizni tasdiqlash uchun barmoq izingizdan foydalaning" "Yuz va barmoq izi bilan ochish" diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 80a5a0d364e..45f500c5bdb 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -2759,7 +2759,7 @@ "Mức sử dụng pin cao" "Xem các ứng dụng có mức sử dụng pin cao nhất" "Chức năng sạc tạm thời bị hạn chế" - "Để kéo dài tuổi thọ pin. Tìm hiểu thêm." + "Để kéo dài thời lượng pin. Tìm hiểu thêm." "Tiếp tục sạc" "Trong một số điều kiện, chẳng hạn như nhiệt độ cao và thời gian sạc lâu, mức sạc có thể bị hạn chế ở %1$s để duy trì độ bền của pin.\n\nKhi các điều kiện đó chấm dứt, điện thoại của bạn sẽ tự động sạc như bình thường." "Trong một số điều kiện, chẳng hạn như nhiệt độ cao và thời gian sạc lâu, mức sạc có thể bị hạn chế ở %1$s để duy trì độ bền của pin.\n\nKhi các điều kiện đó chấm dứt, điện thoại của bạn sẽ tự động sạc như bình thường." @@ -3154,7 +3154,7 @@ "Dữ liệu nền" "Ứng dụng có thể đ.bộ hóa, gửi & nhận dữ liệu bất kỳ lúc nào" "Tắt dữ liệu nền?" - "Tắt dữ liệu nền sẽ kéo dài tuổi thọ pin và giảm mức sử dụng dữ liệu. Một số ứng dụng vẫn có thể sử dụng kết nối dữ liệu nền." + "Tắt dữ liệu nền sẽ kéo dài thời lượng pin và giảm mức sử dụng dữ liệu. Một số ứng dụng vẫn có thể sử dụng kết nối dữ liệu nền." "Tự động đồng bộ hóa dữ liệu ứng dụng" "Tính năng đồng bộ hóa đang BẬT" "Tính năng đồng bộ hóa đang TẮT" @@ -5245,9 +5245,9 @@ "Đang chuyển đổi…" "Thực hiện cuộc gọi trên" "Không thể thay đổi APN (Tên điểm truy cập) này." - "Tăng tuổi thọ pin của máy tính bảng" - "Tăng tuổi thọ pin của thiết bị" - "Tăng tuổi thọ pin của điện thoại" + "Tăng thời lượng pin của máy tính bảng" + "Tăng thời lượng pin của thiết bị" + "Tăng thời lượng pin của điện thoại" "Ngăn đổ chuông" "Nhấn đồng thời nút Nguồn và nút Tăng âm lượng để" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index d7a39ad801c..006e784ddaf 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -476,7 +476,7 @@ "请在感觉到振动后抬起手指" "请移到光线较柔和的地方,然后重试" "您已达到尝试次数上限" - "您可以使用指纹解锁平板电脑或验证自己的身份,例如在登录应用时" + "您可以使用指纹解锁平板电脑,或验证自己的身份(例如在登录应用时)" "您可以使用指纹解锁设备或验证自己的身份,例如在登录应用时" "您可以使用指纹解锁手机或验证自己的身份,例如在登录应用时" "人脸解锁和指纹解锁"