Link to app-provided configuration intent for app-owned rules.

If there is no valid intent, the automatic trigger preference is disabled.

Flag: android.app.modes_ui
Bug: 341961712
Test: manual (for Bedtime & Driving modes), ZenModeSetTriggerLinkPreferenceControllerTest

Change-Id: I673792effb3cfdcaaa7cf85adfb55a93b44dcc86
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a490856..d60e357 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8076,6 +8076,9 @@
     <!-- Duration in hours and minutes for the length of a Do Not Disturb schedule. For example "1 hr, 22 min" -->
     <string name="zen_mode_schedule_duration"><xliff:g example="10" id="hours">%1$d</xliff:g> hr, <xliff:g example="20" id="minutes">%2$d</xliff:g> min</string>
 
+    <!-- Priority Modes: Label for switch to enable/disable a rule turning on automatically; links to an app-provided configuration page [CHAR LIMIT=40] -->
+    <string name="zen_mode_configuration_link_title">Turn on automatically</string>
+
     <!--  Do not disturb: Title do not disturb settings representing automatic (scheduled) do not disturb rules. [CHAR LIMIT=30] -->
     <string name="zen_mode_schedule_category_title">Schedule</string>
 
diff --git a/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java b/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java
index 9f819d1..a4bd2aa 100644
--- a/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java
+++ b/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java
@@ -24,6 +24,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
 
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.notification.modes.ZenMode;
@@ -92,6 +93,16 @@
     }
 
     @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        if (mZenMode != null) {
+            displayPreference(screen, mZenMode);
+        }
+    }
+
+    public void displayPreference(PreferenceScreen screen, @NonNull ZenMode zenMode) {}
+
+    @Override
     public final void updateState(Preference preference) {
         super.updateState(preference);
         if (mZenMode != null) {
diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java
index 67815b1..3a64fb2 100644
--- a/src/com/android/settings/notification/modes/ZenModeFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeFragment.java
@@ -35,6 +35,7 @@
 import java.util.List;
 
 public class ZenModeFragment extends ZenModeFragmentBase {
+
     // for mode deletion menu
     private static final int DELETE_MODE = 1;
 
@@ -61,7 +62,8 @@
         prefControllers.add(new ZenModeDisplayLinkPreferenceController(
                 context, "mode_display_settings", mBackend, mHelperBackend));
         prefControllers.add(new ZenModeSetTriggerLinkPreferenceController(context,
-                "zen_automatic_trigger_category", this, mBackend));
+                "zen_automatic_trigger_category", this, mBackend,
+                context.getPackageManager()));
         prefControllers.add(new InterruptionFilterPreferenceController(
                 context, "allow_filtering", mBackend));
         prefControllers.add(new ManualDurationPreferenceController(
diff --git a/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
index 1c96fee..7328d91 100644
--- a/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
@@ -18,34 +18,62 @@
 
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
+import static android.app.NotificationManager.EXTRA_AUTOMATIC_RULE_ID;
 
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.service.notification.ConditionProviderService;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.utils.ManagedServiceSettings;
+import com.android.settings.utils.ZenServiceListing;
 import com.android.settingslib.PrimarySwitchPreference;
 import com.android.settingslib.notification.modes.ZenMode;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
+import java.util.List;
+
 /**
  * Preference controller for the link to an individual mode's configuration page.
  */
 class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenceController {
+    private static final String TAG = "ZenModeSetTriggerLink";
+
     @VisibleForTesting
     protected static final String AUTOMATIC_TRIGGER_PREF_KEY = "zen_automatic_trigger_settings";
 
+    private static final ManagedServiceSettings.Config CONFIG =
+            ZenModesListFragment.getConditionProviderConfig();
+
+    private ZenServiceListing mServiceListing;
+    private final PackageManager mPm;
     private final DashboardFragment mFragment;
 
     ZenModeSetTriggerLinkPreferenceController(Context context, String key,
-            DashboardFragment fragment,
-            ZenModesBackend backend) {
+            DashboardFragment fragment, ZenModesBackend backend,
+            PackageManager packageManager) {
         super(context, key, backend);
         mFragment = fragment;
+        mPm = packageManager;
+    }
+
+    @VisibleForTesting
+    protected void setServiceListing(ZenServiceListing serviceListing) {
+        mServiceListing = serviceListing;
     }
 
     @Override
@@ -54,6 +82,15 @@
     }
 
     @Override
+    public void displayPreference(PreferenceScreen screen, @NonNull ZenMode zenMode) {
+        if (mServiceListing == null) {
+            mServiceListing = new ZenServiceListing(
+                    mContext, CONFIG, zenMode.getRule().getPackageName());
+        }
+        mServiceListing.reloadApprovedServices();
+    }
+
+    @Override
     public void updateState(Preference preference, @NonNull ZenMode zenMode) {
         // This controller is expected to govern a preference category so that it controls the
         // availability of the entire preference category if the mode doesn't have a way to
@@ -70,29 +107,39 @@
         switchPref.setOnPreferenceClickListener(null);
         switchPref.setIntent(null);
 
-        if (zenMode.isSystemOwned() && zenMode.getType() == TYPE_SCHEDULE_TIME) {
-            switchPref.setTitle(R.string.zen_mode_set_schedule_link);
-            // TODO: b/332937635 - set correct metrics category
-            switchPref.setIntent(ZenSubSettingLauncher.forModeFragment(mContext,
-                    ZenModeSetScheduleFragment.class, zenMode.getId(), 0).toIntent());
-        } else if (zenMode.isSystemOwned() && zenMode.getType() == TYPE_SCHEDULE_CALENDAR) {
-            switchPref.setTitle(R.string.zen_mode_set_calendar_link);
-            switchPref.setIcon(null);
-            // TODO: b/332937635 - set correct metrics category
-            switchPref.setIntent(ZenSubSettingLauncher.forModeFragment(mContext,
-                    ZenModeSetCalendarFragment.class, zenMode.getId(), 0).toIntent());
-        } else if (zenMode.isSystemOwned()) {
-            switchPref.setTitle(R.string.zen_mode_select_schedule);
-            switchPref.setIcon(R.drawable.ic_add_24dp);
-            switchPref.setSummary("");
-            // TODO: b/342156843 - Hide the switch (needs support in SettingsLib).
-            switchPref.setOnPreferenceClickListener(clickedPreference -> {
-                ZenModeScheduleChooserDialog.show(mFragment, mOnScheduleOptionListener);
-                return true;
-            });
+        if (zenMode.isSystemOwned()) {
+            if (zenMode.getType() == TYPE_SCHEDULE_TIME) {
+                switchPref.setTitle(R.string.zen_mode_set_schedule_link);
+                // TODO: b/332937635 - set correct metrics category
+                switchPref.setIntent(ZenSubSettingLauncher.forModeFragment(mContext,
+                        ZenModeSetScheduleFragment.class, zenMode.getId(), 0).toIntent());
+            } else if (zenMode.getType() == TYPE_SCHEDULE_CALENDAR) {
+                switchPref.setTitle(R.string.zen_mode_set_calendar_link);
+                switchPref.setIcon(null);
+                // TODO: b/332937635 - set correct metrics category
+                switchPref.setIntent(ZenSubSettingLauncher.forModeFragment(mContext,
+                        ZenModeSetCalendarFragment.class, zenMode.getId(), 0).toIntent());
+            } else {
+                switchPref.setTitle(R.string.zen_mode_select_schedule);
+                switchPref.setIcon(R.drawable.ic_add_24dp);
+                switchPref.setSummary("");
+                // TODO: b/342156843 - Hide the switch (needs support in SettingsLib).
+                switchPref.setOnPreferenceClickListener(clickedPreference -> {
+                    ZenModeScheduleChooserDialog.show(mFragment, mOnScheduleOptionListener);
+                    return true;
+                });
+            }
         } else {
-            // TODO: b/341961712 - direct preference to app-owned intent if available
-            switchPref.setTitle("not implemented");
+            Intent intent = getAppRuleIntent(zenMode);
+            if (intent != null && isValidIntent(intent)) {
+                preference.setVisible(true);
+                switchPref.setTitle(R.string.zen_mode_configuration_link_title);
+                switchPref.setSummary(zenMode.getRule().getTriggerDescription());
+                switchPref.setIntent(intent);
+            } else {
+                Log.i(TAG, "No intent found for " + zenMode.getRule().getName());
+                preference.setVisible(false);
+            }
         }
     }
 
@@ -114,4 +161,68 @@
         });
         // TODO: b/342156843 - Do we want to jump to the corresponding schedule editing screen?
     };
+
+    @VisibleForTesting
+    protected @Nullable Intent getAppRuleIntent(ZenMode zenMode) {
+        Intent intent = new Intent().addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+                .putExtra(ConditionProviderService.EXTRA_RULE_ID, zenMode.getId())
+                .putExtra(EXTRA_AUTOMATIC_RULE_ID, zenMode.getId());
+        String owner = zenMode.getRule().getPackageName();
+        ComponentName configActivity = null;
+        if (zenMode.getRule().getConfigurationActivity() != null) {
+            // If a configuration activity is present, use that directly in the intent
+            configActivity = zenMode.getRule().getConfigurationActivity();
+        } else {
+            // Otherwise, look for a condition provider service for the rule's package
+            ComponentInfo ci = mServiceListing.findService(zenMode.getRule().getOwner());
+            if (ci == null) {
+                // do nothing
+            } else if (ci instanceof ActivityInfo) {
+                // new activity backed rule
+                intent.setComponent(new ComponentName(ci.packageName, ci.name));
+                return intent;
+            } else if (ci.metaData != null) {
+                // old service backed rule
+                final String configurationActivity = ci.metaData.getString(
+                        ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY);
+                if (configurationActivity != null) {
+                    configActivity = ComponentName.unflattenFromString(configurationActivity);
+                }
+            }
+        }
+
+        if (configActivity != null) {
+            // verify that the owner of the rule owns the configuration activity, but only if
+            // owner exists
+            intent.setComponent(configActivity);
+            if (owner == null) {
+                return intent;
+            }
+            try {
+                int ownerUid = mPm.getPackageUid(owner, 0);
+                int configActivityOwnerUid = mPm.getPackageUid(configActivity.getPackageName(), 0);
+                if (ownerUid == configActivityOwnerUid) {
+                    return intent;
+                } else {
+                    Log.w(TAG, "Config activity not in owner package for "
+                            + zenMode.getRule().getName());
+                    return null;
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "Failed to find config activity");
+                return null;
+            }
+        }
+        return null;
+    }
+
+    private boolean isValidIntent(Intent intent) {
+        List<ResolveInfo> results = mPm.queryIntentActivities(
+                intent, PackageManager.ResolveInfoFlags.of(0));
+        if (intent.resolveActivity(mPm) == null || results.size() == 0) {
+            Log.w(TAG, "intent for zen rule invalid: " + intent);
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/src/com/android/settings/notification/modes/ZenModesListFragment.java b/src/com/android/settings/notification/modes/ZenModesListFragment.java
index 77107f8..1883945 100644
--- a/src/com/android/settings/notification/modes/ZenModesListFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModesListFragment.java
@@ -78,7 +78,7 @@
         return SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION;
     }
 
-    private static ManagedServiceSettings.Config getConditionProviderConfig() {
+    static ManagedServiceSettings.Config getConditionProviderConfig() {
         return new ManagedServiceSettings.Config.Builder()
                 .setTag(TAG)
                 .setIntentAction(ConditionProviderService.SERVICE_INTERFACE)
diff --git a/src/com/android/settings/utils/ZenServiceListing.java b/src/com/android/settings/utils/ZenServiceListing.java
index 99f56f6..96d700b 100644
--- a/src/com/android/settings/utils/ZenServiceListing.java
+++ b/src/com/android/settings/utils/ZenServiceListing.java
@@ -28,11 +28,14 @@
 import android.util.ArraySet;
 import android.util.Slog;
 
+import androidx.annotation.Nullable;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
 public class ZenServiceListing {
+    private static final String TAG = "ZenServiceListing";
 
     private final Context mContext;
     private final ManagedServiceSettings.Config mConfig;
@@ -40,9 +43,18 @@
     private final List<Callback> mZenCallbacks = new ArrayList<>();
     private final NotificationManager mNm;
 
+    // only used when android.app.modes_ui flag is true
+    @Nullable
+    private String mPkg = null;
+
     public ZenServiceListing(Context context, ManagedServiceSettings.Config config) {
+        this(context, config, null);
+    }
+
+    public ZenServiceListing(Context context, ManagedServiceSettings.Config config, @Nullable String pkg) {
         mContext = context;
         mConfig = config;
+        mPkg = pkg;
         mNm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
     }
 
@@ -89,12 +101,16 @@
         }
     }
 
-    private static void getServices(ManagedServiceSettings.Config c, List<ComponentInfo> list,
+    private void getServices(ManagedServiceSettings.Config c, List<ComponentInfo> list,
             PackageManager pm) {
         final int user = ActivityManager.getCurrentUser();
 
+        Intent queryIntent = new Intent(c.intentAction);
+        if (mPkg != null) {
+            queryIntent.setPackage(mPkg);
+        }
         List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
-                new Intent(c.intentAction),
+                queryIntent,
                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
                 user);
 
@@ -115,12 +131,16 @@
         }
     }
 
-    private static void getActivities(ManagedServiceSettings.Config c, List<ComponentInfo> list,
+    private void getActivities(ManagedServiceSettings.Config c, List<ComponentInfo> list,
             PackageManager pm) {
         final int user = ActivityManager.getCurrentUser();
 
+        Intent queryIntent = new Intent(c.configIntentAction);
+        if (mPkg != null) {
+            queryIntent.setPackage(mPkg);
+        }
         List<ResolveInfo> resolveInfos = pm.queryIntentActivitiesAsUser(
-                new Intent(c.configIntentAction),
+                queryIntent,
                 PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA,
                 user);
 
diff --git a/tests/robotests/src/com/android/settings/notification/modes/TestModeBuilder.java b/tests/robotests/src/com/android/settings/notification/modes/TestModeBuilder.java
index 26c7fe1..6a1f474 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/TestModeBuilder.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/TestModeBuilder.java
@@ -18,6 +18,7 @@
 
 import android.app.AutomaticZenRule;
 import android.app.NotificationManager;
+import android.content.ComponentName;
 import android.net.Uri;
 import android.service.notification.Condition;
 import android.service.notification.ZenDeviceEffects;
@@ -149,6 +150,18 @@
         return this;
     }
 
+    TestModeBuilder setConfigurationActivity(ComponentName configActivity) {
+        mRule.setConfigurationActivity(configActivity);
+        mConfigZenRule.configurationActivity = configActivity;
+        return this;
+    }
+
+    TestModeBuilder setOwner(ComponentName owner) {
+        mRule.setOwner(owner);
+        mConfigZenRule.component = owner;
+        return this;
+    }
+
     ZenMode build() {
         return new ZenMode(mId, mRule, mConfigZenRule);
     }
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
index 31959e5..4ba2146 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
@@ -19,8 +19,10 @@
 import static android.app.AutomaticZenRule.TYPE_OTHER;
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
 import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
+import static android.app.NotificationManager.EXTRA_AUTOMATIC_RULE_ID;
 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+import static android.service.notification.ConditionProviderService.EXTRA_RULE_ID;
 
 import static com.android.settings.notification.modes.ZenModeSetTriggerLinkPreferenceController.AUTOMATIC_TRIGGER_PREF_KEY;
 
@@ -31,10 +33,16 @@
 
 import android.app.AutomaticZenRule;
 import android.app.Flags;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
 import android.net.Uri;
+import android.os.Bundle;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
+import android.service.notification.ConditionProviderService;
 import android.service.notification.SystemZenRules;
 import android.service.notification.ZenModeConfig;
 
@@ -44,6 +52,7 @@
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.utils.ZenServiceListing;
 import com.android.settingslib.PrimarySwitchPreference;
 import com.android.settingslib.notification.modes.ZenMode;
 import com.android.settingslib.notification.modes.ZenModesBackend;
@@ -72,6 +81,11 @@
     private PrimarySwitchPreference mPreference;
 
     @Mock
+    private ZenServiceListing mServiceListing;
+    @Mock
+    private PackageManager mPm;
+
+    @Mock
     private PreferenceCategory mPrefCategory;
     @Mock
     private DashboardFragment mFragment;
@@ -84,8 +98,10 @@
         mContext = ApplicationProvider.getApplicationContext();
 
         mPrefController = new ZenModeSetTriggerLinkPreferenceController(mContext,
-                "zen_automatic_trigger_category", mFragment, mBackend);
+                "zen_automatic_trigger_category", mFragment, mBackend, mPm);
+        mPrefController.setServiceListing(mServiceListing);
         mPreference = new PrimarySwitchPreference(mContext);
+
         when(mPrefCategory.findPreference(AUTOMATIC_TRIGGER_PREF_KEY)).thenReturn(mPreference);
     }
 
@@ -93,9 +109,9 @@
     public void testIsAvailable() {
         // should not be available for manual DND
         ZenMode manualMode = ZenMode.manualDndMode(new AutomaticZenRule.Builder("Do Not Disturb",
-                        Uri.parse("manual"))
-                        .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
-                        .build(), true);
+                Uri.parse("manual"))
+                .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+                .build(), true);
 
         mPrefController.updateZenMode(mPrefCategory, manualMode);
         assertThat(mPrefController.isAvailable()).isFalse();
