• 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 static com.android.internal.logging.nano.MetricsProto.MetricsEvent;
20 
21 import android.app.AlertDialog;
22 import android.app.Dialog;
23 import android.app.Fragment;
24 import android.app.NotificationManager;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ServiceInfo;
30 import android.graphics.drawable.Drawable;
31 import android.os.AsyncTask;
32 import android.os.Bundle;
33 import android.service.notification.ZenModeConfig;
34 import android.util.Log;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.widget.ImageView;
38 import android.widget.LinearLayout;
39 import android.widget.TextView;
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 MetricsEvent.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.calendar = null; // any calendar
173         event.reply = ZenModeConfig.EventInfo.REPLY_ANY_EXCEPT_NO;
174         final ZenRuleInfo rt = new ZenRuleInfo();
175         rt.settingsAction = ZenModeEventRuleSettings.ACTION;
176         rt.title = mContext.getString(R.string.zen_event_rule_type_name);
177         rt.packageName = ZenModeConfig.getScheduleConditionProvider().getPackageName();
178         rt.defaultConditionId = ZenModeConfig.toEventConditionId(event);
179         rt.serviceComponent = ZenModeConfig.getEventConditionProvider();
180         rt.isSystem = true;
181         return rt;
182     }
183 
bindExternalRules(Set<ZenRuleInfo> externalRuleTypes)184     private void bindExternalRules(Set<ZenRuleInfo> externalRuleTypes) {
185         for (ZenRuleInfo ri : externalRuleTypes) {
186             bindType(ri);
187         }
188     }
189 
190     private final ZenServiceListing.Callback mServiceListingCallback = new
191             ZenServiceListing.Callback() {
192         @Override
193         public void onServicesReloaded(Set<ServiceInfo> services) {
194             if (DEBUG) Log.d(TAG, "Services reloaded: count=" + services.size());
195             Set<ZenRuleInfo> externalRuleTypes = new TreeSet<>(RULE_TYPE_COMPARATOR);
196             for (ServiceInfo serviceInfo : services) {
197                 final ZenRuleInfo ri = AbstractZenModeAutomaticRulePreferenceController.
198                         getRuleInfo(mPm, serviceInfo);
199                 if (ri != null && ri.configurationActivity != null
200                         && mNm.isNotificationPolicyAccessGrantedForPackage(ri.packageName)
201                         && (ri.ruleInstanceLimit <= 0 || ri.ruleInstanceLimit
202                         >= (mNm.getRuleInstanceCount(serviceInfo.getComponentName()) + 1))) {
203                     externalRuleTypes.add(ri);
204                 }
205             }
206             bindExternalRules(externalRuleTypes);
207         }
208     };
209 
210     private static final Comparator<ZenRuleInfo> RULE_TYPE_COMPARATOR =
211             new Comparator<ZenRuleInfo>() {
212                 private final Collator mCollator = Collator.getInstance();
213 
214                 @Override
215                 public int compare(ZenRuleInfo lhs, ZenRuleInfo rhs) {
216                     int byAppName = mCollator.compare(lhs.packageLabel, rhs.packageLabel);
217                     if (byAppName != 0) {
218                         return byAppName;
219                     } else {
220                         return mCollator.compare(lhs.title, rhs.title);
221                     }
222                 }
223             };
224 
225     private class LoadIconTask extends AsyncTask<ApplicationInfo, Void, Drawable> {
226         private final WeakReference<ImageView> viewReference;
227 
LoadIconTask(ImageView view)228         public LoadIconTask(ImageView view) {
229             viewReference = new WeakReference<>(view);
230         }
231 
232         @Override
doInBackground(ApplicationInfo... params)233         protected Drawable doInBackground(ApplicationInfo... params) {
234             return params[0].loadIcon(mPm);
235         }
236 
237         @Override
onPostExecute(Drawable icon)238         protected void onPostExecute(Drawable icon) {
239             if (icon != null) {
240                 final ImageView view = viewReference.get();
241                 if (view != null) {
242                     view.setImageDrawable(icon);
243                 }
244             }
245         }
246     }
247 }