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.AlertDialog; 20 import android.app.NotificationManager; 21 import android.content.Context; 22 import android.content.DialogInterface; 23 import android.content.DialogInterface.OnDismissListener; 24 import android.content.pm.ApplicationInfo; 25 import android.content.pm.PackageManager; 26 import android.content.pm.ServiceInfo; 27 import android.graphics.drawable.Drawable; 28 import android.os.AsyncTask; 29 import android.service.notification.ZenModeConfig; 30 import android.util.ArraySet; 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 com.android.settings.R; 39 import com.android.settings.utils.ServiceListing; 40 import com.android.settings.utils.ZenServiceListing; 41 42 import java.lang.ref.WeakReference; 43 import java.text.Collator; 44 import java.util.ArrayList; 45 import java.util.Collections; 46 import java.util.Comparator; 47 import java.util.List; 48 import java.util.Set; 49 import java.util.TreeSet; 50 51 public abstract class ZenRuleSelectionDialog { 52 private static final String TAG = "ZenRuleSelectionDialog"; 53 private static final boolean DEBUG = ZenModeSettings.DEBUG; 54 55 private final Context mContext; 56 private final PackageManager mPm; 57 private NotificationManager mNm; 58 private final AlertDialog mDialog; 59 private final LinearLayout mRuleContainer; 60 private final ZenServiceListing mServiceListing; 61 62 public ZenRuleSelectionDialog(Context context, ZenServiceListing serviceListing) { 63 mContext = context; 64 mPm = context.getPackageManager(); 65 mNm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 66 mServiceListing = serviceListing; 67 final View v = 68 LayoutInflater.from(context).inflate(R.layout.zen_rule_type_selection, null, false); 69 70 mRuleContainer = (LinearLayout) v.findViewById(R.id.rule_container); 71 if (mServiceListing != null) { 72 bindType(defaultNewEvent()); 73 bindType(defaultNewSchedule()); 74 mServiceListing.addZenCallback(mServiceListingCallback); 75 mServiceListing.reloadApprovedServices(); 76 } 77 mDialog = new AlertDialog.Builder(context) 78 .setTitle(R.string.zen_mode_choose_rule_type) 79 .setView(v) 80 .setOnDismissListener(new OnDismissListener() { 81 @Override 82 public void onDismiss(DialogInterface dialog) { 83 if (mServiceListing != null) { 84 mServiceListing.removeZenCallback(mServiceListingCallback); 85 } 86 } 87 }) 88 .setNegativeButton(R.string.cancel, null) 89 .create(); 90 } 91 92 public void show() { 93 mDialog.show(); 94 } 95 96 abstract public void onSystemRuleSelected(ZenRuleInfo ruleInfo); 97 abstract public void onExternalRuleSelected(ZenRuleInfo ruleInfo); 98 99 private void bindType(final ZenRuleInfo ri) { 100 try { 101 ApplicationInfo info = mPm.getApplicationInfo(ri.packageName, 0); 102 final LinearLayout v = (LinearLayout) LayoutInflater.from(mContext).inflate( 103 R.layout.zen_rule_type, null, false); 104 105 LoadIconTask task = new LoadIconTask((ImageView) v.findViewById(R.id.icon)); 106 task.execute(info); 107 ((TextView) v.findViewById(R.id.title)).setText(ri.title); 108 if (!ri.isSystem) { 109 TextView subtitle = (TextView) v.findViewById(R.id.subtitle); 110 subtitle.setText(info.loadLabel(mPm)); 111 subtitle.setVisibility(View.VISIBLE); 112 } 113 v.setOnClickListener(new View.OnClickListener() { 114 @Override 115 public void onClick(View v) { 116 mDialog.dismiss(); 117 if (ri.isSystem) { 118 onSystemRuleSelected(ri); 119 } else { 120 onExternalRuleSelected(ri); 121 } 122 } 123 }); 124 mRuleContainer.addView(v); 125 } catch (PackageManager.NameNotFoundException e) { 126 // Omit rule. 127 } 128 } 129 130 private ZenRuleInfo defaultNewSchedule() { 131 final ZenModeConfig.ScheduleInfo schedule = new ZenModeConfig.ScheduleInfo(); 132 schedule.days = ZenModeConfig.ALL_DAYS; 133 schedule.startHour = 22; 134 schedule.endHour = 7; 135 final ZenRuleInfo rt = new ZenRuleInfo(); 136 rt.settingsAction = ZenModeScheduleRuleSettings.ACTION; 137 rt.title = mContext.getString(R.string.zen_schedule_rule_type_name); 138 rt.packageName = ZenModeConfig.getEventConditionProvider().getPackageName(); 139 rt.defaultConditionId = ZenModeConfig.toScheduleConditionId(schedule); 140 rt.serviceComponent = ZenModeConfig.getScheduleConditionProvider(); 141 rt.isSystem = true; 142 return rt; 143 } 144 145 private ZenRuleInfo defaultNewEvent() { 146 final ZenModeConfig.EventInfo event = new ZenModeConfig.EventInfo(); 147 event.calendar = null; // any calendar 148 event.reply = ZenModeConfig.EventInfo.REPLY_ANY_EXCEPT_NO; 149 final ZenRuleInfo rt = new ZenRuleInfo(); 150 rt.settingsAction = ZenModeEventRuleSettings.ACTION; 151 rt.title = mContext.getString(R.string.zen_event_rule_type_name); 152 rt.packageName = ZenModeConfig.getScheduleConditionProvider().getPackageName(); 153 rt.defaultConditionId = ZenModeConfig.toEventConditionId(event); 154 rt.serviceComponent = ZenModeConfig.getEventConditionProvider(); 155 rt.isSystem = true; 156 return rt; 157 } 158 159 private void bindExternalRules(Set<ZenRuleInfo> externalRuleTypes) { 160 for (ZenRuleInfo ri : externalRuleTypes) { 161 bindType(ri); 162 } 163 } 164 165 private final ZenServiceListing.Callback mServiceListingCallback = new 166 ZenServiceListing.Callback() { 167 @Override 168 public void onServicesReloaded(Set<ServiceInfo> services) { 169 if (DEBUG) Log.d(TAG, "Services reloaded: count=" + services.size()); 170 Set<ZenRuleInfo> externalRuleTypes = new TreeSet<>(RULE_TYPE_COMPARATOR); 171 for (ServiceInfo serviceInfo : services) { 172 final ZenRuleInfo ri = ZenModeAutomationSettings.getRuleInfo(mPm, serviceInfo); 173 if (ri != null && ri.configurationActivity != null 174 && mNm.isNotificationPolicyAccessGrantedForPackage(ri.packageName) 175 && (ri.ruleInstanceLimit <= 0 || ri.ruleInstanceLimit 176 >= (mNm.getRuleInstanceCount(serviceInfo.getComponentName()) + 1))) { 177 externalRuleTypes.add(ri); 178 } 179 } 180 bindExternalRules(externalRuleTypes); 181 } 182 }; 183 184 private static final Comparator<ZenRuleInfo> RULE_TYPE_COMPARATOR = 185 new Comparator<ZenRuleInfo>() { 186 private final Collator mCollator = Collator.getInstance(); 187 188 @Override 189 public int compare(ZenRuleInfo lhs, ZenRuleInfo rhs) { 190 int byAppName = mCollator.compare(lhs.packageLabel, rhs.packageLabel); 191 if (byAppName != 0) { 192 return byAppName; 193 } else { 194 return mCollator.compare(lhs.title, rhs.title); 195 } 196 } 197 }; 198 199 private class LoadIconTask extends AsyncTask<ApplicationInfo, Void, Drawable> { 200 private final WeakReference<ImageView> viewReference; 201 202 public LoadIconTask(ImageView view) { 203 viewReference = new WeakReference<>(view); 204 } 205 206 @Override 207 protected Drawable doInBackground(ApplicationInfo... params) { 208 return params[0].loadIcon(mPm); 209 } 210 211 @Override 212 protected void onPostExecute(Drawable icon) { 213 if (icon != null) { 214 final ImageView view = viewReference.get(); 215 if (view != null) { 216 view.setImageDrawable(icon); 217 } 218 } 219 } 220 } 221 }