@@ -164,7 +180,7 @@
     @Test
     public void testRuleLink_schedule() {
         ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo();
-        scheduleInfo.days = new int[] { Calendar.MONDAY, Calendar.TUESDAY, Calendar.THURSDAY };
+        scheduleInfo.days = new int[]{Calendar.MONDAY, Calendar.TUESDAY, Calendar.THURSDAY};
         scheduleInfo.startHour = 1;
         scheduleInfo.endHour = 15;
         ZenMode mode = new TestModeBuilder()
@@ -237,4 +253,109 @@
         assertThat(updatedMode.getRule().getOwner()).isEqualTo(
                 ZenModeConfig.getScheduleConditionProvider());
     }
+
+    @Test
+    public void testGetAppRuleIntent_configActivity() throws Exception {
+        ZenMode mode = new TestModeBuilder()
+                .setId("id")
+                .setPackage(mContext.getPackageName())
+                .setConfigurationActivity(new ComponentName(mContext.getPackageName(), "test"))
+                .setType(TYPE_OTHER)
+                .setTriggerDescription("some rule")
+                .build();
+
+        when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+        when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+        Intent res = mPrefController.getAppRuleIntent(mode);
+        assertThat(res).isNotNull();
+        assertThat(res.getStringExtra(EXTRA_RULE_ID)).isEqualTo("id");
+        assertThat(res.getStringExtra(EXTRA_AUTOMATIC_RULE_ID)).isEqualTo("id");
+        assertThat(res.getComponent()).isEqualTo(
+                new ComponentName(mContext.getPackageName(), "test"));
+    }
+
+    @Test
+    public void testGetAppRuleIntent_configActivity_wrongPackage() throws Exception {
+        ZenMode mode = new TestModeBuilder()
+                .setPackage(mContext.getPackageName())
+                .setConfigurationActivity(new ComponentName("another", "test"))
+                .setType(TYPE_OTHER)
+                .build();
+
+        when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+        when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+        Intent res = mPrefController.getAppRuleIntent(mode);
+        assertThat(res).isNull();
+    }
+
+    @Test
+    public void testGetAppRuleIntent_configActivity_unspecifiedOwner() throws Exception {
+        ZenMode mode = new TestModeBuilder()
+                .setId("id")
+                .setPackage(null)
+                .setConfigurationActivity(new ComponentName("another", "test"))
+                .setType(TYPE_OTHER)
+                .build();
+
+        when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+        when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+        Intent res = mPrefController.getAppRuleIntent(mode);
+        assertThat(res).isNotNull();
+        assertThat(res.getStringExtra(EXTRA_RULE_ID)).isEqualTo("id");
+        assertThat(res.getStringExtra(EXTRA_AUTOMATIC_RULE_ID)).isEqualTo("id");
+        assertThat(res.getComponent()).isEqualTo(new ComponentName("another", "test"));
+    }
+
+    @Test
+    public void testGetAppRuleIntent_cps() throws Exception {
+        ZenMode mode = new TestModeBuilder()
+                .setId("id")
+                .setPackage(mContext.getPackageName())
+                .setOwner(new ComponentName(mContext.getPackageName(), "service"))
+                .build();
+
+        ComponentInfo ci = new ComponentInfo();
+        ci.packageName = mContext.getPackageName();
+        ci.metaData = new Bundle();
+        ci.metaData.putString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY,
+                ComponentName.flattenToShortString(
+                        new ComponentName(mContext.getPackageName(), "activity")));
+
+        when(mServiceListing.findService(new ComponentName(mContext.getPackageName(), "service")))
+                .thenReturn(ci);
+        when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+        when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+        Intent res = mPrefController.getAppRuleIntent(mode);
+        assertThat(res).isNotNull();
+        assertThat(res.getStringExtra(EXTRA_RULE_ID)).isEqualTo("id");
+        assertThat(res.getStringExtra(EXTRA_AUTOMATIC_RULE_ID)).isEqualTo("id");
+        assertThat(res.getComponent()).isEqualTo(
+                new ComponentName(mContext.getPackageName(), "activity"));
+    }
+
+    @Test
+    public void testGetAppRuleIntent_cps_wrongPackage() throws Exception {
+        ZenMode mode = new TestModeBuilder()
+                .setPackage("other")
+                .setOwner(new ComponentName(mContext.getPackageName(), "service"))
+                .setType(TYPE_OTHER)
+                .build();
+
+        ComponentInfo ci = new ComponentInfo();
+        ci.packageName = mContext.getPackageName();
+        ci.metaData = new Bundle();
+        ci.metaData.putString(ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY,
+                ComponentName.flattenToShortString(
+                        new ComponentName(mContext.getPackageName(), "activity")));
+
+        when(mPm.getPackageUid(null, 0)).thenReturn(-1);
+        when(mPm.getPackageUid(mContext.getPackageName(), 0)).thenReturn(1);
+
+        Intent res = mPrefController.getAppRuleIntent(mode);
+        assertThat(res).isNull();
+    }
 }