125384711e3c2894a84642c49953594930dd078abJames Lemieux/*
225384711e3c2894a84642c49953594930dd078abJames Lemieux * Copyright (C) 2016 The Android Open Source Project
325384711e3c2894a84642c49953594930dd078abJames Lemieux *
425384711e3c2894a84642c49953594930dd078abJames Lemieux * Licensed under the Apache License, Version 2.0 (the "License");
525384711e3c2894a84642c49953594930dd078abJames Lemieux * you may not use this file except in compliance with the License.
625384711e3c2894a84642c49953594930dd078abJames Lemieux * You may obtain a copy of the License at
725384711e3c2894a84642c49953594930dd078abJames Lemieux *
825384711e3c2894a84642c49953594930dd078abJames Lemieux *      http://www.apache.org/licenses/LICENSE-2.0
925384711e3c2894a84642c49953594930dd078abJames Lemieux *
1025384711e3c2894a84642c49953594930dd078abJames Lemieux * Unless required by applicable law or agreed to in writing, software
1125384711e3c2894a84642c49953594930dd078abJames Lemieux * distributed under the License is distributed on an "AS IS" BASIS,
1225384711e3c2894a84642c49953594930dd078abJames Lemieux * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1325384711e3c2894a84642c49953594930dd078abJames Lemieux * See the License for the specific language governing permissions and
1425384711e3c2894a84642c49953594930dd078abJames Lemieux * limitations under the License.
1525384711e3c2894a84642c49953594930dd078abJames Lemieux */
1625384711e3c2894a84642c49953594930dd078abJames Lemieux
1725384711e3c2894a84642c49953594930dd078abJames Lemieuxpackage com.android.deskclock.data;
1825384711e3c2894a84642c49953594930dd078abJames Lemieux
1925384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.annotation.TargetApi;
2025384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.app.NotificationManager;
2125384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.content.BroadcastReceiver;
2225384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.content.ContentResolver;
2325384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.content.Context;
2425384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.content.Intent;
2525384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.content.IntentFilter;
2625384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.database.ContentObserver;
2725384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.media.AudioManager;
2825384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.media.RingtoneManager;
2925384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.net.Uri;
3025384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.os.AsyncTask;
3125384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.os.Build;
3225384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.os.Handler;
3325384711e3c2894a84642c49953594930dd078abJames Lemieuximport android.support.v4.app.NotificationManagerCompat;
3425384711e3c2894a84642c49953594930dd078abJames Lemieux
3525384711e3c2894a84642c49953594930dd078abJames Lemieuximport com.android.deskclock.Utils;
3625384711e3c2894a84642c49953594930dd078abJames Lemieuximport com.android.deskclock.data.DataModel.SilentSetting;
3725384711e3c2894a84642c49953594930dd078abJames Lemieux
3825384711e3c2894a84642c49953594930dd078abJames Lemieuximport java.util.ArrayList;
3925384711e3c2894a84642c49953594930dd078abJames Lemieuximport java.util.List;
4025384711e3c2894a84642c49953594930dd078abJames Lemieux
4125384711e3c2894a84642c49953594930dd078abJames Lemieuximport static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
4225384711e3c2894a84642c49953594930dd078abJames Lemieuximport static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
4325384711e3c2894a84642c49953594930dd078abJames Lemieuximport static android.content.Context.AUDIO_SERVICE;
4425384711e3c2894a84642c49953594930dd078abJames Lemieuximport static android.content.Context.NOTIFICATION_SERVICE;
4525384711e3c2894a84642c49953594930dd078abJames Lemieuximport static android.media.AudioManager.STREAM_ALARM;
4625384711e3c2894a84642c49953594930dd078abJames Lemieuximport static android.media.RingtoneManager.TYPE_ALARM;
4725384711e3c2894a84642c49953594930dd078abJames Lemieuximport static android.provider.Settings.System.CONTENT_URI;
4825384711e3c2894a84642c49953594930dd078abJames Lemieuximport static android.provider.Settings.System.DEFAULT_ALARM_ALERT_URI;
4925384711e3c2894a84642c49953594930dd078abJames Lemieux
5025384711e3c2894a84642c49953594930dd078abJames Lemieux/**
5125384711e3c2894a84642c49953594930dd078abJames Lemieux * This model fetches and stores reasons that alarms may be suppressed or silenced by system
5225384711e3c2894a84642c49953594930dd078abJames Lemieux * settings on the device. This information is displayed passively to notify the user of this
5325384711e3c2894a84642c49953594930dd078abJames Lemieux * condition and set their expectations for future firing alarms.
5425384711e3c2894a84642c49953594930dd078abJames Lemieux */
5525384711e3c2894a84642c49953594930dd078abJames Lemieuxfinal class SilentSettingsModel {
5625384711e3c2894a84642c49953594930dd078abJames Lemieux
5725384711e3c2894a84642c49953594930dd078abJames Lemieux    /** The Uri to the settings entry that stores alarm stream volume. */
5825384711e3c2894a84642c49953594930dd078abJames Lemieux    private static final Uri VOLUME_URI = Uri.withAppendedPath(CONTENT_URI, "volume_alarm_speaker");
5925384711e3c2894a84642c49953594930dd078abJames Lemieux
6025384711e3c2894a84642c49953594930dd078abJames Lemieux    private final Context mContext;
6125384711e3c2894a84642c49953594930dd078abJames Lemieux
6225384711e3c2894a84642c49953594930dd078abJames Lemieux    /** Used to query the alarm volume and display the system control to change the alarm volume. */
6325384711e3c2894a84642c49953594930dd078abJames Lemieux    private final AudioManager mAudioManager;
6425384711e3c2894a84642c49953594930dd078abJames Lemieux
6525384711e3c2894a84642c49953594930dd078abJames Lemieux    /** Used to query the do-not-disturb setting value, also called "interruption filter". */
6625384711e3c2894a84642c49953594930dd078abJames Lemieux    private final NotificationManager mNotificationManager;
6725384711e3c2894a84642c49953594930dd078abJames Lemieux
6825384711e3c2894a84642c49953594930dd078abJames Lemieux    /** Used to determine if the application is in the foreground. */
6925384711e3c2894a84642c49953594930dd078abJames Lemieux    private final NotificationModel mNotificationModel;
7025384711e3c2894a84642c49953594930dd078abJames Lemieux
7125384711e3c2894a84642c49953594930dd078abJames Lemieux    /** List of listeners to invoke upon silence state change. */
7225384711e3c2894a84642c49953594930dd078abJames Lemieux    private final List<OnSilentSettingsListener> mListeners = new ArrayList<>(1);
7325384711e3c2894a84642c49953594930dd078abJames Lemieux
7425384711e3c2894a84642c49953594930dd078abJames Lemieux    /**
7525384711e3c2894a84642c49953594930dd078abJames Lemieux     * The last setting known to be blocking alarms; {@code null} indicates no settings are
7625384711e3c2894a84642c49953594930dd078abJames Lemieux     * blocking the app or the app is not in the foreground.
7725384711e3c2894a84642c49953594930dd078abJames Lemieux     */
7825384711e3c2894a84642c49953594930dd078abJames Lemieux    private SilentSetting mSilentSetting;
7925384711e3c2894a84642c49953594930dd078abJames Lemieux
8025384711e3c2894a84642c49953594930dd078abJames Lemieux    /** The background task that checks the device system settings that influence alarm firing. */
8125384711e3c2894a84642c49953594930dd078abJames Lemieux    private CheckSilenceSettingsTask mCheckSilenceSettingsTask;
8225384711e3c2894a84642c49953594930dd078abJames Lemieux
8325384711e3c2894a84642c49953594930dd078abJames Lemieux    SilentSettingsModel(Context context, NotificationModel notificationModel) {
8425384711e3c2894a84642c49953594930dd078abJames Lemieux        mContext = context;
8525384711e3c2894a84642c49953594930dd078abJames Lemieux        mNotificationModel = notificationModel;
8625384711e3c2894a84642c49953594930dd078abJames Lemieux
8725384711e3c2894a84642c49953594930dd078abJames Lemieux        mAudioManager = (AudioManager) context.getSystemService(AUDIO_SERVICE);
8825384711e3c2894a84642c49953594930dd078abJames Lemieux        mNotificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
8925384711e3c2894a84642c49953594930dd078abJames Lemieux
9025384711e3c2894a84642c49953594930dd078abJames Lemieux        // Watch for changes to the settings that may silence alarms.
9125384711e3c2894a84642c49953594930dd078abJames Lemieux        final ContentResolver cr = context.getContentResolver();
9225384711e3c2894a84642c49953594930dd078abJames Lemieux        final ContentObserver contentChangeWatcher = new ContentChangeWatcher();
9325384711e3c2894a84642c49953594930dd078abJames Lemieux        cr.registerContentObserver(VOLUME_URI, false, contentChangeWatcher);
9425384711e3c2894a84642c49953594930dd078abJames Lemieux        cr.registerContentObserver(DEFAULT_ALARM_ALERT_URI, false, contentChangeWatcher);
9525384711e3c2894a84642c49953594930dd078abJames Lemieux        if (Utils.isMOrLater()) {
9625384711e3c2894a84642c49953594930dd078abJames Lemieux            final IntentFilter filter = new IntentFilter(ACTION_INTERRUPTION_FILTER_CHANGED);
9725384711e3c2894a84642c49953594930dd078abJames Lemieux            context.registerReceiver(new DoNotDisturbChangeReceiver(), filter);
9825384711e3c2894a84642c49953594930dd078abJames Lemieux        }
9925384711e3c2894a84642c49953594930dd078abJames Lemieux    }
10025384711e3c2894a84642c49953594930dd078abJames Lemieux
10125384711e3c2894a84642c49953594930dd078abJames Lemieux    void addSilentSettingsListener(OnSilentSettingsListener listener) {
10225384711e3c2894a84642c49953594930dd078abJames Lemieux        mListeners.add(listener);
10325384711e3c2894a84642c49953594930dd078abJames Lemieux    }
10425384711e3c2894a84642c49953594930dd078abJames Lemieux
10525384711e3c2894a84642c49953594930dd078abJames Lemieux    void removeSilentSettingsListener(OnSilentSettingsListener listener) {
10625384711e3c2894a84642c49953594930dd078abJames Lemieux        mListeners.remove(listener);
10725384711e3c2894a84642c49953594930dd078abJames Lemieux    }
10825384711e3c2894a84642c49953594930dd078abJames Lemieux
10925384711e3c2894a84642c49953594930dd078abJames Lemieux    /**
11025384711e3c2894a84642c49953594930dd078abJames Lemieux     * If the app is in the foreground, start a task to determine if any device setting will block
11125384711e3c2894a84642c49953594930dd078abJames Lemieux     * alarms from firing. If the app is in the background, clear any results from the last time
11225384711e3c2894a84642c49953594930dd078abJames Lemieux     * those settings were inspected.
11325384711e3c2894a84642c49953594930dd078abJames Lemieux     */
11425384711e3c2894a84642c49953594930dd078abJames Lemieux    void updateSilentState() {
11525384711e3c2894a84642c49953594930dd078abJames Lemieux        // Cancel any task in flight, the result is no longer relevant.
11625384711e3c2894a84642c49953594930dd078abJames Lemieux        if (mCheckSilenceSettingsTask != null) {
11725384711e3c2894a84642c49953594930dd078abJames Lemieux            mCheckSilenceSettingsTask.cancel(true);
11825384711e3c2894a84642c49953594930dd078abJames Lemieux            mCheckSilenceSettingsTask = null;
11925384711e3c2894a84642c49953594930dd078abJames Lemieux        }
12025384711e3c2894a84642c49953594930dd078abJames Lemieux
12125384711e3c2894a84642c49953594930dd078abJames Lemieux        if (mNotificationModel.isApplicationInForeground()) {
12225384711e3c2894a84642c49953594930dd078abJames Lemieux            mCheckSilenceSettingsTask = new CheckSilenceSettingsTask();
12325384711e3c2894a84642c49953594930dd078abJames Lemieux            mCheckSilenceSettingsTask.execute();
12425384711e3c2894a84642c49953594930dd078abJames Lemieux        } else {
12525384711e3c2894a84642c49953594930dd078abJames Lemieux            setSilentState(null);
12625384711e3c2894a84642c49953594930dd078abJames Lemieux        }
12725384711e3c2894a84642c49953594930dd078abJames Lemieux    }
12825384711e3c2894a84642c49953594930dd078abJames Lemieux
12925384711e3c2894a84642c49953594930dd078abJames Lemieux    /**
13025384711e3c2894a84642c49953594930dd078abJames Lemieux     * @param silentSetting the latest notion of which setting is suppressing alarms; {@code null}
13125384711e3c2894a84642c49953594930dd078abJames Lemieux     *      if no settings are suppressing alarms
13225384711e3c2894a84642c49953594930dd078abJames Lemieux     */
13325384711e3c2894a84642c49953594930dd078abJames Lemieux    private void setSilentState(SilentSetting silentSetting) {
13425384711e3c2894a84642c49953594930dd078abJames Lemieux        if (mSilentSetting != silentSetting) {
13525384711e3c2894a84642c49953594930dd078abJames Lemieux            final SilentSetting oldReason = mSilentSetting;
13625384711e3c2894a84642c49953594930dd078abJames Lemieux            mSilentSetting = silentSetting;
13725384711e3c2894a84642c49953594930dd078abJames Lemieux
13825384711e3c2894a84642c49953594930dd078abJames Lemieux            for (OnSilentSettingsListener listener : mListeners) {
13925384711e3c2894a84642c49953594930dd078abJames Lemieux                listener.onSilentSettingsChange(oldReason, silentSetting);
14025384711e3c2894a84642c49953594930dd078abJames Lemieux            }
14125384711e3c2894a84642c49953594930dd078abJames Lemieux        }
14225384711e3c2894a84642c49953594930dd078abJames Lemieux    }
14325384711e3c2894a84642c49953594930dd078abJames Lemieux
14425384711e3c2894a84642c49953594930dd078abJames Lemieux    /**
14525384711e3c2894a84642c49953594930dd078abJames Lemieux     * This task inspects a variety of system settings that can prevent alarms from firing or the
14625384711e3c2894a84642c49953594930dd078abJames Lemieux     * associated ringtone from playing. If any of them would prevent an alarm from firing or
14725384711e3c2894a84642c49953594930dd078abJames Lemieux     * making noise, a description of the setting is reported to this model on the main thread.
14825384711e3c2894a84642c49953594930dd078abJames Lemieux     */
149ff62e7fa903e3b6b11d0443543725c1351ab289dJames Lemieux    private final class CheckSilenceSettingsTask extends AsyncTask<Void, Void, SilentSetting> {
15025384711e3c2894a84642c49953594930dd078abJames Lemieux        @Override
15125384711e3c2894a84642c49953594930dd078abJames Lemieux        protected SilentSetting doInBackground(Void... parameters) {
15225384711e3c2894a84642c49953594930dd078abJames Lemieux            if (!isCancelled() && isDoNotDisturbBlockingAlarms()) {
15325384711e3c2894a84642c49953594930dd078abJames Lemieux                return SilentSetting.DO_NOT_DISTURB;
15425384711e3c2894a84642c49953594930dd078abJames Lemieux            } else if (!isCancelled() && isAlarmStreamMuted()) {
15525384711e3c2894a84642c49953594930dd078abJames Lemieux                return SilentSetting.MUTED_VOLUME;
15625384711e3c2894a84642c49953594930dd078abJames Lemieux            } else if (!isCancelled() && isSystemAlarmRingtoneSilent()) {
15725384711e3c2894a84642c49953594930dd078abJames Lemieux                return SilentSetting.SILENT_RINGTONE;
15825384711e3c2894a84642c49953594930dd078abJames Lemieux            } else if (!isCancelled() && isAppNotificationBlocked()) {
15925384711e3c2894a84642c49953594930dd078abJames Lemieux                return SilentSetting.BLOCKED_NOTIFICATIONS;
16025384711e3c2894a84642c49953594930dd078abJames Lemieux            }
16125384711e3c2894a84642c49953594930dd078abJames Lemieux            return null;
16225384711e3c2894a84642c49953594930dd078abJames Lemieux        }
16325384711e3c2894a84642c49953594930dd078abJames Lemieux
16425384711e3c2894a84642c49953594930dd078abJames Lemieux        @Override
16525384711e3c2894a84642c49953594930dd078abJames Lemieux        protected void onCancelled() {
16625384711e3c2894a84642c49953594930dd078abJames Lemieux            super.onCancelled();
16725384711e3c2894a84642c49953594930dd078abJames Lemieux            if (mCheckSilenceSettingsTask == this) {
16825384711e3c2894a84642c49953594930dd078abJames Lemieux                mCheckSilenceSettingsTask = null;
16925384711e3c2894a84642c49953594930dd078abJames Lemieux            }
17025384711e3c2894a84642c49953594930dd078abJames Lemieux        }
17125384711e3c2894a84642c49953594930dd078abJames Lemieux
17225384711e3c2894a84642c49953594930dd078abJames Lemieux        @Override
17325384711e3c2894a84642c49953594930dd078abJames Lemieux        protected void onPostExecute(SilentSetting silentSetting) {
17425384711e3c2894a84642c49953594930dd078abJames Lemieux            if (mCheckSilenceSettingsTask == this) {
17525384711e3c2894a84642c49953594930dd078abJames Lemieux                mCheckSilenceSettingsTask = null;
17625384711e3c2894a84642c49953594930dd078abJames Lemieux                setSilentState(silentSetting);
17725384711e3c2894a84642c49953594930dd078abJames Lemieux            }
17825384711e3c2894a84642c49953594930dd078abJames Lemieux        }
17925384711e3c2894a84642c49953594930dd078abJames Lemieux
18025384711e3c2894a84642c49953594930dd078abJames Lemieux        @TargetApi(Build.VERSION_CODES.M)
18125384711e3c2894a84642c49953594930dd078abJames Lemieux        private boolean isDoNotDisturbBlockingAlarms() {
18225384711e3c2894a84642c49953594930dd078abJames Lemieux            if (!Utils.isMOrLater()) {
18325384711e3c2894a84642c49953594930dd078abJames Lemieux                return false;
18425384711e3c2894a84642c49953594930dd078abJames Lemieux            }
18525384711e3c2894a84642c49953594930dd078abJames Lemieux
18625384711e3c2894a84642c49953594930dd078abJames Lemieux            try {
18725384711e3c2894a84642c49953594930dd078abJames Lemieux                final int interruptionFilter = mNotificationManager.getCurrentInterruptionFilter();
18825384711e3c2894a84642c49953594930dd078abJames Lemieux                return interruptionFilter == INTERRUPTION_FILTER_NONE;
18925384711e3c2894a84642c49953594930dd078abJames Lemieux            } catch (Exception e) {
19025384711e3c2894a84642c49953594930dd078abJames Lemieux                // Since this is purely informational, avoid crashing the app.
19125384711e3c2894a84642c49953594930dd078abJames Lemieux                return false;
19225384711e3c2894a84642c49953594930dd078abJames Lemieux            }
19325384711e3c2894a84642c49953594930dd078abJames Lemieux        }
19425384711e3c2894a84642c49953594930dd078abJames Lemieux
19525384711e3c2894a84642c49953594930dd078abJames Lemieux        private boolean isAlarmStreamMuted() {
19625384711e3c2894a84642c49953594930dd078abJames Lemieux            try {
19725384711e3c2894a84642c49953594930dd078abJames Lemieux                return mAudioManager.getStreamVolume(STREAM_ALARM) <= 0;
19825384711e3c2894a84642c49953594930dd078abJames Lemieux            } catch (Exception e) {
19925384711e3c2894a84642c49953594930dd078abJames Lemieux                // Since this is purely informational, avoid crashing the app.
20025384711e3c2894a84642c49953594930dd078abJames Lemieux                return false;
20125384711e3c2894a84642c49953594930dd078abJames Lemieux            }
20225384711e3c2894a84642c49953594930dd078abJames Lemieux        }
20325384711e3c2894a84642c49953594930dd078abJames Lemieux
20425384711e3c2894a84642c49953594930dd078abJames Lemieux        private boolean isSystemAlarmRingtoneSilent() {
20525384711e3c2894a84642c49953594930dd078abJames Lemieux            try {
20625384711e3c2894a84642c49953594930dd078abJames Lemieux                return RingtoneManager.getActualDefaultRingtoneUri(mContext, TYPE_ALARM) == null;
20725384711e3c2894a84642c49953594930dd078abJames Lemieux            } catch (Exception e) {
20825384711e3c2894a84642c49953594930dd078abJames Lemieux                // Since this is purely informational, avoid crashing the app.
20925384711e3c2894a84642c49953594930dd078abJames Lemieux                return false;
21025384711e3c2894a84642c49953594930dd078abJames Lemieux            }
21125384711e3c2894a84642c49953594930dd078abJames Lemieux        }
21225384711e3c2894a84642c49953594930dd078abJames Lemieux
21325384711e3c2894a84642c49953594930dd078abJames Lemieux        private boolean isAppNotificationBlocked() {
21425384711e3c2894a84642c49953594930dd078abJames Lemieux            try {
21525384711e3c2894a84642c49953594930dd078abJames Lemieux                return !NotificationManagerCompat.from(mContext).areNotificationsEnabled();
21625384711e3c2894a84642c49953594930dd078abJames Lemieux            } catch (Exception e) {
21725384711e3c2894a84642c49953594930dd078abJames Lemieux                // Since this is purely informational, avoid crashing the app.
21825384711e3c2894a84642c49953594930dd078abJames Lemieux                return false;
21925384711e3c2894a84642c49953594930dd078abJames Lemieux            }
22025384711e3c2894a84642c49953594930dd078abJames Lemieux        }
22125384711e3c2894a84642c49953594930dd078abJames Lemieux    }
22225384711e3c2894a84642c49953594930dd078abJames Lemieux
22325384711e3c2894a84642c49953594930dd078abJames Lemieux    /**
22425384711e3c2894a84642c49953594930dd078abJames Lemieux     * Observe changes to specific URI for settings that can silence firing alarms.
22525384711e3c2894a84642c49953594930dd078abJames Lemieux     */
22625384711e3c2894a84642c49953594930dd078abJames Lemieux    private final class ContentChangeWatcher extends ContentObserver {
22725384711e3c2894a84642c49953594930dd078abJames Lemieux        private ContentChangeWatcher() {
22825384711e3c2894a84642c49953594930dd078abJames Lemieux            super(new Handler());
22925384711e3c2894a84642c49953594930dd078abJames Lemieux        }
23025384711e3c2894a84642c49953594930dd078abJames Lemieux
23125384711e3c2894a84642c49953594930dd078abJames Lemieux        @Override
23225384711e3c2894a84642c49953594930dd078abJames Lemieux        public void onChange(boolean selfChange) {
23325384711e3c2894a84642c49953594930dd078abJames Lemieux            updateSilentState();
23425384711e3c2894a84642c49953594930dd078abJames Lemieux        }
23525384711e3c2894a84642c49953594930dd078abJames Lemieux    }
23625384711e3c2894a84642c49953594930dd078abJames Lemieux
23725384711e3c2894a84642c49953594930dd078abJames Lemieux    /**
23825384711e3c2894a84642c49953594930dd078abJames Lemieux     * Observe changes to the do-not-disturb setting.
23925384711e3c2894a84642c49953594930dd078abJames Lemieux     */
24025384711e3c2894a84642c49953594930dd078abJames Lemieux    private final class DoNotDisturbChangeReceiver extends BroadcastReceiver {
24125384711e3c2894a84642c49953594930dd078abJames Lemieux        @Override
24225384711e3c2894a84642c49953594930dd078abJames Lemieux        public void onReceive(Context context, Intent intent) {
24325384711e3c2894a84642c49953594930dd078abJames Lemieux            updateSilentState();
24425384711e3c2894a84642c49953594930dd078abJames Lemieux        }
24525384711e3c2894a84642c49953594930dd078abJames Lemieux    }
24625384711e3c2894a84642c49953594930dd078abJames Lemieux}