From a559103b1b5f68c4e468d3cc5573619c762a6f2e Mon Sep 17 00:00:00 2001 From: Matthew Fritze Date: Thu, 24 May 2018 16:09:05 -0700 Subject: [PATCH] Fix DND crash from SpringboardActivity Special case Uris need to explicitly add their intents. This unfortunately duplicates a list of special-cased Slices, but I have attached a bug with a plan to address this duplicity in Q. Change-Id: I346915c32543713d33716422018d7c950cce323d Fixes: 80065409 Test: atest SliceDeepLinkSpringBoardTest --- .../bluetooth/BluetoothSliceBuilder.java | 21 +++--- .../location/LocationSliceBuilder.java | 7 +- .../notification/ZenModeSliceBuilder.java | 22 +++--- .../slices/SliceDeepLinkSpringBoard.java | 37 ++++++++-- .../settings/wifi/WifiSliceBuilder.java | 21 +++--- .../slices/SliceDeepLinkSpringBoardTest.java | 69 ++++++++++++++++--- 6 files changed, 132 insertions(+), 45 deletions(-) diff --git a/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java b/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java index da759a33e5e..a8bb1cad6c1 100644 --- a/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java +++ b/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java @@ -100,6 +100,17 @@ public class BluetoothSliceBuilder { .build(); } + public static Intent getIntent(Context context) { + final String screenTitle = context.getText(R.string.bluetooth_settings_title).toString(); + final Uri contentUri = new Uri.Builder().appendPath( + SettingsSlicesContract.KEY_BLUETOOTH).build(); + return DatabaseIndexingUtils.buildSearchResultPageIntent(context, + BluetoothDashboardFragment.class.getName(), null /* key */, screenTitle, + MetricsProto.MetricsEvent.SETTINGS_CONNECTED_DEVICE_CATEGORY) + .setClassName(context.getPackageName(), SubSettings.class.getName()) + .setData(contentUri); + } + /** * Update the current Bluetooth status to the boolean value keyed by * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}. @@ -122,15 +133,7 @@ public class BluetoothSliceBuilder { } private static PendingIntent getPrimaryAction(Context context) { - final String screenTitle = context.getText(R.string.bluetooth_settings_title).toString(); - final Uri contentUri = new Uri.Builder().appendPath( - SettingsSlicesContract.KEY_BLUETOOTH).build(); - final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context, - BluetoothDashboardFragment.class.getName(), null /* key */, screenTitle, - MetricsProto.MetricsEvent.SETTINGS_CONNECTED_DEVICE_CATEGORY) - .setClassName(context.getPackageName(), SubSettings.class.getName()) - .setData(contentUri); - + final Intent intent = getIntent(context); return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */); } diff --git a/src/com/android/settings/location/LocationSliceBuilder.java b/src/com/android/settings/location/LocationSliceBuilder.java index e69ccfba54c..4cf861f55a7 100644 --- a/src/com/android/settings/location/LocationSliceBuilder.java +++ b/src/com/android/settings/location/LocationSliceBuilder.java @@ -79,15 +79,18 @@ public class LocationSliceBuilder { .build(); } - private static PendingIntent getPrimaryAction(Context context) { + public static Intent getIntent(Context context) { final String screenTitle = context.getText(R.string.location_settings_title).toString(); final Uri contentUri = new Uri.Builder().appendPath(KEY_LOCATION).build(); - final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context, + return DatabaseIndexingUtils.buildSearchResultPageIntent(context, LocationSettings.class.getName(), KEY_LOCATION, screenTitle, MetricsEvent.LOCATION) .setClassName(context.getPackageName(), SubSettings.class.getName()) .setData(contentUri); + } + private static PendingIntent getPrimaryAction(Context context) { + final Intent intent = getIntent(context); return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */); } diff --git a/src/com/android/settings/notification/ZenModeSliceBuilder.java b/src/com/android/settings/notification/ZenModeSliceBuilder.java index aedd0b3e4c3..16591ce33c7 100644 --- a/src/com/android/settings/notification/ZenModeSliceBuilder.java +++ b/src/com/android/settings/notification/ZenModeSliceBuilder.java @@ -123,6 +123,16 @@ public class ZenModeSliceBuilder { // handle it. } + public static Intent getIntent(Context context) { + final Uri contentUri = new Uri.Builder().appendPath(ZEN_MODE_KEY).build(); + final String screenTitle = context.getText(R.string.zen_mode_settings_title).toString(); + return DatabaseIndexingUtils.buildSearchResultPageIntent(context, + ZenModeSettings.class.getName(), ZEN_MODE_KEY, screenTitle, + MetricsEvent.NOTIFICATION_ZEN_MODE) + .setClassName(context.getPackageName(), SubSettings.class.getName()) + .setData(contentUri); + } + private static boolean isZenModeEnabled(Context context) { final NotificationManager manager = context.getSystemService(NotificationManager.class); final int zenMode = manager.getZenMode(); @@ -139,16 +149,8 @@ public class ZenModeSliceBuilder { } private static PendingIntent getPrimaryAction(Context context) { - final String screenTitle = context.getText(R.string.zen_mode_settings_title).toString(); - final Uri contentUri = new Uri.Builder().appendPath(ZEN_MODE_KEY).build(); - final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context, - ZenModeSettings.class.getName(), ZEN_MODE_KEY, screenTitle, - MetricsEvent.NOTIFICATION_ZEN_MODE) - .setClassName(context.getPackageName(), SubSettings.class.getName()) - .setData(contentUri); - - return PendingIntent.getActivity(context, 0 /* requestCode */, - intent, 0 /* flags */); + final Intent intent = getIntent(context); + return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */); } private static PendingIntent getBroadcastIntent(Context context) { diff --git a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java index 7f1a0f35cae..4f8ed96b9a5 100644 --- a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java +++ b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java @@ -18,8 +18,16 @@ import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.provider.Settings; import android.util.Log; +import com.android.settings.bluetooth.BluetoothSliceBuilder; +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.calling.WifiCallingSliceHelper; + import java.net.URISyntaxException; public class SliceDeepLinkSpringBoard extends Activity { @@ -44,11 +52,26 @@ public class SliceDeepLinkSpringBoard extends Activity { if (ACTION_VIEW_SLICE.equals(intent.getAction())) { // This shouldn't matter since the slice is shown instead of the device // index caring about the launch uri. - Uri slice = Uri.parse(intent.getStringExtra(EXTRA_SLICE)); - SlicesDatabaseAccessor slicesDatabaseAccessor = new SlicesDatabaseAccessor(this); - // Sadly have to block here because we don't know where to go. - final SliceData sliceData = slicesDatabaseAccessor.getSliceDataFromUri(slice); - Intent launchIntent = SliceBuilderUtils.getContentIntent(this, sliceData); + final Uri slice = Uri.parse(intent.getStringExtra(EXTRA_SLICE)); + final Intent launchIntent; + + // TODO (b/80263568) Avoid duplicating this list of Slice Uris. + if (WifiSliceBuilder.WIFI_URI.equals(slice)) { + launchIntent = WifiSliceBuilder.getIntent(this /* context */); + } else if (ZenModeSliceBuilder.ZEN_MODE_URI.equals(slice)) { + launchIntent = ZenModeSliceBuilder.getIntent(this /* context */); + } else if (BluetoothSliceBuilder.BLUETOOTH_URI.equals(slice)) { + launchIntent = BluetoothSliceBuilder.getIntent(this /* context */); + } else if (LocationSliceBuilder.LOCATION_URI.equals(slice)) { + launchIntent = LocationSliceBuilder.getIntent(this /* context */); + } else { + final SlicesDatabaseAccessor slicesDatabaseAccessor = + new SlicesDatabaseAccessor(this /* context */); + // Sadly have to block here because we don't know where to go. + final SliceData sliceData = slicesDatabaseAccessor.getSliceDataFromUri(slice); + launchIntent = SliceBuilderUtils.getContentIntent(this, sliceData); + } + startActivity(launchIntent); } else { startActivity(intent); @@ -57,6 +80,10 @@ public class SliceDeepLinkSpringBoard extends Activity { } catch (URISyntaxException e) { Log.e(TAG, "Error decoding uri", e); finish(); + } catch (IllegalStateException e) { + Log.w(TAG, "Couldn't launch Slice intent", e); + startActivity(new Intent(Settings.ACTION_SETTINGS)); + finish(); } } diff --git a/src/com/android/settings/wifi/WifiSliceBuilder.java b/src/com/android/settings/wifi/WifiSliceBuilder.java index 7df7f19ad78..21a9455ab2c 100644 --- a/src/com/android/settings/wifi/WifiSliceBuilder.java +++ b/src/com/android/settings/wifi/WifiSliceBuilder.java @@ -121,6 +121,18 @@ public class WifiSliceBuilder { // handle it. } + public static Intent getIntent(Context context) { + final String screenTitle = context.getText(R.string.wifi_settings).toString(); + final Uri contentUri = new Uri.Builder().appendPath(KEY_WIFI).build(); + final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context, + WifiSettings.class.getName(), KEY_WIFI, screenTitle, + MetricsEvent.DIALOG_WIFI_AP_EDIT) + .setClassName(context.getPackageName(), SubSettings.class.getName()) + .setData(contentUri); + + return intent; + } + private static boolean isWifiEnabled(Context context) { final WifiManager wifiManager = context.getSystemService(WifiManager.class); @@ -159,14 +171,7 @@ public class WifiSliceBuilder { } private static PendingIntent getPrimaryAction(Context context) { - final String screenTitle = context.getText(R.string.wifi_settings).toString(); - final Uri contentUri = new Uri.Builder().appendPath(KEY_WIFI).build(); - final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context, - WifiSettings.class.getName(), KEY_WIFI, screenTitle, - MetricsEvent.DIALOG_WIFI_AP_EDIT); - intent.setClassName(context.getPackageName(), SubSettings.class.getName()); - intent.setData(contentUri); - + final Intent intent = getIntent(context); return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */); } diff --git a/tests/unit/src/com/android/settings/slices/SliceDeepLinkSpringBoardTest.java b/tests/unit/src/com/android/settings/slices/SliceDeepLinkSpringBoardTest.java index e7c5d6e30fe..91057b83d4d 100644 --- a/tests/unit/src/com/android/settings/slices/SliceDeepLinkSpringBoardTest.java +++ b/tests/unit/src/com/android/settings/slices/SliceDeepLinkSpringBoardTest.java @@ -21,14 +21,22 @@ import static com.android.settings.search.DeviceIndexFeatureProvider.createDeepL import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.platform.test.annotations.Presubmit; import android.support.test.InstrumentationRegistry; +import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; +import com.android.settings.bluetooth.BluetoothSliceBuilder; +import com.android.settings.location.LocationSliceBuilder; +import com.android.settings.notification.ZenModeSliceBuilder; +import com.android.settings.wifi.WifiSliceBuilder; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) +@MediumTest public class SliceDeepLinkSpringBoardTest { private Context mContext; @@ -38,18 +46,57 @@ public class SliceDeepLinkSpringBoardTest { } @Test - public void launcheDeepLinkIntent_shouldNotCrash() { - final Uri springBoardIntentUri = createDeepLink( - new Intent(SliceDeepLinkSpringBoard.ACTION_VIEW_SLICE) - .setPackage(mContext.getPackageName()) - .putExtra(SliceDeepLinkSpringBoard.EXTRA_SLICE, - "content://com.android.settings.slices/action/test_slice") - .toUri(Intent.URI_ANDROID_APP_SCHEME)); - - final Intent deepLinkIntent = new Intent(Intent.ACTION_VIEW) - .setData(springBoardIntentUri) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + @Presubmit + public void launchesDeepLinkIntent_shouldNotCrash() { + final Intent deepLinkIntent = getSpringboardIntent( + "content://com.android.settings.slices/action/test_slice"); mContext.startActivity(deepLinkIntent); } + + @Test + @Presubmit + public void launchesDeepLinkIntent_wifiSlice_shouldNotCrash() { + final Intent deepLinkIntent = getSpringboardIntent(WifiSliceBuilder.WIFI_URI.toString()); + + mContext.startActivity(deepLinkIntent); + } + + @Test + @Presubmit + public void launchesDeepLinkIntent_bluetoothSlice_shouldNotCrash() { + final Intent deepLinkIntent = getSpringboardIntent( + BluetoothSliceBuilder.BLUETOOTH_URI.toString()); + + mContext.startActivity(deepLinkIntent); + } + + @Test + @Presubmit + public void launchesDeepLinkIntent_dndSlice_shouldNotCrash() { + final Intent deepLinkIntent = getSpringboardIntent( + ZenModeSliceBuilder.ZEN_MODE_URI.toString()); + + mContext.startActivity(deepLinkIntent); + } + + @Test + @Presubmit + public void launchesDeepLinkIntent_locationSlice_shouldNotCrash() { + final Intent deepLinkIntent = getSpringboardIntent( + LocationSliceBuilder.LOCATION_URI.toString()); + + mContext.startActivity(deepLinkIntent); + } + + private Intent getSpringboardIntent(String uriString) { + final Uri uri = createDeepLink(new Intent(SliceDeepLinkSpringBoard.ACTION_VIEW_SLICE) + .setPackage(mContext.getPackageName()) + .putExtra(SliceDeepLinkSpringBoard.EXTRA_SLICE, uriString) + .toUri(Intent.URI_ANDROID_APP_SCHEME)); + + return new Intent(Intent.ACTION_VIEW) + .setData(uri) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } }