Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3731d3e8 authored by Yuri Lin's avatar Yuri Lin Committed by Android (Google) Code Review
Browse files

Merge "Link to app-provided configuration intent for app-owned rules." into main

parents a954e914 21539cd2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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>
+11 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.util.Log;
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;
@@ -91,6 +92,16 @@ abstract class AbstractZenModePreferenceController extends AbstractPreferenceCon
        updateState(preference);
    }

    @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);
+3 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import java.util.ArrayList;
import java.util.List;

public class ZenModeFragment extends ZenModeFragmentBase {

    // for mode deletion menu
    private static final int DELETE_MODE = 1;

@@ -61,7 +62,8 @@ public class ZenModeFragment extends ZenModeFragmentBase {
        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(
+135 −24
Original line number Diff line number Diff line
@@ -18,34 +18,62 @@ package com.android.settings.notification.modes;

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
@@ -53,6 +81,15 @@ class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenc
        return !zenMode.isManualDnd();
    }

    @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
@@ -70,18 +107,19 @@ class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenc
        switchPref.setOnPreferenceClickListener(null);
        switchPref.setIntent(null);

        if (zenMode.isSystemOwned() && zenMode.getType() == TYPE_SCHEDULE_TIME) {
        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.isSystemOwned() && zenMode.getType() == TYPE_SCHEDULE_CALENDAR) {
            } 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 if (zenMode.isSystemOwned()) {
            } else {
                switchPref.setTitle(R.string.zen_mode_select_schedule);
                switchPref.setIcon(R.drawable.ic_add_24dp);
                switchPref.setSummary("");
@@ -90,9 +128,18 @@ class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenc
                    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 @@ class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenc
        });
        // 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;
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ public class ZenModesListFragment extends ZenModesFragmentBase {
        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)
Loading