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}