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