From b35b78b3b61013d8a26045981aff8bc32127bfaa Mon Sep 17 00:00:00 2001 From: Amy Hsu Date: Tue, 19 May 2020 20:13:02 +0800 Subject: [PATCH 1/9] Add Smooth Display option to developer in Settings Force to the highest refresh rate. Bug: 137064289 Test:$ adb root $ adb shell "echo 1 > /d/tracing/events/sde/enable" $ adb shell "echo 1 > /d/tracing/tracing_on" $ adb shell "cat /d/tracing/trace_pipe" | grep FPS Change-Id: Ia1f804cbc7e297a85591e6b0f293ca1014301b74 --- res/values/strings.xml | 4 + res/xml/development_settings.xml | 5 + .../DevelopmentSettingsDashboardFragment.java | 1 + ...cePeakRefreshRatePreferenceController.java | 132 +++++++++++++++++ ...akRefreshRatePreferenceControllerTest.java | 133 ++++++++++++++++++ 5 files changed, 275 insertions(+) create mode 100644 src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 910aba47c8d..7db903057b7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2752,6 +2752,10 @@ Smooth Display Automatically raises the refresh rate from 60 to 90 Hz for some content. Increases battery usage. + + Smooth Display + + Highest refresh rate for improved touch responsiveness & animation quality. Increases battery usage. Screen attention diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml index e8605894f6d..746a51c4b9d 100644 --- a/res/xml/development_settings.xml +++ b/res/xml/development_settings.xml @@ -256,6 +256,11 @@ android:title="@string/overlay_settings_title" android:summary="@string/overlay_settings_summary" /> + + DEFAULT_REFRESH_RATE; + } else { + return false; + } + } + + @Override + protected void onDeveloperOptionsSwitchDisabled() { + super.onDeveloperOptionsSwitchDisabled(); + Settings.System.putFloat(mContext.getContentResolver(), + Settings.System.MIN_REFRESH_RATE, NO_CONFIG); + + ((SwitchPreference) mPreference).setChecked(false); + } + + @VisibleForTesting + void forcePeakRefreshRate(boolean enable) { + final float peakRefreshRate = enable ? mPeakRefreshRate : NO_CONFIG; + Settings.System.putFloat(mContext.getContentResolver(), + Settings.System.MIN_REFRESH_RATE, peakRefreshRate); + } + + boolean isForcePeakRefreshRateEnabled() { + final float peakRefreshRate = Settings.System.getFloat(mContext.getContentResolver(), + Settings.System.MIN_REFRESH_RATE, NO_CONFIG); + + return peakRefreshRate >= mPeakRefreshRate; + } + + private float findPeakRefreshRate(Display.Mode[] modes) { + float peakRefreshRate = DEFAULT_REFRESH_RATE; + for (Display.Mode mode : modes) { + if (Math.round(mode.getRefreshRate()) > DEFAULT_REFRESH_RATE) { + peakRefreshRate = mode.getRefreshRate(); + } + } + + return peakRefreshRate; + } +} diff --git a/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java new file mode 100644 index 00000000000..2e93d5ef9ca --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2020 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.development; + +import static com.android.settings.development.ForcePeakRefreshRatePreferenceController.DEFAULT_REFRESH_RATE; +import static com.android.settings.development.ForcePeakRefreshRatePreferenceController.NO_CONFIG; +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.provider.Settings; + +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import android.util.Log; + +@RunWith(RobolectricTestRunner.class) +public class ForcePeakRefreshRatePreferenceControllerTest { + + @Mock + private SwitchPreference mPreference; + @Mock + private PreferenceScreen mScreen; + + private Context mContext; + private ForcePeakRefreshRatePreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = new ForcePeakRefreshRatePreferenceController(mContext); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + mController.displayPreference(mScreen); + } + + @Test + public void onPreferenceChange_preferenceChecked_shouldEnableForcePeak() { + mController.mPeakRefreshRate = 88f; + + mController.onPreferenceChange(mPreference, true); + + assertThat(Settings.System.getFloat(mContext.getContentResolver(), + Settings.System.MIN_REFRESH_RATE, NO_CONFIG)).isEqualTo(88f); + } + + @Test + public void onPreferenceChange_preferenceUnchecked_shouldDisableForcePeak() { + mController.mPeakRefreshRate = 88f; + + mController.onPreferenceChange(mPreference, false); + + assertThat(Settings.System.getFloat(mContext.getContentResolver(), + Settings.System.MIN_REFRESH_RATE, NO_CONFIG)).isEqualTo(NO_CONFIG); + } + + @Test + public void updateState_enableForcePeak_shouldCheckedToggle() { + mController.mPeakRefreshRate = 88f; + mController.forcePeakRefreshRate(true); + + mController.updateState(mPreference); + + verify(mPreference).setChecked(true); + } + + @Test + public void updateState_disableForcePeak_shouldUncheckedToggle() { + mController.mPeakRefreshRate = 88f; + mController.forcePeakRefreshRate(false); + + mController.updateState(mPreference); + + verify(mPreference).setChecked(false); + } + + @Test + @Config(qualifiers = "mcc999") + public void isAvailable_withConfigNoShow_returnUnsupported() { + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_refreshRateLargerThanDefault_returnTrue() { + mController.mPeakRefreshRate = DEFAULT_REFRESH_RATE + 1; + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void getAvailabilityStatus_refreshRateEqualToDefault_returnFalse() { + mController.mPeakRefreshRate = DEFAULT_REFRESH_RATE; + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void onDeveloperOptionsDisabled_shouldDisablePreference() { + mController.onDeveloperOptionsSwitchDisabled(); + + assertThat(Settings.System.getFloat(mContext.getContentResolver(), + Settings.System.MIN_REFRESH_RATE, -1f)).isEqualTo(NO_CONFIG); + assertThat(mPreference.isChecked()).isFalse(); + assertThat(mPreference.isEnabled()).isFalse(); + } +} From 257b9bcdfaeb9b0eb54adebcb17771517167a38d Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 29 Apr 2020 23:27:30 +0800 Subject: [PATCH 2/9] Remove schedule recheck logic from TetherService This change just remove unused code. Tethering no longer ask TetherService to schedule recheck (use #EXTRA_SET_ALARM) from Android Q. Intead Tethering (EntitlementManager) would schedule the recheck by itself. This change is necessary in order to move the resourcesout of the framework because TetherService needs to know when it need to re-run entitlement recheck from framework res (config_mobile_hotspot_provision_check_period). Bug: 146918263 Test: atest TetherSerivceTest Change-Id: Ie45859c19b96d0689c45dd610501fae0506742ff --- .../wifi/tether/HotspotOffReceiver.java | 55 -------- .../settings/wifi/tether/TetherService.java | 70 +--------- .../wifi/tether/TetherServiceTest.java | 130 ------------------ .../wifi/tether/TetherServiceTest.java | 46 +------ 4 files changed, 3 insertions(+), 298 deletions(-) delete mode 100644 src/com/android/settings/wifi/tether/HotspotOffReceiver.java delete mode 100644 tests/robotests/src/com/android/settings/wifi/tether/TetherServiceTest.java diff --git a/src/com/android/settings/wifi/tether/HotspotOffReceiver.java b/src/com/android/settings/wifi/tether/HotspotOffReceiver.java deleted file mode 100644 index fcbf888f865..00000000000 --- a/src/com/android/settings/wifi/tether/HotspotOffReceiver.java +++ /dev/null @@ -1,55 +0,0 @@ - -package com.android.settings.wifi.tether; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.wifi.WifiManager; -import android.util.Log; - -/** - * This receiver catches when quick settings turns off the hotspot, so we can - * cancel the alarm in that case. All other cancels are handled in tethersettings. - */ -public class HotspotOffReceiver extends BroadcastReceiver { - - private static final String TAG = "HotspotOffReceiver"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private Context mContext; - private boolean mRegistered; - - public HotspotOffReceiver(Context context) { - mContext = context; - } - - @Override - public void onReceive(Context context, Intent intent) { - if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(intent.getAction())) { - WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - if (wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED) { - if (DEBUG) Log.d(TAG, "TetherService.cancelRecheckAlarmIfNecessary called"); - // The hotspot has been turned off, we don't need to recheck tethering. - TetherService.cancelRecheckAlarmIfNecessary( - context, ConnectivityManager.TETHERING_WIFI); - } - } - } - - public void register() { - if (!mRegistered) { - mContext.registerReceiver(this, - new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)); - mRegistered = true; - } - } - - public void unregister() { - if (mRegistered) { - mContext.unregisterReceiver(this); - mRegistered = false; - } - } -} diff --git a/src/com/android/settings/wifi/tether/TetherService.java b/src/com/android/settings/wifi/tether/TetherService.java index e01a2469d74..72529603334 100644 --- a/src/com/android/settings/wifi/tether/TetherService.java +++ b/src/com/android/settings/wifi/tether/TetherService.java @@ -17,8 +17,6 @@ package com.android.settings.wifi.tether; import android.app.Activity; -import android.app.AlarmManager; -import android.app.PendingIntent; import android.app.Service; import android.app.usage.UsageStatsManager; import android.bluetooth.BluetoothAdapter; @@ -36,7 +34,6 @@ import android.content.res.Resources; import android.net.ConnectivityManager; import android.os.IBinder; import android.os.ResultReceiver; -import android.os.SystemClock; import android.telephony.SubscriptionManager; import android.text.TextUtils; import android.util.ArrayMap; @@ -74,7 +71,6 @@ public class TetherService extends Service { private TetherServiceWrapper mWrapper; private ArrayList mCurrentTethers; private ArrayMap> mPendingCallbacks; - private HotspotOffReceiver mHotspotReceiver; @Override public IBinder onBind(Intent intent) { @@ -97,7 +93,6 @@ public class TetherService extends Service { mPendingCallbacks.put(ConnectivityManager.TETHERING_USB, new ArrayList()); mPendingCallbacks.put( ConnectivityManager.TETHERING_BLUETOOTH, new ArrayList()); - mHotspotReceiver = new HotspotOffReceiver(this); } @Override @@ -146,20 +141,11 @@ public class TetherService extends Service { if (index >= 0) { removeTypeAtIndex(index); } - cancelAlarmIfNecessary(); } else { - if (DEBUG) Log.d(TAG, "Don't cancel alarm during provisioning"); + if (DEBUG) Log.d(TAG, "Don't remove tether type during provisioning"); } } - // Only set the alarm if we have one tether, meaning the one just added, - // to avoid setting it when it was already set previously for another - // type. - if (intent.getBooleanExtra(ConnectivityManager.EXTRA_SET_ALARM, false) - && mCurrentTethers.size() == 1) { - scheduleAlarm(); - } - if (intent.getBooleanExtra(ConnectivityManager.EXTRA_RUN_PROVISION, false)) { startProvisioning(mCurrentTypeIndex); } else if (!mInProvisionCheck) { @@ -182,16 +168,11 @@ public class TetherService extends Service { SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); prefs.edit().putString(KEY_TETHERS, tethersToString(mCurrentTethers)).commit(); - unregisterReceivers(); + unregisterReceiver(mReceiver); if (DEBUG) Log.d(TAG, "Destroying TetherService"); super.onDestroy(); } - private void unregisterReceivers() { - unregisterReceiver(mReceiver); - mHotspotReceiver.unregister(); - } - private void removeTypeAtIndex(int index) { mCurrentTethers.remove(index); // If we are currently in the middle of a check, we may need to adjust the @@ -202,11 +183,6 @@ public class TetherService extends Service { } } - @VisibleForTesting - void setHotspotOffReceiver(HotspotOffReceiver receiver) { - mHotspotReceiver = receiver; - } - private ArrayList stringToTethers(String tethersStr) { ArrayList ret = new ArrayList(); if (TextUtils.isEmpty(tethersStr)) return ret; @@ -304,48 +280,6 @@ public class TetherService extends Service { } } - @VisibleForTesting - void scheduleAlarm() { - Intent intent = new Intent(this, TetherService.class); - intent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true); - - PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0); - AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); - int period = getResourceForActiveDataSubId().getInteger( - com.android.internal.R.integer.config_mobile_hotspot_provision_check_period); - long periodMs = period * MS_PER_HOUR; - long firstTime = SystemClock.elapsedRealtime() + periodMs; - if (DEBUG) Log.d(TAG, "Scheduling alarm at interval " + periodMs); - alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstTime, periodMs, - pendingIntent); - mHotspotReceiver.register(); - } - - /** - * Cancels the recheck alarm only if no tethering is currently active. - * - * Runs in the background, to get access to bluetooth service that takes time to bind. - */ - public static void cancelRecheckAlarmIfNecessary(final Context context, int type) { - Intent intent = new Intent(context, TetherService.class); - intent.putExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, type); - context.startService(intent); - } - - @VisibleForTesting - void cancelAlarmIfNecessary() { - if (mCurrentTethers.size() != 0) { - if (DEBUG) Log.d(TAG, "Tethering still active, not cancelling alarm"); - return; - } - Intent intent = new Intent(this, TetherService.class); - PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0); - AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); - alarmManager.cancel(pendingIntent); - if (DEBUG) Log.d(TAG, "Tethering no longer active, canceling recheck"); - mHotspotReceiver.unregister(); - } - private void fireCallbacksForType(int type, int result) { List callbacksForType = mPendingCallbacks.get(type); if (callbacksForType == null) { diff --git a/tests/robotests/src/com/android/settings/wifi/tether/TetherServiceTest.java b/tests/robotests/src/com/android/settings/wifi/tether/TetherServiceTest.java deleted file mode 100644 index 61b9b5bf9a5..00000000000 --- a/tests/robotests/src/com/android/settings/wifi/tether/TetherServiceTest.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2017 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.wifi.tether; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.net.wifi.WifiManager; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.shadows.ShadowApplication; -import org.robolectric.shadows.ShadowApplication.Wrapper; -import org.robolectric.util.ReflectionHelpers; - -import java.util.ArrayList; - -@RunWith(RobolectricTestRunner.class) -public class TetherServiceTest { - - private static final int CHECK_PERIOD_HOURS = 24; - - @Mock - private Context mContext; - @Mock - private Resources mResources; - - private Context mAppContext; - private TetherService mService; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mAppContext = RuntimeEnvironment.application; - mService = spy(new TetherService()); - ReflectionHelpers.setField(mService, "mBase", mAppContext); - mService.setHotspotOffReceiver(new HotspotOffReceiver(mContext)); - doReturn(CHECK_PERIOD_HOURS).when(mResources).getInteger( - com.android.internal.R.integer.config_mobile_hotspot_provision_check_period); - doReturn(mResources).when(mService).getResourceForActiveDataSubId(); - } - - @Test - public void scheduleAlarm_shouldRegisterReceiver() { - mService.setHotspotOffReceiver(new HotspotOffReceiver(mAppContext)); - - mService.scheduleAlarm(); - - boolean found = false; - for (Wrapper wrapper : ShadowApplication.getInstance().getRegisteredReceivers()) { - if (wrapper.intentFilter.matchAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) { - found = true; - break; - } - } - - assertThat(found).isTrue(); - } - - @Test - public void cancelAlarmIfNecessary_hasActiveTethers_shouldNotUnregisterReceiver() { - mService.scheduleAlarm(); - final ArrayList tethers = new ArrayList<>(); - tethers.add(1); - ReflectionHelpers.setField(mService, "mCurrentTethers", tethers); - - mService.cancelAlarmIfNecessary(); - - verify(mContext, never()).unregisterReceiver(any(HotspotOffReceiver.class)); - } - - @Test - public void cancelAlarmIfNecessary_noActiveTethers_shouldUnregisterReceiver() { - final ArrayList tethers = new ArrayList<>(); - ReflectionHelpers.setField(mService, "mCurrentTethers", tethers); - mService.scheduleAlarm(); - - mService.cancelAlarmIfNecessary(); - - verify(mContext).unregisterReceiver(any(HotspotOffReceiver.class)); - } - - @Test - public void onDestroy_shouldUnregisterReceiver() { - final ArrayList tethers = new ArrayList<>(); - ReflectionHelpers.setField(mService, "mCurrentTethers", tethers); - ReflectionHelpers.setField(mService, "mBase", mContext); - final SharedPreferences prefs = mock(SharedPreferences .class); - final SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class); - when(mContext.getSharedPreferences(anyString(), anyInt())).thenReturn(prefs); - when(prefs.edit()).thenReturn(editor); - when(editor.putString(anyString(), anyString())).thenReturn(editor); - final HotspotOffReceiver hotspotOffReceiver = mock(HotspotOffReceiver.class); - mService.setHotspotOffReceiver(hotspotOffReceiver); - - mService.onDestroy(); - - verify(hotspotOffReceiver).unregister(); - } -} diff --git a/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java b/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java index 68914415bba..514755beb3b 100644 --- a/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java +++ b/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java @@ -18,9 +18,7 @@ package com.android.settings.wifi.tether; import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE; import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK; -import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE; import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION; -import static android.net.ConnectivityManager.EXTRA_SET_ALARM; import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; import static android.net.ConnectivityManager.TETHERING_INVALID; import static android.net.ConnectivityManager.TETHERING_USB; @@ -30,13 +28,11 @@ import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Activity; -import android.app.AlarmManager; import android.app.PendingIntent; import android.app.usage.UsageStatsManager; import android.content.BroadcastReceiver; @@ -92,7 +88,6 @@ public class TetherServiceTest extends ServiceTestCase { private ProvisionReceiver mProvisionReceiver; private Receiver mResultReceiver; - @Mock private AlarmManager mAlarmManager; @Mock private ConnectivityManager mConnectivityManager; @Mock private PackageManager mPackageManager; @Mock private WifiManager mWifiManager; @@ -158,15 +153,6 @@ public class TetherServiceTest extends ServiceTestCase { super.tearDown(); } - private void cancelAllProvisioning() { - int[] types = new int[]{TETHERING_BLUETOOTH, TETHERING_WIFI, TETHERING_USB}; - for (int type : types) { - Intent intent = new Intent(); - intent.putExtra(EXTRA_REM_TETHER_TYPE, type); - startService(intent); - } - } - public void testStartForProvision() { runProvisioningForType(TETHERING_WIFI); @@ -184,19 +170,6 @@ public class TetherServiceTest extends ServiceTestCase { assertTrue(mWrapper.isAppInactive(FAKE_PACKAGE_NAME)); } - public void testScheduleRechecks() { - Intent intent = new Intent(); - intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI); - intent.putExtra(EXTRA_SET_ALARM, true); - startService(intent); - - long period = TEST_CHECK_PERIOD * MS_PER_HOUR; - verify(mAlarmManager).setRepeating(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), - eq(period), mPiCaptor.capture()); - PendingIntent pi = mPiCaptor.getValue(); - assertEquals(TetherService.class.getName(), pi.getIntent().getComponent().getClassName()); - } - public void testStartMultiple() { runProvisioningForType(TETHERING_WIFI); @@ -251,21 +224,6 @@ public class TetherServiceTest extends ServiceTestCase { verify(mConnectivityManager).setUsbTethering(eq(false)); } - public void testCancelAlarm() { - runProvisioningForType(TETHERING_WIFI); - - assertTrue(waitForProvisionRequest(TETHERING_WIFI)); - assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR)); - - Intent intent = new Intent(); - intent.putExtra(EXTRA_REM_TETHER_TYPE, TETHERING_WIFI); - startService(intent); - - verify(mAlarmManager).cancel(mPiCaptor.capture()); - PendingIntent pi = mPiCaptor.getValue(); - assertEquals(TetherService.class.getName(), pi.getIntent().getComponent().getClassName()); - } - public void testIgnoreOutdatedRequest() { Intent intent = new Intent(); intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI); @@ -387,9 +345,7 @@ public class TetherServiceTest extends ServiceTestCase { @Override public Object getSystemService(String name) { - if (ALARM_SERVICE.equals(name)) { - return mAlarmManager; - } else if (CONNECTIVITY_SERVICE.equals(name)) { + if (CONNECTIVITY_SERVICE.equals(name)) { return mConnectivityManager; } else if (WIFI_SERVICE.equals(name)) { return mWifiManager; From 17feecffaeab005ce0833180b6c9702ca35d6086 Mon Sep 17 00:00:00 2001 From: markchien Date: Sun, 7 Jun 2020 17:40:56 +0800 Subject: [PATCH 3/9] Replace ConnectivityManager as TetheringManager Tethering APIs are all move to TetheringManager from Android R. 1. Replace ConnectivityManager tethering API usage as TetheringManager. 2. Use TetheringManager#stopTethering to disable usb tethering instead of using deprecated ConnectivityService#setUsbTethering 3. Use TetheringManager#stopTethering to disable bluetooth tethering instead of directly use BluetoothPan#setBlueoothTethering. So bluetooth getProfileProxy is not needed in TetherService because tethering would do that when calling #stopTethering. 4. Also support TETHERING_ETHERNET entitlement check that TETHERING_ETHERNET is new added from Android R. Bug: 146918263 Test: atest TetherServiceTest Change-Id: Id969f29d7210f2ee32719c76439049bbc86cd4f6 --- .../network/TetherProvisioningActivity.java | 37 +++---- .../settings/wifi/tether/TetherService.java | 98 +++++++------------ .../wifi/tether/TetherServiceTest.java | 34 +++---- 3 files changed, 71 insertions(+), 98 deletions(-) diff --git a/src/com/android/settings/network/TetherProvisioningActivity.java b/src/com/android/settings/network/TetherProvisioningActivity.java index 09efe482e68..bb61546594d 100644 --- a/src/com/android/settings/network/TetherProvisioningActivity.java +++ b/src/com/android/settings/network/TetherProvisioningActivity.java @@ -16,13 +16,19 @@ package com.android.settings.network; +import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; +import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; +import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; +import static android.net.TetheringManager.TETHERING_INVALID; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; +import static android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.net.ConnectivityManager; -import android.net.TetheringConstants; -import android.net.TetheringManager; import android.os.Bundle; import android.os.ResultReceiver; import android.os.UserHandle; @@ -52,23 +58,19 @@ public class TetherProvisioningActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mResultReceiver = (ResultReceiver)getIntent().getParcelableExtra( - ConnectivityManager.EXTRA_PROVISION_CALLBACK); + mResultReceiver = (ResultReceiver) getIntent().getParcelableExtra(EXTRA_PROVISION_CALLBACK); - final int tetherType = getIntent().getIntExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, - ConnectivityManager.TETHERING_INVALID); + final int tetherType = getIntent().getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID); - final int tetherSubId = getIntent().getIntExtra(EXTRA_SUBID, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); + final int tetherSubId = getIntent().getIntExtra(EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); final int subId = SubscriptionManager.getActiveDataSubscriptionId(); if (tetherSubId != subId) { Log.e(TAG, "This Provisioning request is outdated, current subId: " + subId); - mResultReceiver.send(TetheringManager.TETHER_ERROR_PROVISIONING_FAILED, null); + mResultReceiver.send(TETHER_ERROR_PROVISIONING_FAILED, null); finish(); return; } - String[] provisionApp = getIntent().getStringArrayExtra( - TetheringConstants.EXTRA_RUN_PROVISION); + String[] provisionApp = getIntent().getStringArrayExtra(EXTRA_RUN_PROVISION); if (provisionApp == null || provisionApp.length < 2) { final Resources res = Utils.getResourcesForSubId(this, subId); provisionApp = res.getStringArray( @@ -77,8 +79,8 @@ public class TetherProvisioningActivity extends Activity { final Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClassName(provisionApp[0], provisionApp[1]); intent.putExtra(EXTRA_TETHER_TYPE, tetherType); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); - intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, mResultReceiver); + intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId); + intent.putExtra(EXTRA_PROVISION_CALLBACK, mResultReceiver); if (DEBUG) { Log.d(TAG, "Starting provisioning app: " + provisionApp[0] + "." + provisionApp[1]); } @@ -86,7 +88,7 @@ public class TetherProvisioningActivity extends Activity { if (getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) { Log.e(TAG, "Provisioning app is configured, but not available."); - mResultReceiver.send(TetheringManager.TETHER_ERROR_PROVISIONING_FAILED, null); + mResultReceiver.send(TETHER_ERROR_PROVISIONING_FAILED, null); finish(); return; } @@ -99,9 +101,8 @@ public class TetherProvisioningActivity extends Activity { super.onActivityResult(requestCode, resultCode, intent); if (requestCode == PROVISION_REQUEST) { if (DEBUG) Log.d(TAG, "Got result from app: " + resultCode); - int result = resultCode == Activity.RESULT_OK ? - TetheringManager.TETHER_ERROR_NO_ERROR : - TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; + int result = resultCode == Activity.RESULT_OK + ? TETHER_ERROR_NO_ERROR : TETHER_ERROR_PROVISIONING_FAILED; mResultReceiver.send(result, null); finish(); } diff --git a/src/com/android/settings/wifi/tether/TetherService.java b/src/com/android/settings/wifi/tether/TetherService.java index 72529603334..72ea1a9c591 100644 --- a/src/com/android/settings/wifi/tether/TetherService.java +++ b/src/com/android/settings/wifi/tether/TetherService.java @@ -16,13 +16,24 @@ package com.android.settings.wifi.tether; +import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; +import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; +import static android.net.TetheringConstants.EXTRA_REM_TETHER_TYPE; +import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_ETHERNET; +import static android.net.TetheringManager.TETHERING_INVALID; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; +import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; +import static android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + import android.app.Activity; import android.app.Service; import android.app.usage.UsageStatsManager; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothPan; -import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothProfile.ServiceListener; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -31,7 +42,7 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; -import android.net.ConnectivityManager; +import android.net.TetheringManager; import android.os.IBinder; import android.os.ResultReceiver; import android.telephony.SubscriptionManager; @@ -89,17 +100,16 @@ public class TetherService extends Service { mCurrentTethers = stringToTethers(prefs.getString(KEY_TETHERS, "")); mCurrentTypeIndex = 0; mPendingCallbacks = new ArrayMap<>(3); - mPendingCallbacks.put(ConnectivityManager.TETHERING_WIFI, new ArrayList()); - mPendingCallbacks.put(ConnectivityManager.TETHERING_USB, new ArrayList()); - mPendingCallbacks.put( - ConnectivityManager.TETHERING_BLUETOOTH, new ArrayList()); + mPendingCallbacks.put(TETHERING_WIFI, new ArrayList()); + mPendingCallbacks.put(TETHERING_USB, new ArrayList()); + mPendingCallbacks.put(TETHERING_BLUETOOTH, new ArrayList()); + mPendingCallbacks.put(TETHERING_ETHERNET, new ArrayList()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent.hasExtra(EXTRA_SUBID)) { - final int tetherSubId = intent.getIntExtra(EXTRA_SUBID, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); + final int tetherSubId = intent.getIntExtra(EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); if (tetherSubId != subId) { Log.e(TAG, "This Provisioning request is outdated, current subId: " + subId); @@ -109,18 +119,16 @@ public class TetherService extends Service { return START_NOT_STICKY; } } - if (intent.hasExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE)) { - int type = intent.getIntExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, - ConnectivityManager.TETHERING_INVALID); - ResultReceiver callback = - intent.getParcelableExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK); + if (intent.hasExtra(EXTRA_ADD_TETHER_TYPE)) { + int type = intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID); + ResultReceiver callback = intent.getParcelableExtra(EXTRA_PROVISION_CALLBACK); if (callback != null) { List callbacksForType = mPendingCallbacks.get(type); if (callbacksForType != null) { callbacksForType.add(callback); } else { // Invalid tether type. Just ignore this request and report failure. - callback.send(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE, null); + callback.send(TETHER_ERROR_UNKNOWN_IFACE, null); stopSelf(); return START_NOT_STICKY; } @@ -132,10 +140,9 @@ public class TetherService extends Service { } } - if (intent.hasExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE)) { + if (intent.hasExtra(EXTRA_REM_TETHER_TYPE)) { if (!mInProvisionCheck) { - int type = intent.getIntExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, - ConnectivityManager.TETHERING_INVALID); + int type = intent.getIntExtra(EXTRA_REM_TETHER_TYPE, TETHERING_INVALID); int index = mCurrentTethers.indexOf(type); if (DEBUG) Log.d(TAG, "Removing tether " + type + ", index " + index); if (index >= 0) { @@ -146,7 +153,7 @@ public class TetherService extends Service { } } - if (intent.getBooleanExtra(ConnectivityManager.EXTRA_RUN_PROVISION, false)) { + if (intent.getBooleanExtra(EXTRA_RUN_PROVISION, false)) { startProvisioning(mCurrentTypeIndex); } else if (!mInProvisionCheck) { // If we aren't running any provisioning, no reason to stay alive. @@ -207,32 +214,9 @@ public class TetherService extends Service { return buffer.toString(); } - private void disableWifiTethering() { - ConnectivityManager cm = - (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); - cm.stopTethering(ConnectivityManager.TETHERING_WIFI); - } - - private void disableUsbTethering() { - ConnectivityManager cm = - (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); - cm.setUsbTethering(false); - } - - private void disableBtTethering() { - final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - if (adapter != null) { - adapter.getProfileProxy(this, new ServiceListener() { - @Override - public void onServiceDisconnected(int profile) { } - - @Override - public void onServiceConnected(int profile, BluetoothProfile proxy) { - ((BluetoothPan) proxy).setBluetoothTethering(false); - adapter.closeProfileProxy(BluetoothProfile.PAN, proxy); - } - }, BluetoothProfile.PAN); - } + private void disableTethering(final int tetheringType) { + final TetheringManager tm = (TetheringManager) getSystemService(Context.TETHERING_SERVICE); + tm.stopTethering(tetheringType); } private void startProvisioning(int index) { @@ -255,7 +239,7 @@ public class TetherService extends Service { Intent intent = new Intent(provisionAction); int type = mCurrentTethers.get(index); intent.putExtra(TETHER_CHOICE, type); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); + intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId); intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); @@ -285,8 +269,8 @@ public class TetherService extends Service { if (callbacksForType == null) { return; } - int errorCode = result == RESULT_OK ? ConnectivityManager.TETHER_ERROR_NO_ERROR : - ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; + int errorCode = result == RESULT_OK ? TETHER_ERROR_NO_ERROR : + TETHER_ERROR_PROVISIONING_FAILED; for (ResultReceiver callback : callbacksForType) { if (DEBUG) Log.d(TAG, "Firing result: " + errorCode + " to callback"); callback.send(errorCode, null); @@ -309,19 +293,7 @@ public class TetherService extends Service { int checkType = mCurrentTethers.get(mCurrentTypeIndex); mInProvisionCheck = false; int result = intent.getIntExtra(EXTRA_RESULT, RESULT_DEFAULT); - if (result != RESULT_OK) { - switch (checkType) { - case ConnectivityManager.TETHERING_WIFI: - disableWifiTethering(); - break; - case ConnectivityManager.TETHERING_BLUETOOTH: - disableBtTethering(); - break; - case ConnectivityManager.TETHERING_USB: - disableUsbTethering(); - break; - } - } + if (result != RESULT_OK) disableTethering(checkType); fireCallbacksForType(checkType, result); if (++mCurrentTypeIndex >= mCurrentTethers.size()) { diff --git a/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java b/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java index 514755beb3b..19f29c03cfb 100644 --- a/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java +++ b/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java @@ -16,15 +16,15 @@ package com.android.settings.wifi.tether; -import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE; -import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK; -import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION; -import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; -import static android.net.ConnectivityManager.TETHERING_INVALID; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; +import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; +import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; +import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; +import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_INVALID; +import static android.net.TetheringManager.TETHERING_USB; +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.mockito.Matchers.any; @@ -47,7 +47,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; -import android.net.ConnectivityManager; +import android.net.TetheringManager; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.ResultReceiver; @@ -88,7 +88,7 @@ public class TetherServiceTest extends ServiceTestCase { private ProvisionReceiver mProvisionReceiver; private Receiver mResultReceiver; - @Mock private ConnectivityManager mConnectivityManager; + @Mock private TetheringManager mTetheringManager; @Mock private PackageManager mPackageManager; @Mock private WifiManager mWifiManager; @Mock private SharedPreferences mPrefs; @@ -208,9 +208,9 @@ public class TetherServiceTest extends ServiceTestCase { runProvisioningForType(TETHERING_WIFI); assertTrue(waitForProvisionRequest(TETHERING_WIFI)); - assertTrue(waitForProvisionResponse(TETHER_ERROR_PROVISION_FAILED)); + assertTrue(waitForProvisionResponse(TETHER_ERROR_PROVISIONING_FAILED)); - verify(mConnectivityManager).stopTethering(ConnectivityManager.TETHERING_WIFI); + verify(mTetheringManager).stopTethering(TETHERING_WIFI); } public void testFailureStopsTethering_Usb() { @@ -219,9 +219,9 @@ public class TetherServiceTest extends ServiceTestCase { runProvisioningForType(TETHERING_USB); assertTrue(waitForProvisionRequest(TETHERING_USB)); - assertTrue(waitForProvisionResponse(TETHER_ERROR_PROVISION_FAILED)); + assertTrue(waitForProvisionResponse(TETHER_ERROR_PROVISIONING_FAILED)); - verify(mConnectivityManager).setUsbTethering(eq(false)); + verify(mTetheringManager).stopTethering(TETHERING_USB); } public void testIgnoreOutdatedRequest() { @@ -345,8 +345,8 @@ public class TetherServiceTest extends ServiceTestCase { @Override public Object getSystemService(String name) { - if (CONNECTIVITY_SERVICE.equals(name)) { - return mConnectivityManager; + if (TETHERING_SERVICE.equals(name)) { + return mTetheringManager; } else if (WIFI_SERVICE.equals(name)) { return mWifiManager; } From 670a30e7664844ba4177a7183805127cdc32edd1 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Thu, 11 Jun 2020 22:45:35 +0100 Subject: [PATCH 4/9] Remove password shards from memory Force a garbage collection and zeroize some fields after Activity finishes Test: Goes through password change flow, then grab a heap dump via adb shell 'am dumpheap $(pidof com.android.settings) /data/local/tmp/settings.hprof' And grep for password in the dump Bug: 144537463 Change-Id: Idd0a04ada98900aeb2a6d20bb1270a4a4aec2cfd --- .../settings/password/ChooseLockGeneric.java | 8 ++++++++ .../settings/password/ChooseLockPassword.java | 13 +++++++++++++ .../settings/password/ChooseLockPattern.java | 13 +++++++++++++ .../ConfirmDeviceCredentialBaseActivity.java | 10 ++++++++++ .../settings/password/ConfirmLockPassword.java | 11 +++++++++++ 5 files changed, 55 insertions(+) diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 81d5036a740..04ee1b81ff9 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -821,6 +821,14 @@ public class ChooseLockGeneric extends SettingsActivity { @Override public void onDestroy() { super.onDestroy(); + if (mUserPassword != null) { + mUserPassword.zeroize(); + } + // Force a garbage collection immediately to remove remnant of user password shards + // from memory. + System.gc(); + System.runFinalization(); + System.gc(); } @Override diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index cdc03f95055..19cc9c8018a 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -530,6 +530,19 @@ public class ChooseLockPassword extends SettingsActivity { } } + @Override + public void onDestroy() { + super.onDestroy(); + if (mCurrentCredential != null) { + mCurrentCredential.zeroize(); + } + // Force a garbage collection immediately to remove remnant of user password shards + // from memory. + System.gc(); + System.runFinalization(); + System.gc(); + } + protected int getStageType() { return mForFingerprint ? Stage.TYPE_FINGERPRINT : mForFace ? Stage.TYPE_FACE : diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index ece3da8f247..27fc9f022ea 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -617,6 +617,19 @@ public class ChooseLockPattern extends SettingsActivity { } } + @Override + public void onDestroy() { + super.onDestroy(); + if (mCurrentCredential != null) { + mCurrentCredential.zeroize(); + } + // Force a garbage collection immediately to remove remnant of user password shards + // from memory. + System.gc(); + System.runFinalization(); + System.gc(); + } + protected Intent getRedactionInterstitialIntent(Context context) { return RedactionInterstitial.createStartIntent(context, mUserId); } diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java index eaea2eac0e8..383ae4f1a06 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java @@ -157,6 +157,16 @@ public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivi } } + @Override + public void onDestroy() { + super.onDestroy(); + // Force a garbage collection immediately to remove remnant of user password shards + // from memory. + System.gc(); + System.runFinalization(); + System.gc(); + } + @Override public void finish() { super.finish(); diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java index 6f8dbfdecdd..8aa44e9780f 100644 --- a/src/com/android/settings/password/ConfirmLockPassword.java +++ b/src/com/android/settings/password/ConfirmLockPassword.java @@ -217,6 +217,17 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { } } + @Override + public void onDestroy() { + super.onDestroy(); + mPasswordEntry.setText(null); + // Force a garbage collection immediately to remove remnant of user password shards + // from memory. + System.gc(); + System.runFinalization(); + System.gc(); + } + private int getDefaultHeader() { if (mFrp) { return mIsAlpha ? R.string.lockpassword_confirm_your_password_header_frp From 451ae5441ecfbb76db3990c63e9f2b7c79e5d261 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Mon, 15 Jun 2020 00:45:36 +0000 Subject: [PATCH 5/9] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: I9d2dd999c963161e7283fc6a6bd7d76c7d44bafa --- res/values-af/strings.xml | 2 +- res/values-ar/strings.xml | 8 ++++---- res/values-bg/strings.xml | 2 +- res/values-es-rUS/strings.xml | 2 +- res/values-iw/strings.xml | 2 +- res/values-mk/strings.xml | 2 +- res/values-th/strings.xml | 2 +- res/values-uk/strings.xml | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index 358bd83096d..c39095c0bc8 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -785,7 +785,7 @@ "Skakel NFC aan" "NFC ruil data uit tussen hierdie toestel en ander nabygeleë toestelle of teikens, soos byvoorbeeld betaalterminale, toeganglesers en interaktiewe advertensies of merkers." "Vereis toestelontsluiting vir NFC" - "Laat die gebruik van NFC-betalings en Publieke Vervoer net toe wanneer die skerm ontsluit is" + "Laat die gebruik van NFC-betalings en -oordragte net toe wanneer die skerm ontsluit is" "Android Beam" "Gereed om programinhoud te stuur via NFC" "Af" diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 99201924e49..5424dd771e4 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -853,7 +853,7 @@ "‏تفعيل NFC" "‏يتم من خلال تقنية الاتصال بالحقل القريب (NFC) تبادل البيانات بين هذا الجهاز والأجهزة أو الأهداف المجاورة الأخرى، مثل محطات الدفع وبرامج قراءة الوصول والعلامات أو الإعلانات التفاعلية." "‏يجب فتح قفل الجهاز لاستخدام تقنية الاتصالات القريبة المدى (NFC)" - "‏السماح باستخدام \"الدفع والتقل عبر تقنية NFC\" فقط عندما تكون الشاشة مفتوحة" + "‏السماح باستخدام \"الدفع والتنقل عبر تقنية NFC\" فقط عندما تكون الشاشة مفتوحة" "‏شعاع Android" "‏جاهز لنقل محتوى التطبيق عبر الاتصالات القريبة المدى (NFC)" "إيقاف" @@ -1861,7 +1861,7 @@ "أرقام التعريف الشخصي غير متطابقة" "ارسم النقش مرة أخرى" "اختيار طريقة فتح القفل" - "تم تعيين كلمة المرور" + "تم ضبط كلمة المرور" "‏تم تعيين رمز PIN" "تم تعيين النقش" "لاستخدام \"فتح القفل بالوجه\"، يجب تحديد كلمة مرور" @@ -2192,7 +2192,7 @@ "التطبيق" "آخر مرة تم استخدامه" "وقت الاستخدام" - "سهولة الاستخدام" + "إمكانية الوصول" "إعدادات \"سهولة الاستخدام\"" "أجهزة قارئ الشاشة والشاشة وعناصر التحكم التفاعلية" "إعدادات الرؤية" @@ -4886,7 +4886,7 @@ %d شهادة CA كحد أدنى ‏شهادة CA واحدة (%d) كحد أدنى - "يمكن للمشرف قفل الجهاز وإعادة تعيين كلمة المرور" + "يمكن للمشرف قفل الجهاز وإعادة ضبط كلمة المرور" "يمكن للمشرف حذف جميع بيانات الجهاز" "محاولات كلمة المرور الخاطئة قبل حذف جميع بيانات الجهاز" "محاولات كلمة المرور الخاطئة قبل حذف بيانات الملف الشخصي للعمل" diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index a7023fcd6fb..0c37eabba5b 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -785,7 +785,7 @@ "Включване на КБП" "Чрез КБП се обменят данни между това устройство и други в близост или целеви такива, като например терминали за плащане, четци за достъп и интерактивни реклами или маркери." "Изискване за отключване на устройството за NFC" - "Разрешаване на използването на КБП за плащане и прехвърляне само при отключен екран" + "Разрешаване на използването на NFC за плащане и прехвърляне само при отключен екран" "Android Beam" "В готовност за предаване на съдържание на приложения чрез КБП" "Изключено" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 1d21d6ec7dc..03f28f33f03 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -4812,7 +4812,7 @@ "Ver más" "Ver menos" "Conectar al dispositivo" - "La app de %1$s quiere usar una red Wi-Fi temporal para conectarte al dispositivo" + "La app de %1$s quiere usar una red Wi-Fi temporal para conectarse a tu dispositivo" "No se encontraron dispositivos. Asegúrate de que los dispositivos estén encendidos y puedan conectarse." "Volver a intentarlo" "Se produjo un error. La aplicación canceló la solicitud para elegir un dispositivo." diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index f469e55c8f2..67d04ebab87 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -2551,7 +2551,7 @@ ‏%1$d אפליקציות מוגבלות אפליקציה מוגבלת אחת - " ""%""^1" + " ""^1""%" "לעצור את האפליקציה?" "הניהול של צריכת הסוללה בטלפון לא תקין, כי האפליקציה %1$s לא מאפשרת למכשיר להיכנס למצב שינה.\n\nכדי לפתור את הבעיה, ניתן להפסיק את פעולת האפליקציה.\n\nאם הבעיה תימשך, ייתכן שיהיה עליך להסיר את התקנת האפליקציה כדי לשפר את ביצועי הסוללה." "הניהול של צריכת הסוללה בטאבלט לא תקין, כי האפליקציה %1$s לא מאפשרת למכשיר להיכנס למצב שינה.\n\nכדי לפתור את הבעיה, ניתן להפסיק את פעולת האפליקציה.\n\nאם הבעיה תימשך, ייתכן שיהיה עליך להסיר את התקנת האפליקציה כדי לשפר את ביצועי הסוללה." diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index 5870b4175d7..adba54bb2d3 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -1798,7 +1798,7 @@ "Телефонот е ресетиран на фабрички поставки. За да го користите, внесете го претходниот PIN." "Телефонот е ресетиран на фабрички поставки. За да го користите, внесете ја претходната лозинка." "Потврдете ја шемата" - "Потврди PIN" + "Потврдете го PIN-от" "Потврдете ја лозинката" "Погрешен PIN" "Погрешна лозинка" diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index 44b6e17e2bf..c5ad3de7850 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -785,7 +785,7 @@ "เปิดใช้ NFC" "NFC จะแลกเปลี่ยนข้อมูลระหว่างอุปกรณ์นี้กับอุปกรณ์อื่นที่อยู่ใกล้ๆ หรืออุปกรณ์เป้าหมาย เช่น เครื่องชำระเงิน เครื่องอ่านการเข้าถึง และโฆษณาหรือป้ายสินค้าเชิงโต้ตอบ" "ต้องปลดล็อกอุปกรณ์เพื่อใช้งาน NFC" - "อนุญาตการใช้การชำระเงินผ่าน NFC และขนส่งสาธารณะเฉพาะเวลาที่ไม่ได้ล็อกหน้าจอเท่านั้น" + "อนุญาตให้ใช้ขนส่งสาธารณะและการชำระเงินผ่าน NFC เฉพาะเวลาที่ไม่ได้ล็อกหน้าจอเท่านั้น" "Android Beam" "พร้อมที่จะส่งเนื้อหาแอปผ่านทาง NFC" "ปิด" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 27b098498a4..e453b768561 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -2200,7 +2200,7 @@ "Провести двома пальцями вгору" "Провести трьома пальцями вгору" "Натиснути кнопку спеціальних можливостей" - "Натиснути кнопку спеціальних можливостей %s унизу екрана.\n\nЩоб переключитися між функціями, натисніть і утримуйте кнопку спеціальних можливостей." + "Натисніть кнопку спеціальних можливостей %s унизу екрана.\n\nЩоб переключитися між функціями, натисніть і утримуйте кнопку спеціальних можливостей." "Провести двома пальцями знизу вгору по екрану.\n\nЩоб переключитися між функціями, проведіть двома пальцями вгору й утримуйте екран." "Провести по екрану знизу вгору трьома пальцями.\n\nЩоб переключитися між функціями, проведіть по екрану знизу вгору трьома пальцями й утримуйте їх." "Утримувати клавіші гучності" From 723c251c13aa7d1ae79709225385b89877e6eaf0 Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Tue, 9 Jun 2020 18:07:56 +0800 Subject: [PATCH 6/9] [Settings] Allow talkback to focus and select APN Change the focus area to help talkback focus on APN items. Bug: 149794675 Test: manual Change-Id: I5f391be89a5b22095d6f0d04b187ea18970f18d4 --- res/layout/apn_preference_layout.xml | 10 ++-- .../settings/network/ApnPreference.java | 48 +++++++++++++------ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/res/layout/apn_preference_layout.xml b/res/layout/apn_preference_layout.xml index fa98d88e2fc..4d984435f68 100644 --- a/res/layout/apn_preference_layout.xml +++ b/res/layout/apn_preference_layout.xml @@ -4,9 +4,9 @@ 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. @@ -21,6 +21,7 @@ android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:minHeight="?android:attr/listPreferredItemHeight" + android:focusable="false" android:gravity="center_vertical"> @@ -48,6 +50,7 @@ android:layout_alignStart="@android:id/title" android:textAppearance="?android:attr/textAppearanceListItemSecondary" android:textColor="?android:attr/textColorSecondary" + android:focusable="false" android:maxLines="2" /> @@ -59,6 +62,7 @@ android:layout_marginStart="8dip" android:layout_marginEnd="8dip" android:layout_gravity="center_vertical" + android:focusable="true" android:clickable="true" /> diff --git a/src/com/android/settings/network/ApnPreference.java b/src/com/android/settings/network/ApnPreference.java index 2ec83d1ec26..63e283818f0 100755 --- a/src/com/android/settings/network/ApnPreference.java +++ b/src/com/android/settings/network/ApnPreference.java @@ -27,6 +27,7 @@ import android.util.Log; import android.view.View; import android.widget.CompoundButton; import android.widget.RadioButton; +import android.widget.RelativeLayout; import android.widget.Toast; import androidx.preference.Preference; @@ -34,19 +35,32 @@ import androidx.preference.PreferenceViewHolder; import com.android.settings.R; -public class ApnPreference extends Preference implements CompoundButton.OnCheckedChangeListener { +/** + * Preference of APN UI entry + */ +public class ApnPreference extends Preference implements CompoundButton.OnCheckedChangeListener, + View.OnClickListener { final static String TAG = "ApnPreference"; private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + /** + * Constructor of Preference + */ public ApnPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } + /** + * Constructor of Preference + */ public ApnPreference(Context context, AttributeSet attrs) { this(context, attrs, R.attr.apnPreferenceStyle); } + /** + * Constructor of Preference + */ public ApnPreference(Context context) { this(context, null); } @@ -61,6 +75,9 @@ public class ApnPreference extends Preference implements CompoundButton.OnChecke public void onBindViewHolder(PreferenceViewHolder view) { super.onBindViewHolder(view); + final RelativeLayout textArea = (RelativeLayout) view.findViewById(R.id.text_layout); + textArea.setOnClickListener(this); + final View widget = view.findViewById(R.id.apn_radiobutton); if ((widget != null) && widget instanceof RadioButton) { final RadioButton rb = (RadioButton) widget; @@ -111,22 +128,25 @@ public class ApnPreference extends Preference implements CompoundButton.OnChecke } @Override - protected void onClick() { + public void onClick(View layoutView) { super.onClick(); final Context context = getContext(); - if (context != null) { - if (mHideDetails) { - Toast.makeText(context, context.getString( - R.string.cannot_change_apn_toast), Toast.LENGTH_LONG).show(); - return; - } - final int pos = Integer.parseInt(getKey()); - final Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos); - final Intent editIntent = new Intent(Intent.ACTION_EDIT, url); - editIntent.putExtra(ApnSettings.SUB_ID, mSubId); - editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - context.startActivity(editIntent); + final int pos = Integer.parseInt(getKey()); + if (context == null) { + Log.w(TAG, "No context available for pos=" + pos); + return; } + + if (mHideDetails) { + Toast.makeText(context, context.getString( + R.string.cannot_change_apn_toast), Toast.LENGTH_LONG).show(); + return; + } + final Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos); + final Intent editIntent = new Intent(Intent.ACTION_EDIT, url); + editIntent.putExtra(ApnSettings.SUB_ID, mSubId); + editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + context.startActivity(editIntent); } public void setSelectable(boolean selectable) { From 3e8425468b573edbc508b9264256a4c0bba319a1 Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Sat, 13 Jun 2020 02:54:05 +0800 Subject: [PATCH 7/9] [Settings] WEA title wording change The wording of WEA need to align in UI entry and UIs within. The "Wireless Emergency Alerts" should be the official wording for it. Bug: 158498436 Test: build pass Change-Id: I17e6659915e1038c8ab11ad4003c08f87bbdb82e --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index de8ca8a54fd..405b3e1e085 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7280,7 +7280,7 @@ %1$s - Emergency alerts + Wireless emergency alerts Network operators From e3a821d6fe4f90389be61f2fb07f9d2cd02ef8ae Mon Sep 17 00:00:00 2001 From: Tim Peng Date: Mon, 15 Jun 2020 11:34:26 +0800 Subject: [PATCH 8/9] Unable to adjust remote session volume in Sound Setting -It is incorrect to compare the device ID with session ID -The preference key is the session ID and we should adjust remote session volume by it Fix: 158956140 Test: make -j42 RunSettingsRoboTests Change-Id: Ia815b7bfdf6d7e44aca9832f11371669e973d363 --- .../settings/notification/RemoteVolumeGroupController.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/com/android/settings/notification/RemoteVolumeGroupController.java b/src/com/android/settings/notification/RemoteVolumeGroupController.java index 4b045e289b0..6d3c96dcc3d 100644 --- a/src/com/android/settings/notification/RemoteVolumeGroupController.java +++ b/src/com/android/settings/notification/RemoteVolumeGroupController.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.Intent; import android.media.RoutingSessionInfo; import android.text.TextUtils; -import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -136,11 +135,6 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem @Override public boolean onPreferenceChange(Preference preference, Object newValue) { - final MediaDevice device = mLocalMediaManager.getMediaDeviceById(preference.getKey()); - if (device == null) { - Log.e(TAG, "Unable to find " + preference.getKey() + " to set volume"); - return false; - } ThreadUtils.postOnBackgroundThread(() -> { mLocalMediaManager.adjustSessionVolume(preference.getKey(), (int) newValue); }); @@ -184,6 +178,5 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem @Override public void onSelectedDeviceStateChanged(MediaDevice device, int state) { - } } From 88e4c39e835fe5b0c0ddb89e8b844ea1c80dc815 Mon Sep 17 00:00:00 2001 From: Chen Xu Date: Mon, 15 Jun 2020 15:42:53 -0700 Subject: [PATCH 9/9] update description for string transaltion for IT-CMAS requirement Bug: 159062066 Test: Build Change-Id: I14945535145721c3d035113c3fcba3222fc614b3 --- res/values-mcc222/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/res/values-mcc222/strings.xml b/res/values-mcc222/strings.xml index 0e1f4754cee..d27073504c8 100644 --- a/res/values-mcc222/strings.xml +++ b/res/values-mcc222/strings.xml @@ -14,6 +14,8 @@ limitations under the License. --> - + Public warnings \ No newline at end of file