Merge "2nd attempt to fix Slice strict mode." into pi-dev
am: 7d214f99ee
Change-Id: If0e5bec4bc187f4e77848a1af2fd861f8bb7cbdb
This commit is contained in:
@@ -17,8 +17,6 @@ package com.android.settings.bluetooth;
|
|||||||
|
|
||||||
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
|
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
|
||||||
|
|
||||||
import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
|
|
||||||
|
|
||||||
import android.annotation.ColorInt;
|
import android.annotation.ColorInt;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
@@ -28,6 +26,7 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.SettingsSlicesContract;
|
import android.provider.SettingsSlicesContract;
|
||||||
|
import android.support.v4.graphics.drawable.IconCompat;
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto;
|
import com.android.internal.logging.nano.MetricsProto;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
@@ -42,8 +41,6 @@ import androidx.slice.Slice;
|
|||||||
import androidx.slice.builders.ListBuilder;
|
import androidx.slice.builders.ListBuilder;
|
||||||
import androidx.slice.builders.SliceAction;
|
import androidx.slice.builders.SliceAction;
|
||||||
|
|
||||||
import android.support.v4.graphics.drawable.IconCompat;
|
|
||||||
|
|
||||||
public class BluetoothSliceBuilder {
|
public class BluetoothSliceBuilder {
|
||||||
|
|
||||||
private static final String TAG = "BluetoothSliceBuilder";
|
private static final String TAG = "BluetoothSliceBuilder";
|
||||||
@@ -71,7 +68,8 @@ public class BluetoothSliceBuilder {
|
|||||||
INTENT_FILTER.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
|
INTENT_FILTER.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BluetoothSliceBuilder() {}
|
private BluetoothSliceBuilder() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a Bluetooth Slice bound to {@link #BLUETOOTH_URI}.
|
* Return a Bluetooth Slice bound to {@link #BLUETOOTH_URI}.
|
||||||
@@ -80,7 +78,7 @@ public class BluetoothSliceBuilder {
|
|||||||
* Bluetooth.
|
* Bluetooth.
|
||||||
*/
|
*/
|
||||||
public static Slice getSlice(Context context) {
|
public static Slice getSlice(Context context) {
|
||||||
final boolean isBluetoothEnabled = isBluetoothEnabled(context);
|
final boolean isBluetoothEnabled = isBluetoothEnabled();
|
||||||
final CharSequence title = context.getText(R.string.bluetooth_settings);
|
final CharSequence title = context.getText(R.string.bluetooth_settings);
|
||||||
final IconCompat icon = IconCompat.createWithResource(context,
|
final IconCompat icon = IconCompat.createWithResource(context,
|
||||||
R.drawable.ic_settings_bluetooth);
|
R.drawable.ic_settings_bluetooth);
|
||||||
@@ -115,9 +113,8 @@ public class BluetoothSliceBuilder {
|
|||||||
// handle it.
|
// handle it.
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isBluetoothEnabled(Context context) {
|
private static boolean isBluetoothEnabled() {
|
||||||
final LocalBluetoothAdapter adapter = LocalBluetoothManager.getInstance(context,
|
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
null /* callback */).getBluetoothAdapter();
|
|
||||||
return adapter.isEnabled();
|
return adapter.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,23 +23,23 @@ import android.content.ContentResolver;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.StrictMode;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.provider.SettingsSlicesContract;
|
import android.provider.SettingsSlicesContract;
|
||||||
import android.support.annotation.VisibleForTesting;
|
import android.support.annotation.VisibleForTesting;
|
||||||
import android.support.v4.graphics.drawable.IconCompat;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.KeyValueListParser;
|
import android.util.KeyValueListParser;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.android.settings.location.LocationSliceBuilder;
|
import com.android.settings.bluetooth.BluetoothSliceBuilder;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
|
||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settings.location.LocationSliceBuilder;
|
||||||
|
import com.android.settings.notification.ZenModeSliceBuilder;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.wifi.WifiSliceBuilder;
|
import com.android.settings.wifi.WifiSliceBuilder;
|
||||||
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
|
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
|
||||||
import com.android.settings.bluetooth.BluetoothSliceBuilder;
|
|
||||||
import com.android.settings.notification.ZenModeSliceBuilder;
|
|
||||||
import com.android.settingslib.SliceBroadcastRelay;
|
import com.android.settingslib.SliceBroadcastRelay;
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ public class SettingsSliceProvider extends SliceProvider {
|
|||||||
@Override
|
@Override
|
||||||
public void onSlicePinned(Uri sliceUri) {
|
public void onSlicePinned(Uri sliceUri) {
|
||||||
if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) {
|
if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) {
|
||||||
registerIntentToUri(WifiSliceBuilder.INTENT_FILTER , sliceUri);
|
registerIntentToUri(WifiSliceBuilder.INTENT_FILTER, sliceUri);
|
||||||
return;
|
return;
|
||||||
} else if (ZenModeSliceBuilder.ZEN_MODE_URI.equals(sliceUri)) {
|
} else if (ZenModeSliceBuilder.ZEN_MODE_URI.equals(sliceUri)) {
|
||||||
registerIntentToUri(ZenModeSliceBuilder.INTENT_FILTER, sliceUri);
|
registerIntentToUri(ZenModeSliceBuilder.INTENT_FILTER, sliceUri);
|
||||||
@@ -176,6 +176,13 @@ public class SettingsSliceProvider extends SliceProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Slice onBindSlice(Uri sliceUri) {
|
public Slice onBindSlice(Uri sliceUri) {
|
||||||
|
final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
|
||||||
|
try {
|
||||||
|
if (!ThreadUtils.isMainThread()) {
|
||||||
|
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
|
||||||
|
.permitAll()
|
||||||
|
.build());
|
||||||
|
}
|
||||||
final Set<String> blockedKeys = getBlockedKeys();
|
final Set<String> blockedKeys = getBlockedKeys();
|
||||||
final String key = sliceUri.getLastPathSegment();
|
final String key = sliceUri.getLastPathSegment();
|
||||||
if (blockedKeys.contains(key)) {
|
if (blockedKeys.contains(key)) {
|
||||||
@@ -211,6 +218,9 @@ public class SettingsSliceProvider extends SliceProvider {
|
|||||||
mSliceWeakDataCache.remove(sliceUri);
|
mSliceWeakDataCache.remove(sliceUri);
|
||||||
}
|
}
|
||||||
return SliceBuilderUtils.buildSlice(getContext(), cachedSliceData);
|
return SliceBuilderUtils.buildSlice(getContext(), cachedSliceData);
|
||||||
|
} finally {
|
||||||
|
StrictMode.setThreadPolicy(oldPolicy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -18,9 +18,7 @@
|
|||||||
package com.android.settings.slices;
|
package com.android.settings.slices;
|
||||||
|
|
||||||
import static android.content.ContentResolver.SCHEME_CONTENT;
|
import static android.content.ContentResolver.SCHEME_CONTENT;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
@@ -38,19 +36,24 @@ import android.os.StrictMode;
|
|||||||
import android.provider.SettingsSlicesContract;
|
import android.provider.SettingsSlicesContract;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
|
||||||
import com.android.settings.location.LocationSliceBuilder;
|
|
||||||
import com.android.settings.wifi.WifiSliceBuilder;
|
|
||||||
import com.android.settings.bluetooth.BluetoothSliceBuilder;
|
import com.android.settings.bluetooth.BluetoothSliceBuilder;
|
||||||
|
import com.android.settings.location.LocationSliceBuilder;
|
||||||
import com.android.settings.notification.ZenModeSliceBuilder;
|
import com.android.settings.notification.ZenModeSliceBuilder;
|
||||||
import com.android.settings.testutils.DatabaseTestUtils;
|
import com.android.settings.testutils.DatabaseTestUtils;
|
||||||
import com.android.settings.testutils.FakeToggleController;
|
import com.android.settings.testutils.FakeToggleController;
|
||||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowThreadUtils;
|
||||||
|
import com.android.settings.wifi.WifiSliceBuilder;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.annotation.Implementation;
|
||||||
|
import org.robolectric.annotation.Implements;
|
||||||
|
import org.robolectric.annotation.Resetter;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -66,6 +69,7 @@ import androidx.slice.Slice;
|
|||||||
* TODO Investigate using ShadowContentResolver.registerProviderInternal(String, ContentProvider)
|
* TODO Investigate using ShadowContentResolver.registerProviderInternal(String, ContentProvider)
|
||||||
*/
|
*/
|
||||||
@RunWith(SettingsRobolectricTestRunner.class)
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(shadows = ShadowThreadUtils.class)
|
||||||
public class SettingsSliceProviderTest {
|
public class SettingsSliceProviderTest {
|
||||||
|
|
||||||
private static final String KEY = "KEY";
|
private static final String KEY = "KEY";
|
||||||
@@ -98,6 +102,7 @@ public class SettingsSliceProviderTest {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
mContext = spy(RuntimeEnvironment.application);
|
mContext = spy(RuntimeEnvironment.application);
|
||||||
mProvider = spy(new SettingsSliceProvider());
|
mProvider = spy(new SettingsSliceProvider());
|
||||||
|
ShadowStrictMode.reset();
|
||||||
mProvider.mSliceWeakDataCache = new HashMap<>();
|
mProvider.mSliceWeakDataCache = new HashMap<>();
|
||||||
mProvider.mSliceDataCache = new HashMap<>();
|
mProvider.mSliceDataCache = new HashMap<>();
|
||||||
mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext);
|
mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext);
|
||||||
@@ -112,6 +117,7 @@ public class SettingsSliceProviderTest {
|
|||||||
|
|
||||||
@After
|
@After
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
|
ShadowThreadUtils.reset();
|
||||||
DatabaseTestUtils.clearDb(mContext);
|
DatabaseTestUtils.clearDb(mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +190,8 @@ public class SettingsSliceProviderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onBindSlice_shouldNotOverrideStrictMode() {
|
public void onBindSlice_mainThread_shouldNotOverrideStrictMode() {
|
||||||
|
ShadowThreadUtils.setIsMainThread(true);
|
||||||
final StrictMode.ThreadPolicy oldThreadPolicy = StrictMode.getThreadPolicy();
|
final StrictMode.ThreadPolicy oldThreadPolicy = StrictMode.getThreadPolicy();
|
||||||
SliceData data = getDummyData();
|
SliceData data = getDummyData();
|
||||||
mProvider.mSliceWeakDataCache.put(data.getUri(), data);
|
mProvider.mSliceWeakDataCache.put(data.getUri(), data);
|
||||||
@@ -195,6 +202,18 @@ public class SettingsSliceProviderTest {
|
|||||||
assertThat(newThreadPolicy.toString()).isEqualTo(oldThreadPolicy.toString());
|
assertThat(newThreadPolicy.toString()).isEqualTo(oldThreadPolicy.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = ShadowStrictMode.class)
|
||||||
|
public void onBindSlice_backgroundThread_shouldOverrideStrictMode() {
|
||||||
|
ShadowThreadUtils.setIsMainThread(false);
|
||||||
|
|
||||||
|
SliceData data = getDummyData();
|
||||||
|
mProvider.mSliceWeakDataCache.put(data.getUri(), data);
|
||||||
|
mProvider.onBindSlice(data.getUri());
|
||||||
|
|
||||||
|
assertThat(ShadowStrictMode.isThreadPolicyOverridden()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onBindSlice_requestsBlockedSlice_retunsNull() {
|
public void onBindSlice_requestsBlockedSlice_retunsNull() {
|
||||||
final String blockedKey = "blocked_key";
|
final String blockedKey = "blocked_key";
|
||||||
@@ -456,7 +475,7 @@ public class SettingsSliceProviderTest {
|
|||||||
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
|
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SliceData getDummyData() {
|
private static SliceData getDummyData() {
|
||||||
return new SliceData.Builder()
|
return new SliceData.Builder()
|
||||||
.setKey(KEY)
|
.setKey(KEY)
|
||||||
.setTitle(TITLE)
|
.setTitle(TITLE)
|
||||||
@@ -468,4 +487,24 @@ public class SettingsSliceProviderTest {
|
|||||||
.setPreferenceControllerClassName(PREF_CONTROLLER)
|
.setPreferenceControllerClassName(PREF_CONTROLLER)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Implements(value = StrictMode.class, inheritImplementationMethods = true)
|
||||||
|
public static class ShadowStrictMode {
|
||||||
|
|
||||||
|
private static int sSetThreadPolicyCount;
|
||||||
|
|
||||||
|
@Resetter
|
||||||
|
public static void reset() {
|
||||||
|
sSetThreadPolicyCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public static void setThreadPolicy(final StrictMode.ThreadPolicy policy) {
|
||||||
|
sSetThreadPolicyCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isThreadPolicyOverridden() {
|
||||||
|
return sSetThreadPolicyCount != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -20,10 +20,18 @@ import com.android.settingslib.utils.ThreadUtils;
|
|||||||
|
|
||||||
import org.robolectric.annotation.Implementation;
|
import org.robolectric.annotation.Implementation;
|
||||||
import org.robolectric.annotation.Implements;
|
import org.robolectric.annotation.Implements;
|
||||||
|
import org.robolectric.annotation.Resetter;
|
||||||
|
|
||||||
@Implements(ThreadUtils.class)
|
@Implements(ThreadUtils.class)
|
||||||
public class ShadowThreadUtils {
|
public class ShadowThreadUtils {
|
||||||
|
|
||||||
|
private static boolean sIsMainThread = true;
|
||||||
|
|
||||||
|
@Resetter
|
||||||
|
public static void reset() {
|
||||||
|
sIsMainThread = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Implementation
|
@Implementation
|
||||||
public static void postOnBackgroundThread(Runnable runnable) {
|
public static void postOnBackgroundThread(Runnable runnable) {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
@@ -33,4 +41,14 @@ public class ShadowThreadUtils {
|
|||||||
public static void postOnMainThread(Runnable runnable) {
|
public static void postOnMainThread(Runnable runnable) {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public static boolean isMainThread() {
|
||||||
|
return sIsMainThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setIsMainThread(boolean isMainThread) {
|
||||||
|
sIsMainThread = isMainThread;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user