1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.notification.zen; 18 19 import static android.app.NotificationManager.EXTRA_AUTOMATIC_RULE_ID; 20 21 import android.app.AutomaticZenRule; 22 import android.app.Flags; 23 import android.app.NotificationManager; 24 import android.app.settings.SettingsEnums; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.ActivityInfo; 29 import android.content.pm.ComponentInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.ServiceInfo; 32 import android.provider.Settings; 33 import android.service.notification.ConditionProviderService; 34 import android.util.Log; 35 36 import androidx.fragment.app.Fragment; 37 import androidx.preference.Preference; 38 39 import com.android.settings.Utils; 40 import com.android.settings.core.PreferenceControllerMixin; 41 import com.android.settingslib.core.lifecycle.Lifecycle; 42 43 import java.util.Map; 44 45 abstract public class AbstractZenModeAutomaticRulePreferenceController extends 46 AbstractZenModePreferenceController implements PreferenceControllerMixin { 47 48 protected ZenModeBackend mBackend; 49 protected Fragment mParent; 50 protected Map.Entry<String, AutomaticZenRule>[] mRules; 51 protected PackageManager mPm; 52 AbstractZenModeAutomaticRulePreferenceController(Context context, String key, Fragment parent, Lifecycle lifecycle)53 public AbstractZenModeAutomaticRulePreferenceController(Context context, String key, Fragment 54 parent, Lifecycle lifecycle) { 55 super(context, key, lifecycle); 56 mBackend = ZenModeBackend.getInstance(context); 57 mPm = mContext.getPackageManager(); 58 mParent = parent; 59 } 60 61 @Override updateState(Preference preference)62 public void updateState(Preference preference) { 63 super.updateState(preference); 64 mRules = mBackend.getAutomaticZenRules(); 65 } 66 getRules()67 protected Map.Entry<String, AutomaticZenRule>[] getRules() { 68 mRules = mBackend.getAutomaticZenRules(); 69 return mRules; 70 } 71 showNameRuleDialog(final ZenRuleInfo ri, Fragment parent)72 protected void showNameRuleDialog(final ZenRuleInfo ri, Fragment parent) { 73 ZenRuleNameDialog.show(parent, null, ri.defaultConditionId, new 74 RuleNameChangeListener(ri)); 75 } 76 getRuleIntent(String settingsAction, ComponentName configurationActivity, String ruleId)77 protected static Intent getRuleIntent(String settingsAction, 78 ComponentName configurationActivity, String ruleId) { 79 final Intent intent = new Intent() 80 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 81 .putExtra(ConditionProviderService.EXTRA_RULE_ID, ruleId) 82 .putExtra(EXTRA_AUTOMATIC_RULE_ID, ruleId); 83 if (configurationActivity != null) { 84 intent.setComponent(configurationActivity); 85 } else { 86 intent.setAction(settingsAction); 87 intent.setPackage(Utils.SETTINGS_PACKAGE_NAME); 88 } 89 return intent; 90 } 91 getRuleInfo(PackageManager pm, ComponentInfo ci)92 public static ZenRuleInfo getRuleInfo(PackageManager pm, ComponentInfo ci) { 93 if (ci == null || ci.metaData == null) { 94 return null; 95 } 96 final String ruleType = (ci instanceof ServiceInfo) 97 ? ci.metaData.getString(ConditionProviderService.META_DATA_RULE_TYPE) 98 : ci.metaData.getString(NotificationManager.META_DATA_AUTOMATIC_RULE_TYPE); 99 100 final ComponentName configurationActivity = getSettingsActivity(pm, null, ci); 101 if (ruleType != null && !ruleType.trim().isEmpty() && configurationActivity != null) { 102 final ZenRuleInfo ri = new ZenRuleInfo(); 103 ri.serviceComponent = 104 (ci instanceof ServiceInfo) ? new ComponentName(ci.packageName, ci.name) : null; 105 ri.settingsAction = Settings.ACTION_ZEN_MODE_EXTERNAL_RULE_SETTINGS; 106 ri.title = ruleType; 107 ri.packageName = ci.packageName; 108 ri.configurationActivity = configurationActivity; 109 ri.packageLabel = ci.applicationInfo.loadLabel(pm); 110 ri.ruleInstanceLimit = (ci instanceof ServiceInfo) 111 ? ci.metaData.getInt(ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1) 112 : ci.metaData.getInt(NotificationManager.META_DATA_RULE_INSTANCE_LIMIT, -1); 113 return ri; 114 } 115 return null; 116 } 117 getSettingsActivity(PackageManager pm, AutomaticZenRule rule, ComponentInfo ci)118 protected static ComponentName getSettingsActivity(PackageManager pm, AutomaticZenRule rule, 119 ComponentInfo ci) { 120 String owner = rule != null ? rule.getPackageName() : ci.packageName; 121 ComponentName settingsActivity = null; 122 // prefer config activity on the rule itself; fallback to manifest definition 123 if (rule != null && rule.getConfigurationActivity() != null) { 124 settingsActivity = rule.getConfigurationActivity(); 125 } else { 126 if (ci == null) { 127 settingsActivity = null; 128 } else if (ci instanceof ActivityInfo) { 129 // new activity backed rule 130 settingsActivity = new ComponentName(ci.packageName, ci.name); 131 } else if (ci.metaData != null) { 132 // old service backed rule 133 final String configurationActivity = ci.metaData.getString( 134 ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY); 135 if (configurationActivity != null) { 136 settingsActivity = ComponentName.unflattenFromString(configurationActivity); 137 } 138 } 139 } 140 if (settingsActivity == null || owner == null) { 141 return settingsActivity; 142 } 143 try { 144 int ownerUid = pm.getPackageUid(owner, 0); 145 int configActivityOwnerUid = pm.getPackageUid(settingsActivity.getPackageName(), 0); 146 if (ownerUid == configActivityOwnerUid) { 147 return settingsActivity; 148 } else { 149 Log.w(TAG, "Config activity not in owner package for " + rule.getName()); 150 return null; 151 } 152 } catch (PackageManager.NameNotFoundException e) { 153 Log.e(TAG, "Failed to find config activity"); 154 return null; 155 } 156 } 157 158 public class RuleNameChangeListener implements ZenRuleNameDialog.PositiveClickListener { 159 ZenRuleInfo mRuleInfo; 160 RuleNameChangeListener(ZenRuleInfo ruleInfo)161 public RuleNameChangeListener(ZenRuleInfo ruleInfo) { 162 mRuleInfo = ruleInfo; 163 } 164 165 @Override onOk(String ruleName, Fragment parent)166 public void onOk(String ruleName, Fragment parent) { 167 mMetricsFeatureProvider.action(mContext, 168 SettingsEnums.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK); 169 AutomaticZenRule rule; 170 if (Flags.modesApi() && Flags.modesUi()) { 171 rule = new AutomaticZenRule.Builder(ruleName, mRuleInfo.defaultConditionId) 172 .setType(mRuleInfo.type) 173 .setOwner(mRuleInfo.serviceComponent) 174 .setConfigurationActivity(mRuleInfo.configurationActivity) 175 .setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY) 176 .setTriggerDescription(mRuleInfo.defaultTriggerDescription) 177 .build(); 178 } else { 179 rule = new AutomaticZenRule(ruleName, mRuleInfo.serviceComponent, 180 mRuleInfo.configurationActivity, mRuleInfo.defaultConditionId, null, 181 NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); 182 } 183 String savedRuleId = mBackend.addZenRule(rule); 184 if (savedRuleId != null) { 185 parent.startActivity(getRuleIntent(mRuleInfo.settingsAction, null, 186 savedRuleId)); 187 } 188 } 189 } 190 } 191