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 android.app.AutomaticZenRule; 20 import android.app.NotificationManager; 21 import android.app.settings.SettingsEnums; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.ActivityInfo; 26 import android.content.pm.ComponentInfo; 27 import android.content.pm.PackageManager; 28 import android.content.pm.ServiceInfo; 29 import android.os.Binder; 30 import android.provider.Settings; 31 import android.service.notification.ConditionProviderService; 32 import android.util.Log; 33 import android.util.Slog; 34 35 import androidx.fragment.app.Fragment; 36 import androidx.preference.Preference; 37 38 import com.android.settings.core.PreferenceControllerMixin; 39 import com.android.settingslib.core.lifecycle.Lifecycle; 40 41 import java.util.Map; 42 import java.util.Objects; 43 44 abstract public class AbstractZenModeAutomaticRulePreferenceController extends 45 AbstractZenModePreferenceController implements PreferenceControllerMixin { 46 47 protected ZenModeBackend mBackend; 48 protected Fragment mParent; 49 protected Map.Entry<String, AutomaticZenRule>[] mRules; 50 protected PackageManager mPm; 51 AbstractZenModeAutomaticRulePreferenceController(Context context, String key, Fragment parent, Lifecycle lifecycle)52 public AbstractZenModeAutomaticRulePreferenceController(Context context, String key, Fragment 53 parent, Lifecycle lifecycle) { 54 super(context, key, lifecycle); 55 mBackend = ZenModeBackend.getInstance(context); 56 mPm = mContext.getPackageManager(); 57 mParent = parent; 58 } 59 60 @Override updateState(Preference preference)61 public void updateState(Preference preference) { 62 super.updateState(preference); 63 mRules = mBackend.getAutomaticZenRules(); 64 } 65 getRules()66 protected Map.Entry<String, AutomaticZenRule>[] getRules() { 67 if (mRules == null) { 68 mRules = mBackend.getAutomaticZenRules(); 69 } 70 return mRules; 71 } 72 showNameRuleDialog(final ZenRuleInfo ri, Fragment parent)73 protected void showNameRuleDialog(final ZenRuleInfo ri, Fragment parent) { 74 ZenRuleNameDialog.show(parent, null, ri.defaultConditionId, new 75 RuleNameChangeListener(ri)); 76 } 77 getRuleIntent(String settingsAction, ComponentName configurationActivity, String ruleId)78 protected static Intent getRuleIntent(String settingsAction, 79 ComponentName configurationActivity, String ruleId) { 80 final Intent intent = new Intent() 81 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 82 .putExtra(ConditionProviderService.EXTRA_RULE_ID, ruleId); 83 if (configurationActivity != null) { 84 intent.setComponent(configurationActivity); 85 } else { 86 intent.setAction(settingsAction); 87 } 88 return intent; 89 } 90 getRuleInfo(PackageManager pm, ComponentInfo ci)91 public static ZenRuleInfo getRuleInfo(PackageManager pm, ComponentInfo ci) { 92 if (ci == null || ci.metaData == null) { 93 return null; 94 } 95 final String ruleType = (ci instanceof ServiceInfo) 96 ? ci.metaData.getString(ConditionProviderService.META_DATA_RULE_TYPE) 97 : ci.metaData.getString(NotificationManager.META_DATA_AUTOMATIC_RULE_TYPE); 98 99 final ComponentName configurationActivity = getSettingsActivity(pm, null, ci); 100 if (ruleType != null && !ruleType.trim().isEmpty() && configurationActivity != null) { 101 final ZenRuleInfo ri = new ZenRuleInfo(); 102 ri.serviceComponent = 103 (ci instanceof ServiceInfo) ? new ComponentName(ci.packageName, ci.name) : null; 104 ri.settingsAction = Settings.ACTION_ZEN_MODE_EXTERNAL_RULE_SETTINGS; 105 ri.title = ruleType; 106 ri.packageName = ci.packageName; 107 ri.configurationActivity = configurationActivity; 108 ri.packageLabel = ci.applicationInfo.loadLabel(pm); 109 ri.ruleInstanceLimit = (ci instanceof ServiceInfo) 110 ? ci.metaData.getInt(ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1) 111 : ci.metaData.getInt(NotificationManager.META_DATA_RULE_INSTANCE_LIMIT, -1); 112 return ri; 113 } 114 return null; 115 } 116 getSettingsActivity(PackageManager pm, AutomaticZenRule rule, ComponentInfo ci)117 protected static ComponentName getSettingsActivity(PackageManager pm, AutomaticZenRule rule, 118 ComponentInfo ci) { 119 String owner = rule != null ? rule.getPackageName() : ci.packageName; 120 ComponentName settingsActivity = null; 121 // prefer config activity on the rule itself; fallback to manifest definition 122 if (rule != null && rule.getConfigurationActivity() != null) { 123 settingsActivity = rule.getConfigurationActivity(); 124 } else { 125 if (ci == null) { 126 settingsActivity = null; 127 } else if (ci instanceof ActivityInfo) { 128 // new activity backed rule 129 settingsActivity = new ComponentName(ci.packageName, ci.name); 130 } else if (ci.metaData != null) { 131 // old service backed rule 132 final String configurationActivity = ci.metaData.getString( 133 ConditionProviderService.META_DATA_CONFIGURATION_ACTIVITY); 134 if (configurationActivity != null) { 135 settingsActivity = ComponentName.unflattenFromString(configurationActivity); 136 } 137 } 138 } 139 if (settingsActivity == null || owner == null) { 140 return settingsActivity; 141 } 142 try { 143 int ownerUid = pm.getPackageUid(owner, 0); 144 int configActivityOwnerUid = pm.getPackageUid(settingsActivity.getPackageName(), 0); 145 if (ownerUid == configActivityOwnerUid) { 146 return settingsActivity; 147 } else { 148 Log.w(TAG, "Config activity not in owner package for " + rule.getName()); 149 return null; 150 } 151 } catch (PackageManager.NameNotFoundException e) { 152 Log.e(TAG, "Failed to find config activity"); 153 return null; 154 } 155 } 156 157 public class RuleNameChangeListener implements ZenRuleNameDialog.PositiveClickListener { 158 ZenRuleInfo mRuleInfo; 159 RuleNameChangeListener(ZenRuleInfo ruleInfo)160 public RuleNameChangeListener(ZenRuleInfo ruleInfo) { 161 mRuleInfo = ruleInfo; 162 } 163 164 @Override onOk(String ruleName, Fragment parent)165 public void onOk(String ruleName, Fragment parent) { 166 mMetricsFeatureProvider.action(mContext, 167 SettingsEnums.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK); 168 AutomaticZenRule rule = new AutomaticZenRule(ruleName, mRuleInfo.serviceComponent, 169 mRuleInfo.configurationActivity, mRuleInfo.defaultConditionId, null, 170 NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); 171 String savedRuleId = mBackend.addZenRule(rule); 172 if (savedRuleId != null) { 173 parent.startActivity(getRuleIntent(mRuleInfo.settingsAction, null, 174 savedRuleId)); 175 } 176 } 177 } 178 } 179