• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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;
18 
19 import android.app.Dialog;
20 import android.app.NotificationManager;
21 import android.app.settings.SettingsEnums;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.ComponentInfo;
26 import android.content.pm.PackageManager;
27 import android.graphics.drawable.Drawable;
28 import android.os.AsyncTask;
29 import android.os.Bundle;
30 import android.service.notification.ZenModeConfig;
31 import android.util.Log;
32 import android.view.LayoutInflater;
33 import android.view.View;
34 import android.widget.ImageView;
35 import android.widget.LinearLayout;
36 import android.widget.TextView;
37 
38 import androidx.appcompat.app.AlertDialog;
39 import androidx.fragment.app.Fragment;
40 
41 import com.android.settings.R;
42 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
43 import com.android.settings.utils.ZenServiceListing;
44 
45 import java.lang.ref.WeakReference;
46 import java.text.Collator;
47 import java.util.Comparator;
48 import java.util.Set;
49 import java.util.TreeSet;
50 
51 public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
52     private static final String TAG = "ZenRuleSelectionDialog";
53     private static final boolean DEBUG = ZenModeSettings.DEBUG;
54 
55     private static ZenServiceListing mServiceListing;
56     protected static PositiveClickListener mPositiveClickListener;
57 
58     private static Context mContext;
59     private static PackageManager mPm;
60     private static NotificationManager mNm;
61     private LinearLayout mRuleContainer;
62 
63     /**
64      * The interface we expect a listener to implement.
65      */
66     public interface PositiveClickListener {
onSystemRuleSelected(ZenRuleInfo ruleInfo, Fragment parent)67         void onSystemRuleSelected(ZenRuleInfo ruleInfo, Fragment parent);
onExternalRuleSelected(ZenRuleInfo ruleInfo, Fragment parent)68         void onExternalRuleSelected(ZenRuleInfo ruleInfo, Fragment parent);
69     }
70 
71     @Override
getMetricsCategory()72     public int getMetricsCategory() {
73         return SettingsEnums.NOTIFICATION_ZEN_MODE_RULE_SELECTION_DIALOG;
74     }
75 
show(Context context, Fragment parent, PositiveClickListener listener, ZenServiceListing serviceListing)76     public static void show(Context context, Fragment parent, PositiveClickListener
77             listener, ZenServiceListing serviceListing) {
78         mPositiveClickListener = listener;
79         mContext = context;
80         mPm = mContext.getPackageManager();
81         mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
82         mServiceListing = serviceListing;
83 
84         ZenRuleSelectionDialog dialog = new ZenRuleSelectionDialog();
85         dialog.setTargetFragment(parent, 0);
86         dialog.show(parent.getFragmentManager(), TAG);
87     }
88 
89     @Override
onCreateDialog(Bundle savedInstanceState)90     public Dialog onCreateDialog(Bundle savedInstanceState) {
91         final View v = LayoutInflater.from(getContext()).inflate(R.layout.zen_rule_type_selection,
92                 null, false);
93 
94         mRuleContainer = (LinearLayout) v.findViewById(R.id.rule_container);
95         if (mServiceListing != null) {
96             bindType(defaultNewEvent());
97             bindType(defaultNewSchedule());
98             mServiceListing.addZenCallback(mServiceListingCallback);
99             mServiceListing.reloadApprovedServices();
100         }
101         return new AlertDialog.Builder(getContext())
102                 .setTitle(R.string.zen_mode_choose_rule_type)
103                 .setView(v)
104                 .setNegativeButton(R.string.cancel, null)
105                 .create();
106     }
107 
108     @Override
onDismiss(DialogInterface dialog)109     public void onDismiss(DialogInterface dialog) {
110         super.onDismiss(dialog);
111         if (mServiceListing != null) {
112             mServiceListing.removeZenCallback(mServiceListingCallback);
113         }
114     }
115 
bindType(final ZenRuleInfo ri)116     private void bindType(final ZenRuleInfo ri) {
117         try {
118             ApplicationInfo info = mPm.getApplicationInfo(ri.packageName, 0);
119             final LinearLayout v = (LinearLayout) LayoutInflater.from(mContext).inflate(
120                     R.layout.zen_rule_type, null, false);
121 
122             ImageView iconView = v.findViewById(R.id.icon);
123             ((TextView) v.findViewById(R.id.title)).setText(ri.title);
124             if (!ri.isSystem) {
125                 LoadIconTask task = new LoadIconTask(iconView);
126                 task.execute(info);
127 
128                 TextView subtitle = (TextView) v.findViewById(R.id.subtitle);
129                 subtitle.setText(info.loadLabel(mPm));
130                 subtitle.setVisibility(View.VISIBLE);
131             } else {
132                 if (ZenModeConfig.isValidScheduleConditionId(ri.defaultConditionId)) {
133                     iconView.setImageDrawable(mContext.getDrawable(R.drawable.ic_timelapse));
134                 } else if (ZenModeConfig.isValidEventConditionId(ri.defaultConditionId)) {
135                     iconView.setImageDrawable(mContext.getDrawable(R.drawable.ic_event));
136                 }
137             }
138             v.setOnClickListener(new View.OnClickListener() {
139                 @Override
140                 public void onClick(View v) {
141                     dismiss();
142                     if (ri.isSystem) {
143                         mPositiveClickListener.onSystemRuleSelected(ri, getTargetFragment());
144                     } else {
145                         mPositiveClickListener.onExternalRuleSelected(ri, getTargetFragment());
146                     }
147                 }
148             });
149             mRuleContainer.addView(v);
150         } catch (PackageManager.NameNotFoundException e) {
151             // Omit rule.
152         }
153     }
154 
defaultNewSchedule()155     private ZenRuleInfo defaultNewSchedule() {
156         final ZenModeConfig.ScheduleInfo schedule = new ZenModeConfig.ScheduleInfo();
157         schedule.days = ZenModeConfig.ALL_DAYS;
158         schedule.startHour = 22;
159         schedule.endHour = 7;
160         final ZenRuleInfo rt = new ZenRuleInfo();
161         rt.settingsAction = ZenModeScheduleRuleSettings.ACTION;
162         rt.title = mContext.getString(R.string.zen_schedule_rule_type_name);
163         rt.packageName = ZenModeConfig.getEventConditionProvider().getPackageName();
164         rt.defaultConditionId = ZenModeConfig.toScheduleConditionId(schedule);
165         rt.serviceComponent = ZenModeConfig.getScheduleConditionProvider();
166         rt.isSystem = true;
167         return rt;
168     }
169 
defaultNewEvent()170     private ZenRuleInfo defaultNewEvent() {
171         final ZenModeConfig.EventInfo event = new ZenModeConfig.EventInfo();
172         event.calName = null; // any calendar
173         event.calendarId = null;
174         event.reply = ZenModeConfig.EventInfo.REPLY_ANY_EXCEPT_NO;
175         final ZenRuleInfo rt = new ZenRuleInfo();
176         rt.settingsAction = ZenModeEventRuleSettings.ACTION;
177         rt.title = mContext.getString(R.string.zen_event_rule_type_name);
178         rt.packageName = ZenModeConfig.getScheduleConditionProvider().getPackageName();
179         rt.defaultConditionId = ZenModeConfig.toEventConditionId(event);
180         rt.serviceComponent = ZenModeConfig.getEventConditionProvider();
181         rt.isSystem = true;
182         return rt;
183     }
184 
bindExternalRules(Set<ZenRuleInfo> externalRuleTypes)185     private void bindExternalRules(Set<ZenRuleInfo> externalRuleTypes) {
186         for (ZenRuleInfo ri : externalRuleTypes) {
187             bindType(ri);
188         }
189     }
190 
191     private final ZenServiceListing.Callback mServiceListingCallback = new
192             ZenServiceListing.Callback() {
193         @Override
194         public void onComponentsReloaded(Set<ComponentInfo> componentInfos) {
195             if (DEBUG) Log.d(TAG, "Reloaded: count=" + componentInfos.size());
196 
197             Set<ZenRuleInfo> externalRuleTypes = new TreeSet<>(RULE_TYPE_COMPARATOR);
198             for (ComponentInfo ci : componentInfos) {
199                 final ZenRuleInfo ri = AbstractZenModeAutomaticRulePreferenceController.
200                         getRuleInfo(mPm, ci);
201                 if (ri != null && ri.configurationActivity != null
202                         && mNm.isNotificationPolicyAccessGrantedForPackage(ri.packageName)
203                         && (ri.ruleInstanceLimit <= 0 || ri.ruleInstanceLimit
204                         >= (mNm.getRuleInstanceCount(ci.getComponentName()) + 1))) {
205                     externalRuleTypes.add(ri);
206                 }
207             }
208             bindExternalRules(externalRuleTypes);
209         }
210     };
211 
212     private static final Comparator<ZenRuleInfo> RULE_TYPE_COMPARATOR =
213             new Comparator<ZenRuleInfo>() {
214                 private final Collator mCollator = Collator.getInstance();
215 
216                 @Override
217                 public int compare(ZenRuleInfo lhs, ZenRuleInfo rhs) {
218                     int byAppName = mCollator.compare(lhs.packageLabel, rhs.packageLabel);
219                     if (byAppName != 0) {
220                         return byAppName;
221                     } else {
222                         return mCollator.compare(lhs.title, rhs.title);
223                     }
224                 }
225             };
226 
227     private class LoadIconTask extends AsyncTask<ApplicationInfo, Void, Drawable> {
228         private final WeakReference<ImageView> viewReference;
229 
LoadIconTask(ImageView view)230         public LoadIconTask(ImageView view) {
231             viewReference = new WeakReference<>(view);
232         }
233 
234         @Override
doInBackground(ApplicationInfo... params)235         protected Drawable doInBackground(ApplicationInfo... params) {
236             return params[0].loadIcon(mPm);
237         }
238 
239         @Override
onPostExecute(Drawable icon)240         protected void onPostExecute(Drawable icon) {
241             if (icon != null) {
242                 final ImageView view = viewReference.get();
243                 if (view != null) {
244                     view.setImageDrawable(icon);
245                 }
246             }
247         }
248     }
249 }