1 /*
2  * Copyright (C) 2016 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.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
20 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
21 
22 import android.app.admin.DevicePolicyManager;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.database.ContentObserver;
26 import android.net.Uri;
27 import android.os.Handler;
28 import android.os.UserHandle;
29 import android.os.UserManager;
30 import android.provider.Settings;
31 import android.text.TextUtils;
32 import android.util.Log;
33 
34 import androidx.preference.Preference;
35 import androidx.preference.PreferenceScreen;
36 
37 import com.android.internal.widget.LockPatternUtils;
38 import com.android.settings.R;
39 import com.android.settings.RestrictedListPreference;
40 import com.android.settings.Utils;
41 import com.android.settings.core.PreferenceControllerMixin;
42 import com.android.settings.overlay.FeatureFactory;
43 import com.android.settingslib.RestrictedLockUtils;
44 import com.android.settingslib.RestrictedLockUtilsInternal;
45 import com.android.settingslib.core.AbstractPreferenceController;
46 import com.android.settingslib.core.lifecycle.LifecycleObserver;
47 import com.android.settingslib.core.lifecycle.events.OnPause;
48 import com.android.settingslib.core.lifecycle.events.OnResume;
49 
50 import java.util.ArrayList;
51 
52 public class LockScreenNotificationPreferenceController extends AbstractPreferenceController
53         implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener,
54         LifecycleObserver, OnResume, OnPause {
55 
56     private static final String TAG = "LockScreenNotifPref";
57 
58     private final String mSettingKey;
59     private final String mWorkSettingCategoryKey;
60     private final String mWorkSettingKey;
61 
62     private RestrictedListPreference mLockscreen;
63     private RestrictedListPreference mLockscreenProfile;
64 
65     private final int mProfileUserId;
66     private final boolean mSecure;
67     private final boolean mSecureProfile;
68 
69     private SettingObserver mSettingObserver;
70     private int mLockscreenSelectedValue;
71     private int mLockscreenSelectedValueProfile;
72 
LockScreenNotificationPreferenceController(Context context)73     public LockScreenNotificationPreferenceController(Context context) {
74         this(context, null, null, null);
75     }
76 
LockScreenNotificationPreferenceController(Context context, String settingKey, String workSettingCategoryKey, String workSettingKey)77     public LockScreenNotificationPreferenceController(Context context,
78             String settingKey, String workSettingCategoryKey, String workSettingKey) {
79         super(context);
80         mSettingKey = settingKey;
81         mWorkSettingCategoryKey = workSettingCategoryKey;
82         mWorkSettingKey = workSettingKey;
83 
84         mProfileUserId = Utils.getManagedProfileId(UserManager.get(context), UserHandle.myUserId());
85         final LockPatternUtils utils = FeatureFactory.getFactory(context)
86                 .getSecurityFeatureProvider()
87                 .getLockPatternUtils(context);
88         mSecure = utils.isSecure(UserHandle.myUserId());
89         mSecureProfile = (mProfileUserId != UserHandle.USER_NULL) && utils.isSecure(mProfileUserId);
90     }
91 
92     @Override
displayPreference(PreferenceScreen screen)93     public void displayPreference(PreferenceScreen screen) {
94         super.displayPreference(screen);
95         mLockscreen = screen.findPreference(mSettingKey);
96         if (mLockscreen == null) {
97             Log.i(TAG, "Preference not found: " + mSettingKey);
98             return;
99         }
100         if (mProfileUserId != UserHandle.USER_NULL) {
101             mLockscreenProfile = screen.findPreference(mWorkSettingKey);
102             mLockscreenProfile.setRequiresActiveUnlockedProfile(true);
103             mLockscreenProfile.setProfileUserId(mProfileUserId);
104         } else {
105             setVisible(screen, mWorkSettingKey, false /* visible */);
106             setVisible(screen, mWorkSettingCategoryKey, false /* visible */);
107         }
108         mSettingObserver = new SettingObserver();
109         initLockScreenNotificationPrefDisplay();
110         initLockscreenNotificationPrefForProfile();
111     }
112 
initLockScreenNotificationPrefDisplay()113     private void initLockScreenNotificationPrefDisplay() {
114         ArrayList<CharSequence> entries = new ArrayList<>();
115         ArrayList<CharSequence> values = new ArrayList<>();
116 
117         String summaryShowEntry =
118                 mContext.getString(R.string.lock_screen_notifications_summary_show);
119         String summaryShowEntryValue =
120                 Integer.toString(R.string.lock_screen_notifications_summary_show);
121         entries.add(summaryShowEntry);
122         values.add(summaryShowEntryValue);
123         setRestrictedIfNotificationFeaturesDisabled(summaryShowEntry, summaryShowEntryValue,
124                 KEYGUARD_DISABLE_SECURE_NOTIFICATIONS | KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
125 
126         if (mSecure) {
127             String summaryHideEntry =
128                     mContext.getString(R.string.lock_screen_notifications_summary_hide);
129             String summaryHideEntryValue =
130                     Integer.toString(R.string.lock_screen_notifications_summary_hide);
131             entries.add(summaryHideEntry);
132             values.add(summaryHideEntryValue);
133             setRestrictedIfNotificationFeaturesDisabled(summaryHideEntry, summaryHideEntryValue,
134                     KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
135         }
136 
137         entries.add(mContext.getString(R.string.lock_screen_notifications_summary_disable));
138         values.add(Integer.toString(R.string.lock_screen_notifications_summary_disable));
139 
140 
141         mLockscreen.setEntries(entries.toArray(new CharSequence[entries.size()]));
142         mLockscreen.setEntryValues(values.toArray(new CharSequence[values.size()]));
143         updateLockscreenNotifications();
144 
145         if (mLockscreen.getEntries().length > 1) {
146             mLockscreen.setOnPreferenceChangeListener(this);
147         } else {
148             // There is one or less option for the user, disable the drop down.
149             mLockscreen.setEnabled(false);
150         }
151     }
152 
initLockscreenNotificationPrefForProfile()153     private void initLockscreenNotificationPrefForProfile() {
154         if (mLockscreenProfile == null) {
155             Log.i(TAG, "Preference not found: " + mWorkSettingKey);
156             return;
157         }
158         ArrayList<CharSequence> entries = new ArrayList<>();
159         ArrayList<CharSequence> values = new ArrayList<>();
160 
161         String summaryShowEntry = mContext.getString(
162                 R.string.lock_screen_notifications_summary_show_profile);
163         String summaryShowEntryValue = Integer.toString(
164                 R.string.lock_screen_notifications_summary_show_profile);
165         entries.add(summaryShowEntry);
166         values.add(summaryShowEntryValue);
167         setRestrictedIfNotificationFeaturesDisabled(summaryShowEntry, summaryShowEntryValue,
168                 KEYGUARD_DISABLE_SECURE_NOTIFICATIONS | KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
169 
170         if (mSecureProfile) {
171             String summaryHideEntry = mContext.getString(
172                     R.string.lock_screen_notifications_summary_hide_profile);
173             String summaryHideEntryValue = Integer.toString(
174                     R.string.lock_screen_notifications_summary_hide_profile);
175             entries.add(summaryHideEntry);
176             values.add(summaryHideEntryValue);
177             setRestrictedIfNotificationFeaturesDisabled(summaryHideEntry, summaryHideEntryValue,
178                     KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
179         }
180 
181         mLockscreenProfile.setEntries(entries.toArray(new CharSequence[entries.size()]));
182         mLockscreenProfile.setEntryValues(values.toArray(new CharSequence[values.size()]));
183         updateLockscreenNotificationsForProfile();
184         if (mLockscreenProfile.getEntries().length > 1) {
185             mLockscreenProfile.setOnPreferenceChangeListener(this);
186         } else {
187             // There is one or less option for the user, disable the drop down.
188             mLockscreenProfile.setEnabled(false);
189         }
190     }
191 
192     @Override
getPreferenceKey()193     public String getPreferenceKey() {
194         return null;
195     }
196 
197     @Override
isAvailable()198     public boolean isAvailable() {
199         return false;
200     }
201 
202     @Override
onResume()203     public void onResume() {
204         if (mSettingObserver != null) {
205             mSettingObserver.register(mContext.getContentResolver(), true /* register */);
206         }
207     }
208 
209     @Override
onPause()210     public void onPause() {
211         if (mSettingObserver != null) {
212             mSettingObserver.register(mContext.getContentResolver(), false /* register */);
213         }
214     }
215 
216     @Override
onPreferenceChange(Preference preference, Object newValue)217     public boolean onPreferenceChange(Preference preference, Object newValue) {
218         final String key = preference.getKey();
219         if (TextUtils.equals(mWorkSettingKey, key)) {
220             final int val = Integer.parseInt((String) newValue);
221             if (val == mLockscreenSelectedValueProfile) {
222                 return false;
223             }
224             final boolean show = val == R.string.lock_screen_notifications_summary_show_profile;
225             Settings.Secure.putIntForUser(mContext.getContentResolver(),
226                     Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
227                     show ? 1 : 0, mProfileUserId);
228             mLockscreenSelectedValueProfile = val;
229             return true;
230         } else if (TextUtils.equals(mSettingKey, key)) {
231             final int val = Integer.parseInt((String) newValue);
232             if (val == mLockscreenSelectedValue) {
233                 return false;
234             }
235             final boolean enabled = val != R.string.lock_screen_notifications_summary_disable;
236             final boolean show = val == R.string.lock_screen_notifications_summary_show;
237             Settings.Secure.putInt(mContext.getContentResolver(),
238                     Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, show ? 1 : 0);
239             Settings.Secure.putInt(mContext.getContentResolver(),
240                     Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, enabled ? 1 : 0);
241             mLockscreenSelectedValue = val;
242             return true;
243         }
244         return false;
245     }
246 
setRestrictedIfNotificationFeaturesDisabled(CharSequence entry, CharSequence entryValue, int keyguardNotificationFeatures)247     private void setRestrictedIfNotificationFeaturesDisabled(CharSequence entry,
248             CharSequence entryValue, int keyguardNotificationFeatures) {
249         RestrictedLockUtils.EnforcedAdmin admin =
250                 RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
251                         mContext, keyguardNotificationFeatures, UserHandle.myUserId());
252         if (admin != null && mLockscreen != null) {
253             RestrictedListPreference.RestrictedItem item =
254                     new RestrictedListPreference.RestrictedItem(entry, entryValue, admin);
255             mLockscreen.addRestrictedItem(item);
256         }
257         if (mProfileUserId != UserHandle.USER_NULL) {
258             RestrictedLockUtils.EnforcedAdmin profileAdmin =
259                     RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
260                             mContext, keyguardNotificationFeatures, mProfileUserId);
261             if (profileAdmin != null && mLockscreenProfile != null) {
262                 RestrictedListPreference.RestrictedItem item =
263                         new RestrictedListPreference.RestrictedItem(
264                                 entry, entryValue, profileAdmin);
265                 mLockscreenProfile.addRestrictedItem(item);
266             }
267         }
268     }
269 
getSummaryResource(Context context)270     public static int getSummaryResource(Context context) {
271         final boolean enabled = getLockscreenNotificationsEnabled(context);
272         final boolean secure = FeatureFactory.getFactory(context)
273                 .getSecurityFeatureProvider()
274                 .getLockPatternUtils(context)
275                 .isSecure(UserHandle.myUserId());
276         final boolean allowPrivate = !secure
277             || getAllowPrivateNotifications(context, UserHandle.myUserId());
278         return !enabled ? R.string.lock_screen_notifications_summary_disable :
279             allowPrivate ? R.string.lock_screen_notifications_summary_show :
280                 R.string.lock_screen_notifications_summary_hide;
281     }
282 
updateLockscreenNotifications()283     private void updateLockscreenNotifications() {
284         if (mLockscreen == null) {
285             return;
286         }
287         mLockscreenSelectedValue = getSummaryResource(mContext);
288         mLockscreen.setSummary("%s");
289         mLockscreen.setValue(Integer.toString(mLockscreenSelectedValue));
290     }
291 
adminAllowsUnredactedNotifications(int userId)292     private boolean adminAllowsUnredactedNotifications(int userId) {
293         final int dpmFlags = mContext.getSystemService(DevicePolicyManager.class)
294                 .getKeyguardDisabledFeatures(null/* admin */, userId);
295         return (dpmFlags & KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
296     }
297 
updateLockscreenNotificationsForProfile()298     private void updateLockscreenNotificationsForProfile() {
299         if (mProfileUserId == UserHandle.USER_NULL) {
300             return;
301         }
302         if (mLockscreenProfile == null) {
303             return;
304         }
305         final boolean allowPrivate = adminAllowsUnredactedNotifications(mProfileUserId) &&
306                 (!mSecureProfile || getAllowPrivateNotifications(mContext, mProfileUserId));
307         mLockscreenProfile.setSummary("%s");
308         mLockscreenSelectedValueProfile = allowPrivate
309                         ? R.string.lock_screen_notifications_summary_show_profile
310                         : R.string.lock_screen_notifications_summary_hide_profile;
311         mLockscreenProfile.setValue(Integer.toString(mLockscreenSelectedValueProfile));
312     }
313 
getLockscreenNotificationsEnabled(Context context)314     private static boolean getLockscreenNotificationsEnabled(Context context) {
315         return Settings.Secure.getInt(context.getContentResolver(),
316                 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0;
317     }
318 
getAllowPrivateNotifications(Context context, int userId)319     private static boolean getAllowPrivateNotifications(Context context, int userId) {
320         return Settings.Secure.getIntForUser(context.getContentResolver(),
321                 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userId) != 0;
322     }
323 
324     class SettingObserver extends ContentObserver {
325 
326         private final Uri LOCK_SCREEN_PRIVATE_URI =
327                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
328         private final Uri LOCK_SCREEN_SHOW_URI =
329                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
330 
SettingObserver()331         public SettingObserver() {
332             super(new Handler());
333         }
334 
register(ContentResolver cr, boolean register)335         public void register(ContentResolver cr, boolean register) {
336             if (register) {
337                 cr.registerContentObserver(LOCK_SCREEN_PRIVATE_URI, false, this);
338                 cr.registerContentObserver(LOCK_SCREEN_SHOW_URI, false, this);
339             } else {
340                 cr.unregisterContentObserver(this);
341             }
342         }
343 
344         @Override
onChange(boolean selfChange, Uri uri)345         public void onChange(boolean selfChange, Uri uri) {
346             super.onChange(selfChange, uri);
347             if (LOCK_SCREEN_PRIVATE_URI.equals(uri) || LOCK_SCREEN_SHOW_URI.equals(uri)) {
348                 updateLockscreenNotifications();
349                 if (mProfileUserId != UserHandle.USER_NULL) {
350                     updateLockscreenNotificationsForProfile();
351                 }
352             }
353         }
354     }
355 }
356