From 222be02b34082fb5839e8e76b007840655a9f127 Mon Sep 17 00:00:00 2001 From: Zhen Zhang Date: Tue, 30 Jun 2020 15:00:58 -0700 Subject: [PATCH 1/3] Fix bug: "Hotspot & Tethering" preference doesn't get updated Aissign the value of mPrefrence when displayPrefrence() being called. This can fix the preference doesn't get updated bug. Added test to ensure it. Bug: 160169699 Test: make RunSettingsRoboTests ROBOTEST_FILTER=AllInOneTetherPreferenceController Change-Id: If0e7ce421cc46cff2b92837d2d07ea0ff4dc5fd9 --- .../AllInOneTetherPreferenceController.java | 7 +++++++ .../AllInOneTetherPreferenceControllerTest.java | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/network/AllInOneTetherPreferenceController.java b/src/com/android/settings/network/AllInOneTetherPreferenceController.java index 8180d5a6ef7..75453b4f57a 100644 --- a/src/com/android/settings/network/AllInOneTetherPreferenceController.java +++ b/src/com/android/settings/network/AllInOneTetherPreferenceController.java @@ -37,6 +37,7 @@ import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle.Event; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; +import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; @@ -93,6 +94,12 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(mPreferenceKey); + } + @Override public int getAvailabilityStatus() { if (!TetherUtil.isTetherAvailable(mContext) diff --git a/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java index 12e687d8222..f37b0e418cb 100644 --- a/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java @@ -24,6 +24,7 @@ import static com.android.settings.network.TetherEnabler.TETHERING_WIFI_ON; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -35,6 +36,9 @@ import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; import android.content.Context; +import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; + import com.android.settings.R; import com.android.settings.widget.MasterSwitchPreference; @@ -109,13 +113,13 @@ public class AllInOneTetherPreferenceControllerTest { }); } - @Mock private Context mContext; @Mock private BluetoothAdapter mBluetoothAdapter; @Mock private MasterSwitchPreference mPreference; + private static final String PREF_KEY = "tether"; private AllInOneTetherPreferenceController mController; private final int mTetherState; private final int mSummaryResId; @@ -127,11 +131,16 @@ public class AllInOneTetherPreferenceControllerTest { @Before public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); MockitoAnnotations.initMocks(this); mController = spy(AllInOneTetherPreferenceController.class); ReflectionHelpers.setField(mController, "mContext", mContext); ReflectionHelpers.setField(mController, "mBluetoothAdapter", mBluetoothAdapter); - ReflectionHelpers.setField(mController, "mPreference", mPreference); + ReflectionHelpers.setField(mController, "mPreferenceKey", PREF_KEY); + PreferenceScreen screen = mock(PreferenceScreen.class); + when(screen.findPreference(PREF_KEY)).thenReturn(mPreference); + doReturn(mController.AVAILABLE).when(mController).getAvailabilityStatus(); + mController.displayPreference(screen); } @Test @@ -169,5 +178,8 @@ public class AllInOneTetherPreferenceControllerTest { public void getSummary_afterTetherStateChanged() { mController.onTetherStateUpdated(mTetherState); assertThat(mController.getSummary()).isEqualTo(mContext.getString(mSummaryResId)); + + verify(mController).updateState(mPreference); + verify(mPreference).setSummary(mContext.getString(mSummaryResId)); } } From ea689abbcd16363fccde246b61b4e5ebf896902a Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Wed, 1 Jul 2020 17:18:29 +0800 Subject: [PATCH 2/3] Fix the exception of accessing an ArrayMap - ArrayMap is not thread-safe. - When accessing the map across threads at the same time, the map may throw a ConcurrentModificationException. - Convert the map to a synchronizedMap to avoid the exception. Fixes: 159813482 Test: robotest Change-Id: I3b8bdd435c7c546acf736fa8aafd2ceaed94d081 --- src/com/android/settings/slices/SliceBackgroundWorker.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/slices/SliceBackgroundWorker.java b/src/com/android/settings/slices/SliceBackgroundWorker.java index 6eb154e9558..2b029999ef0 100644 --- a/src/com/android/settings/slices/SliceBackgroundWorker.java +++ b/src/com/android/settings/slices/SliceBackgroundWorker.java @@ -33,6 +33,7 @@ import java.io.Closeable; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -190,7 +191,8 @@ public abstract class SliceBackgroundWorker implements Closeable { private static NotifySliceChangeHandler sHandler; - private final Map mLastUpdateTimeLookup = new ArrayMap<>(); + private final Map mLastUpdateTimeLookup = Collections.synchronizedMap( + new ArrayMap<>()); private static NotifySliceChangeHandler getInstance() { if (sHandler == null) { From 61147df890caf7558dc56f7d2ebb51e8b15f5f61 Mon Sep 17 00:00:00 2001 From: Stanley Wang Date: Thu, 2 Jul 2020 14:13:18 +0800 Subject: [PATCH 3/3] Fix the bug of showing the "Smooth display" item in the search result. The controller can't be created when Settings Search gets the non-indexable keys. So Settings Search can't get the correct value from it. The controller creates the Handler without the parameter in constructor and causes the exception. It should use the main Looper of Context as the parameter to create the Handler. Fixes: 160179400 Test: run robotest and observe the search result Change-Id: I6f9bf6de087ae776e8d531ff59d28966aee96b7b --- .../settings/display/PeakRefreshRatePreferenceController.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java index 091ae326484..10cab1c9e27 100644 --- a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java +++ b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java @@ -27,7 +27,6 @@ import android.view.Display; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import androidx.preference.SwitchPreference; import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; @@ -45,7 +44,6 @@ public class PeakRefreshRatePreferenceController extends TogglePreferenceControl @VisibleForTesting float mPeakRefreshRate; private static final String TAG = "RefreshRatePrefCtr"; - private static final String KEY_PEAK_REFRESH_RATE_DEFAULT = "peak_refresh_rate_default"; private static final float INVALIDATE_REFRESH_RATE = -1f; private final Handler mHandler; @@ -59,7 +57,7 @@ public class PeakRefreshRatePreferenceController extends TogglePreferenceControl public PeakRefreshRatePreferenceController(Context context, String key) { super(context, key); - mHandler = new Handler(); + mHandler = new Handler(context.getMainLooper()); mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); mOnDeviceConfigChange = new IDeviceConfigChange() {