1 /* 2 * Copyright (C) 2018 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 static android.app.slice.Slice.EXTRA_TOGGLE_STATE; 20 21 import static androidx.slice.builders.ListBuilder.ICON_IMAGE; 22 23 import android.annotation.ColorInt; 24 import android.app.NotificationManager; 25 import android.app.PendingIntent; 26 import android.content.ContentResolver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.net.Uri; 31 import android.provider.Settings; 32 import android.provider.SettingsSlicesContract; 33 34 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 35 import com.android.settings.R; 36 import com.android.settings.SubSettings; 37 import com.android.settings.Utils; 38 import com.android.settings.search.DatabaseIndexingUtils; 39 import com.android.settings.slices.SettingsSliceProvider; 40 import com.android.settings.slices.SliceBroadcastReceiver; 41 import com.android.settings.slices.SliceBuilderUtils; 42 43 import androidx.slice.Slice; 44 import androidx.slice.builders.ListBuilder; 45 import androidx.slice.builders.SliceAction; 46 47 import android.support.v4.graphics.drawable.IconCompat; 48 49 public class ZenModeSliceBuilder { 50 51 private static final String TAG = "ZenModeSliceBuilder"; 52 53 private static final String ZEN_MODE_KEY = "zen_mode"; 54 55 /** 56 * Backing Uri for the Zen Mode Slice. 57 */ 58 public static final Uri ZEN_MODE_URI = new Uri.Builder() 59 .scheme(ContentResolver.SCHEME_CONTENT) 60 .authority(SettingsSliceProvider.SLICE_AUTHORITY) 61 .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) 62 .appendPath(ZEN_MODE_KEY) 63 .build(); 64 65 /** 66 * Action notifying a change on the Zen Mode Slice. 67 */ 68 public static final String ACTION_ZEN_MODE_SLICE_CHANGED = 69 "com.android.settings.notification.ZEN_MODE_CHANGED"; 70 71 public static final IntentFilter INTENT_FILTER = new IntentFilter(); 72 73 static { 74 INTENT_FILTER.addAction(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED); 75 INTENT_FILTER.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); 76 INTENT_FILTER.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL); 77 } 78 ZenModeSliceBuilder()79 private ZenModeSliceBuilder() { 80 } 81 82 /** 83 * Return a ZenMode Slice bound to {@link #ZEN_MODE_URI}. 84 * <p> 85 * Note that you should register a listener for {@link #INTENT_FILTER} to get changes for 86 * ZenMode. 87 */ getSlice(Context context)88 public static Slice getSlice(Context context) { 89 final boolean isZenModeEnabled = isZenModeEnabled(context); 90 final CharSequence title = context.getText(R.string.zen_mode_settings_title); 91 @ColorInt final int color = Utils.getColorAccent(context); 92 final PendingIntent toggleAction = getBroadcastIntent(context); 93 final PendingIntent primaryAction = getPrimaryAction(context); 94 final SliceAction primarySliceAction = new SliceAction(primaryAction, 95 (IconCompat) null /* icon */, title); 96 final SliceAction toggleSliceAction = new SliceAction(toggleAction, null /* actionTitle */, 97 isZenModeEnabled); 98 99 return new ListBuilder(context, ZEN_MODE_URI, ListBuilder.INFINITY) 100 .setAccentColor(color) 101 .addRow(b -> b 102 .setTitle(title) 103 .addEndItem(toggleSliceAction) 104 .setPrimaryAction(primarySliceAction)) 105 .build(); 106 } 107 108 /** 109 * Update the current ZenMode status to the boolean value keyed by 110 * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}. 111 */ handleUriChange(Context context, Intent intent)112 public static void handleUriChange(Context context, Intent intent) { 113 final boolean zenModeOn = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, false); 114 final int zenMode; 115 if (zenModeOn) { 116 zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; 117 } else { 118 zenMode = Settings.Global.ZEN_MODE_OFF; 119 } 120 NotificationManager.from(context).setZenMode(zenMode, null /* conditionId */, TAG); 121 // Do not notifyChange on Uri. The service takes longer to update the current value than it 122 // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay} 123 // handle it. 124 } 125 getIntent(Context context)126 public static Intent getIntent(Context context) { 127 final Uri contentUri = new Uri.Builder().appendPath(ZEN_MODE_KEY).build(); 128 final String screenTitle = context.getText(R.string.zen_mode_settings_title).toString(); 129 return DatabaseIndexingUtils.buildSearchResultPageIntent(context, 130 ZenModeSettings.class.getName(), ZEN_MODE_KEY, screenTitle, 131 MetricsEvent.NOTIFICATION_ZEN_MODE) 132 .setClassName(context.getPackageName(), SubSettings.class.getName()) 133 .setData(contentUri); 134 } 135 isZenModeEnabled(Context context)136 private static boolean isZenModeEnabled(Context context) { 137 final NotificationManager manager = context.getSystemService(NotificationManager.class); 138 final int zenMode = manager.getZenMode(); 139 140 switch (zenMode) { 141 case Settings.Global.ZEN_MODE_ALARMS: 142 case Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: 143 case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS: 144 return true; 145 case Settings.Global.ZEN_MODE_OFF: 146 default: 147 return false; 148 } 149 } 150 getPrimaryAction(Context context)151 private static PendingIntent getPrimaryAction(Context context) { 152 final Intent intent = getIntent(context); 153 return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */); 154 } 155 getBroadcastIntent(Context context)156 private static PendingIntent getBroadcastIntent(Context context) { 157 final Intent intent = new Intent(ACTION_ZEN_MODE_SLICE_CHANGED) 158 .setClass(context, SliceBroadcastReceiver.class); 159 return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent, 160 PendingIntent.FLAG_CANCEL_CURRENT); 161 } 162 } 163