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