1 /* 2 * Copyright (C) 2022 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.safetycenter; 18 19 import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED; 20 21 import android.app.PendingIntent; 22 import android.app.settings.SettingsEnums; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.os.UserHandle; 26 import android.os.UserManager; 27 import android.safetycenter.SafetyEvent; 28 import android.safetycenter.SafetySourceData; 29 import android.safetycenter.SafetySourceIssue; 30 import android.safetycenter.SafetySourceStatus; 31 import android.safetycenter.SafetySourceStatus.IconAction; 32 33 import com.android.settings.R; 34 import com.android.settings.security.ScreenLockPreferenceDetailsUtils; 35 import com.android.settingslib.RestrictedLockUtils; 36 import com.android.settingslib.RestrictedLockUtilsInternal; 37 38 /** Lock Screen Safety Source for Safety Center. */ 39 public final class LockScreenSafetySource { 40 41 public static final String SAFETY_SOURCE_ID = "AndroidLockScreen"; 42 public static final String NO_SCREEN_LOCK_ISSUE_ID = "NoScreenLockIssue"; 43 public static final String NO_SCREEN_LOCK_ISSUE_TYPE_ID = "NoScreenLockIssueType"; 44 public static final String SET_SCREEN_LOCK_ACTION_ID = "SetScreenLockAction"; 45 46 private static final int REQUEST_CODE_SCREEN_LOCK = 1; 47 private static final int REQUEST_CODE_SCREEN_LOCK_SETTINGS = 2; 48 LockScreenSafetySource()49 private LockScreenSafetySource() { 50 } 51 52 /** Sets lock screen safety data for Safety Center. */ setSafetySourceData(Context context, ScreenLockPreferenceDetailsUtils screenLockPreferenceDetailsUtils, SafetyEvent safetyEvent)53 public static void setSafetySourceData(Context context, 54 ScreenLockPreferenceDetailsUtils screenLockPreferenceDetailsUtils, 55 SafetyEvent safetyEvent) { 56 if (!SafetyCenterManagerWrapper.get().isEnabled(context)) { 57 return; 58 } 59 60 UserManager userManager = context.getSystemService(UserManager.class); 61 if (userManager != null && userManager.isProfile()) { 62 return; // LockScreen source only supports primary profile. 63 } 64 65 if (!screenLockPreferenceDetailsUtils.isAvailable()) { 66 return; 67 } 68 69 final int userId = UserHandle.myUserId(); 70 final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtilsInternal 71 .checkIfPasswordQualityIsSet(context, userId); 72 final PendingIntent pendingIntent = createPendingIntent(context, 73 screenLockPreferenceDetailsUtils.getLaunchChooseLockGenericFragmentIntent( 74 SettingsEnums.SAFETY_CENTER), REQUEST_CODE_SCREEN_LOCK); 75 final IconAction gearMenuIconAction = createGearMenuIconAction(context, 76 screenLockPreferenceDetailsUtils); 77 final boolean enabled = 78 !screenLockPreferenceDetailsUtils.isPasswordQualityManaged(userId, admin); 79 final boolean isLockPatternSecure = screenLockPreferenceDetailsUtils.isLockPatternSecure(); 80 final int severityLevel = enabled 81 ? isLockPatternSecure 82 ? SafetySourceData.SEVERITY_LEVEL_INFORMATION 83 : SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION 84 : SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED; 85 86 87 final SafetySourceStatus status = new SafetySourceStatus.Builder( 88 context.getString(R.string.unlock_set_unlock_launch_picker_title), 89 screenLockPreferenceDetailsUtils.getSummary(UserHandle.myUserId()), 90 severityLevel) 91 .setPendingIntent(pendingIntent) 92 .setEnabled(enabled) 93 .setIconAction(gearMenuIconAction).build(); 94 final SafetySourceData.Builder safetySourceDataBuilder = 95 new SafetySourceData.Builder().setStatus(status); 96 if (enabled && !isLockPatternSecure) { 97 safetySourceDataBuilder.addIssue(createNoScreenLockIssue(context, pendingIntent)); 98 } 99 final SafetySourceData safetySourceData = safetySourceDataBuilder.build(); 100 101 SafetyCenterManagerWrapper.get().setSafetySourceData( 102 context, 103 SAFETY_SOURCE_ID, 104 safetySourceData, 105 safetyEvent 106 ); 107 } 108 109 /** Notifies Safety Center of a change in lock screen settings. */ onLockScreenChange(Context context)110 public static void onLockScreenChange(Context context) { 111 setSafetySourceData( 112 context, new ScreenLockPreferenceDetailsUtils(context), 113 new SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()); 114 115 // Also send refreshed safety center data for biometrics, since changing lockscreen settings 116 // can unset biometrics. 117 BiometricsSafetySource.onBiometricsChanged(context); 118 } 119 createGearMenuIconAction(Context context, ScreenLockPreferenceDetailsUtils screenLockPreferenceDetailsUtils)120 private static IconAction createGearMenuIconAction(Context context, 121 ScreenLockPreferenceDetailsUtils screenLockPreferenceDetailsUtils) { 122 return screenLockPreferenceDetailsUtils.shouldShowGearMenu() ? new IconAction( 123 IconAction.ICON_TYPE_GEAR, 124 createPendingIntent(context, 125 screenLockPreferenceDetailsUtils.getLaunchScreenLockSettingsIntent( 126 SettingsEnums.SAFETY_CENTER), 127 REQUEST_CODE_SCREEN_LOCK_SETTINGS)) 128 : null; 129 } 130 createPendingIntent(Context context, Intent intent, int requestCode)131 private static PendingIntent createPendingIntent(Context context, Intent intent, 132 int requestCode) { 133 return PendingIntent 134 .getActivity( 135 context, 136 requestCode, 137 intent, 138 PendingIntent.FLAG_IMMUTABLE); 139 } 140 createNoScreenLockIssue(Context context, PendingIntent pendingIntent)141 private static SafetySourceIssue createNoScreenLockIssue(Context context, 142 PendingIntent pendingIntent) { 143 final SafetySourceIssue.Action action = new SafetySourceIssue.Action.Builder( 144 SET_SCREEN_LOCK_ACTION_ID, 145 context.getString(R.string.no_screen_lock_issue_action_label), 146 pendingIntent).build(); 147 // Custom notification deliberately has zero actions 148 final SafetySourceIssue.Notification customNotification = 149 new SafetySourceIssue.Notification.Builder( 150 context.getString(R.string.no_screen_lock_issue_notification_title), 151 context.getString(R.string.no_screen_lock_issue_notification_text)) 152 .build(); 153 return new SafetySourceIssue.Builder( 154 NO_SCREEN_LOCK_ISSUE_ID, 155 context.getString(R.string.no_screen_lock_issue_title), 156 context.getString(R.string.no_screen_lock_issue_summary), 157 SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION, 158 NO_SCREEN_LOCK_ISSUE_TYPE_ID) 159 .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE) 160 .addAction(action) 161 .setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL) 162 .setCustomNotification(customNotification) 163 .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED) 164 .build(); 165 } 166 } 167