Home | History | Annotate | Download | only in policy
      1 /*
      2  * Copyright (C) 2014 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.systemui.statusbar.policy;
     18 
     19 import android.app.ActivityManager;
     20 import android.app.AlarmManager;
     21 import android.app.NotificationManager;
     22 import android.content.BroadcastReceiver;
     23 import android.content.ComponentName;
     24 import android.content.ContentResolver;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.IntentFilter;
     28 import android.database.ContentObserver;
     29 import android.net.Uri;
     30 import android.os.Handler;
     31 import android.os.UserHandle;
     32 import android.os.UserManager;
     33 import android.provider.Settings.Global;
     34 import android.provider.Settings.Secure;
     35 import android.service.notification.Condition;
     36 import android.service.notification.ZenModeConfig;
     37 import android.service.notification.ZenModeConfig.ZenRule;
     38 import android.util.Log;
     39 import android.util.Slog;
     40 
     41 import com.android.internal.annotations.VisibleForTesting;
     42 import com.android.systemui.qs.GlobalSetting;
     43 import com.android.systemui.settings.CurrentUserTracker;
     44 import com.android.systemui.util.Utils;
     45 
     46 import java.util.ArrayList;
     47 import java.util.LinkedHashMap;
     48 import java.util.Objects;
     49 
     50 /** Platform implementation of the zen mode controller. **/
     51 public class ZenModeControllerImpl extends CurrentUserTracker implements ZenModeController {
     52     private static final String TAG = "ZenModeController";
     53     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     54 
     55     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     56     private final Context mContext;
     57     private final GlobalSetting mModeSetting;
     58     private final GlobalSetting mConfigSetting;
     59     private final NotificationManager mNoMan;
     60     private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();
     61     private final AlarmManager mAlarmManager;
     62     private final SetupObserver mSetupObserver;
     63     private final UserManager mUserManager;
     64 
     65     private int mUserId;
     66     private boolean mRegistered;
     67     private ZenModeConfig mConfig;
     68     private int mZenMode;
     69 
     70     public ZenModeControllerImpl(Context context, Handler handler) {
     71         super(context);
     72         mContext = context;
     73         mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
     74             @Override
     75             protected void handleValueChanged(int value) {
     76                 updateZenMode(value);
     77                 fireZenChanged(value);
     78             }
     79         };
     80         mConfigSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE_CONFIG_ETAG) {
     81             @Override
     82             protected void handleValueChanged(int value) {
     83                 updateZenModeConfig();
     84             }
     85         };
     86         mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
     87         mConfig = mNoMan.getZenModeConfig();
     88         mModeSetting.setListening(true);
     89         updateZenMode(mModeSetting.getValue());
     90         mConfigSetting.setListening(true);
     91         updateZenModeConfig();
     92         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
     93         mSetupObserver = new SetupObserver(handler);
     94         mSetupObserver.register();
     95         mUserManager = context.getSystemService(UserManager.class);
     96         startTracking();
     97     }
     98 
     99     @Override
    100     public boolean isVolumeRestricted() {
    101         return mUserManager.hasUserRestriction(UserManager.DISALLOW_ADJUST_VOLUME,
    102                 new UserHandle(mUserId));
    103     }
    104 
    105     @Override
    106     public boolean areNotificationsHiddenInShade() {
    107         if (mZenMode != Global.ZEN_MODE_OFF) {
    108             return (mConfig.suppressedVisualEffects & NotificationManager.Policy
    109                     .SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0;
    110         }
    111         return false;
    112     }
    113 
    114     @Override
    115     public void addCallback(Callback callback) {
    116         if (callback == null) {
    117             Slog.e(TAG, "Attempted to add a null callback.");
    118             return;
    119         }
    120         mCallbacks.add(callback);
    121     }
    122 
    123     @Override
    124     public void removeCallback(Callback callback) {
    125         mCallbacks.remove(callback);
    126     }
    127 
    128     @Override
    129     public int getZen() {
    130         return mZenMode;
    131     }
    132 
    133     @Override
    134     public void setZen(int zen, Uri conditionId, String reason) {
    135         mNoMan.setZenMode(zen, conditionId, reason);
    136     }
    137 
    138     @Override
    139     public boolean isZenAvailable() {
    140         return mSetupObserver.isDeviceProvisioned() && mSetupObserver.isUserSetup();
    141     }
    142 
    143     @Override
    144     public ZenRule getManualRule() {
    145         return mConfig == null ? null : mConfig.manualRule;
    146     }
    147 
    148     @Override
    149     public ZenModeConfig getConfig() {
    150         return mConfig;
    151     }
    152 
    153     @Override
    154     public long getNextAlarm() {
    155         final AlarmManager.AlarmClockInfo info = mAlarmManager.getNextAlarmClock(mUserId);
    156         return info != null ? info.getTriggerTime() : 0;
    157     }
    158 
    159     @Override
    160     public void onUserSwitched(int userId) {
    161         mUserId = userId;
    162         if (mRegistered) {
    163             mContext.unregisterReceiver(mReceiver);
    164         }
    165         final IntentFilter filter = new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
    166         filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
    167         mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId), filter, null, null);
    168         mRegistered = true;
    169         mSetupObserver.register();
    170     }
    171 
    172     @Override
    173     public ComponentName getEffectsSuppressor() {
    174         return NotificationManager.from(mContext).getEffectsSuppressor();
    175     }
    176 
    177     @Override
    178     public boolean isCountdownConditionSupported() {
    179         return NotificationManager.from(mContext)
    180                 .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH);
    181     }
    182 
    183     @Override
    184     public int getCurrentUser() {
    185         return ActivityManager.getCurrentUser();
    186     }
    187 
    188     private void fireNextAlarmChanged() {
    189         Utils.safeForeach(mCallbacks, c -> c.onNextAlarmChanged());
    190     }
    191 
    192     private void fireEffectsSuppressorChanged() {
    193         Utils.safeForeach(mCallbacks, c -> c.onEffectsSupressorChanged());
    194     }
    195 
    196     private void fireZenChanged(int zen) {
    197         Utils.safeForeach(mCallbacks, c -> c.onZenChanged(zen));
    198     }
    199 
    200     private void fireZenAvailableChanged(boolean available) {
    201         Utils.safeForeach(mCallbacks, c -> c.onZenAvailableChanged(available));
    202     }
    203 
    204     private void fireManualRuleChanged(ZenRule rule) {
    205         Utils.safeForeach(mCallbacks, c -> c.onManualRuleChanged(rule));
    206     }
    207 
    208     @VisibleForTesting
    209     protected void fireConfigChanged(ZenModeConfig config) {
    210         Utils.safeForeach(mCallbacks, c -> c.onConfigChanged(config));
    211     }
    212 
    213     @VisibleForTesting
    214     protected void updateZenMode(int mode) {
    215         mZenMode = mode;
    216     }
    217 
    218     @VisibleForTesting
    219     protected void updateZenModeConfig() {
    220         final ZenModeConfig config = mNoMan.getZenModeConfig();
    221         if (Objects.equals(config, mConfig)) return;
    222         final ZenRule oldRule = mConfig != null ? mConfig.manualRule : null;
    223         mConfig = config;
    224         fireConfigChanged(config);
    225         final ZenRule newRule = config != null ? config.manualRule : null;
    226         if (Objects.equals(oldRule, newRule)) return;
    227         fireManualRuleChanged(newRule);
    228     }
    229 
    230     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    231         @Override
    232         public void onReceive(Context context, Intent intent) {
    233             if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(intent.getAction())) {
    234                 fireNextAlarmChanged();
    235             }
    236             if (NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED.equals(intent.getAction())) {
    237                 fireEffectsSuppressorChanged();
    238             }
    239         }
    240     };
    241 
    242     private final class SetupObserver extends ContentObserver {
    243         private final ContentResolver mResolver;
    244 
    245         private boolean mRegistered;
    246 
    247         public SetupObserver(Handler handler) {
    248             super(handler);
    249             mResolver = mContext.getContentResolver();
    250         }
    251 
    252         public boolean isUserSetup() {
    253             return Secure.getIntForUser(mResolver, Secure.USER_SETUP_COMPLETE, 0, mUserId) != 0;
    254         }
    255 
    256         public boolean isDeviceProvisioned() {
    257             return Global.getInt(mResolver, Global.DEVICE_PROVISIONED, 0) != 0;
    258         }
    259 
    260         public void register() {
    261             if (mRegistered) {
    262                 mResolver.unregisterContentObserver(this);
    263             }
    264             mResolver.registerContentObserver(
    265                     Global.getUriFor(Global.DEVICE_PROVISIONED), false, this);
    266             mResolver.registerContentObserver(
    267                     Secure.getUriFor(Secure.USER_SETUP_COMPLETE), false, this, mUserId);
    268             fireZenAvailableChanged(isZenAvailable());
    269         }
    270 
    271         @Override
    272         public void onChange(boolean selfChange, Uri uri) {
    273             if (Global.getUriFor(Global.DEVICE_PROVISIONED).equals(uri)
    274                     || Secure.getUriFor(Secure.USER_SETUP_COMPLETE).equals(uri)) {
    275                 fireZenAvailableChanged(isZenAvailable());
    276             }
    277         }
    278     }
    279 }
    280