Home | History | Annotate | Download | only in notification
      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 = ZenModeSettings.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 }