1 /* 2 * Copyright (C) 2019 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.provider.Settings.Global.NOTIFICATION_BUBBLES; 20 21 import android.annotation.Nullable; 22 import android.content.Context; 23 import android.provider.Settings; 24 25 import com.android.settings.R; 26 import com.android.settings.core.PreferenceControllerMixin; 27 import com.android.settingslib.RestrictedSwitchPreference; 28 29 import androidx.annotation.VisibleForTesting; 30 import androidx.fragment.app.FragmentManager; 31 import androidx.preference.Preference; 32 33 public class BubblePreferenceController extends NotificationPreferenceController 34 implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { 35 36 private static final String TAG = "BubblePrefContr"; 37 private static final String KEY = "bubble_pref"; 38 @VisibleForTesting 39 static final int SYSTEM_WIDE_ON = 1; 40 @VisibleForTesting 41 static final int SYSTEM_WIDE_OFF = 0; 42 43 private FragmentManager mFragmentManager; 44 private boolean mIsAppPage; 45 BubblePreferenceController(Context context, @Nullable FragmentManager fragmentManager, NotificationBackend backend, boolean isAppPage)46 public BubblePreferenceController(Context context, @Nullable FragmentManager fragmentManager, 47 NotificationBackend backend, boolean isAppPage) { 48 super(context, backend); 49 mFragmentManager = fragmentManager; 50 mIsAppPage = isAppPage; 51 } 52 53 @Override getPreferenceKey()54 public String getPreferenceKey() { 55 return KEY; 56 } 57 58 @Override isAvailable()59 public boolean isAvailable() { 60 if (!super.isAvailable()) { 61 return false; 62 } 63 if (!mIsAppPage && !isGloballyEnabled()) { 64 return false; 65 } 66 if (mChannel != null) { 67 if (isDefaultChannel()) { 68 return true; 69 } else { 70 return mAppRow != null && mAppRow.allowBubbles; 71 } 72 } 73 return true; 74 } 75 updateState(Preference preference)76 public void updateState(Preference preference) { 77 if (mAppRow != null) { 78 RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference; 79 pref.setDisabledByAdmin(mAdmin); 80 if (mChannel != null) { 81 pref.setChecked(mChannel.canBubble() && isGloballyEnabled()); 82 pref.setEnabled(!pref.isDisabledByAdmin()); 83 } else { 84 pref.setChecked(mAppRow.allowBubbles && isGloballyEnabled()); 85 pref.setSummary(mContext.getString( 86 R.string.bubbles_app_toggle_summary, mAppRow.label)); 87 } 88 } 89 } 90 91 @Override onPreferenceChange(Preference preference, Object newValue)92 public boolean onPreferenceChange(Preference preference, Object newValue) { 93 final boolean value = (Boolean) newValue && isGloballyEnabled(); 94 if (mChannel != null) { 95 mChannel.setAllowBubbles(value); 96 saveChannel(); 97 return true; 98 } else if (mAppRow != null && mFragmentManager != null) { 99 RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference; 100 // if the global setting is off, toggling app level permission requires extra 101 // confirmation 102 if (!isGloballyEnabled() && !pref.isChecked()) { 103 new BubbleWarningDialogFragment() 104 .setPkgInfo(mAppRow.pkg, mAppRow.uid) 105 .show(mFragmentManager, "dialog"); 106 return false; 107 } else { 108 mAppRow.allowBubbles = value; 109 mBackend.setAllowBubbles(mAppRow.pkg, mAppRow.uid, value); 110 } 111 } 112 return true; 113 } 114 isGloballyEnabled()115 private boolean isGloballyEnabled() { 116 return Settings.Global.getInt(mContext.getContentResolver(), 117 NOTIFICATION_BUBBLES, SYSTEM_WIDE_OFF) == SYSTEM_WIDE_ON; 118 } 119 120 // Used in app level prompt that confirms the user is ok with turning on bubbles 121 // globally. If they aren't, undo what revertBubblesApproval(Context mContext, String pkg, int uid)122 public static void revertBubblesApproval(Context mContext, String pkg, int uid) { 123 NotificationBackend backend = new NotificationBackend(); 124 backend.setAllowBubbles(pkg, uid, false); 125 // changing the global settings will cause the observer on the host page to reload 126 // correct preference state 127 Settings.Global.putInt(mContext.getContentResolver(), 128 NOTIFICATION_BUBBLES, SYSTEM_WIDE_OFF); 129 } 130 131 // Apply global bubbles approval applyBubblesApproval(Context mContext, String pkg, int uid)132 public static void applyBubblesApproval(Context mContext, String pkg, int uid) { 133 NotificationBackend backend = new NotificationBackend(); 134 backend.setAllowBubbles(pkg, uid, true); 135 // changing the global settings will cause the observer on the host page to reload 136 // correct preference state 137 Settings.Global.putInt(mContext.getContentResolver(), 138 NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON); 139 } 140 } 141