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