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.homepage.contextualcards.slices; 18 19 20 import android.app.PendingIntent; 21 import android.app.settings.SettingsEnums; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.hardware.face.FaceManager; 25 import android.net.Uri; 26 import android.os.UserHandle; 27 import android.provider.Settings; 28 29 import androidx.core.graphics.drawable.IconCompat; 30 import androidx.slice.Slice; 31 import androidx.slice.builders.ListBuilder; 32 import androidx.slice.builders.ListBuilder.RowBuilder; 33 import androidx.slice.builders.SliceAction; 34 35 import com.android.settings.R; 36 import com.android.settings.SubSettings; 37 import com.android.settings.Utils; 38 import com.android.settings.biometrics.face.FaceStatusPreferenceController; 39 import com.android.settings.homepage.contextualcards.FaceReEnrollDialog; 40 import com.android.settings.security.SecuritySettings; 41 import com.android.settings.slices.CustomSliceRegistry; 42 import com.android.settings.slices.CustomSliceable; 43 import com.android.settings.slices.SliceBuilderUtils; 44 45 /** 46 * This class is used for showing re-enroll suggestions in the Settings page. By either having an 47 * un-enrolled user or setting {@link Settings.Secure#FACE_UNLOCK_RE_ENROLL} to one of the 48 * states listed in {@link Settings.Secure} the slice will change its text and potentially show 49 * a {@link FaceReEnrollDialog}. 50 */ 51 public class FaceSetupSlice implements CustomSliceable { 52 53 private final Context mContext; 54 /** 55 * If a user currently is not enrolled then this class will show a recommendation to 56 * enroll their face. 57 */ 58 private FaceManager mFaceManager; 59 60 /** 61 * Various states the {@link FaceSetupSlice} can be in, 62 * See {@link Settings.Secure#FACE_UNLOCK_RE_ENROLL} for more details. 63 */ 64 65 // No re-enrollment. 66 public static final int FACE_NO_RE_ENROLL_REQUIRED = 0; 67 // Re enrollment is suggested. 68 public static final int FACE_RE_ENROLL_SUGGESTED = 1; 69 // Re enrollment is required after a set time period. 70 public static final int FACE_RE_ENROLL_AFTER_TIMEOUT = 2; 71 // Re enrollment is required immediately. 72 public static final int FACE_RE_ENROLL_REQUIRED = 3; 73 FaceSetupSlice(Context context)74 public FaceSetupSlice(Context context) { 75 mContext = context; 76 } 77 78 @Override getSlice()79 public Slice getSlice() { 80 mFaceManager = Utils.getFaceManagerOrNull(mContext); 81 if (mFaceManager == null) { 82 return new ListBuilder(mContext, CustomSliceRegistry.FACE_ENROLL_SLICE_URI, 83 ListBuilder.INFINITY).setIsError(true).build(); 84 } 85 86 final int userId = UserHandle.myUserId(); 87 final boolean hasEnrolledTemplates = mFaceManager.hasEnrolledTemplates(userId); 88 final int shouldReEnroll = FaceSetupSlice.getReEnrollSetting(mContext, userId); 89 90 CharSequence title = ""; 91 CharSequence subtitle = ""; 92 93 // Set the title and subtitle according to the different states, the icon and layout will 94 // stay the same. 95 if (!hasEnrolledTemplates) { 96 title = mContext.getText(R.string.security_settings_face_settings_enroll); 97 subtitle = mContext.getText( 98 R.string.security_settings_face_settings_context_subtitle); 99 } else if (shouldReEnroll == FACE_RE_ENROLL_SUGGESTED) { 100 title = mContext.getText( 101 R.string.security_settings_face_enroll_should_re_enroll_title); 102 subtitle = mContext.getText( 103 R.string.security_settings_face_enroll_should_re_enroll_subtitle); 104 } else if (shouldReEnroll == FACE_RE_ENROLL_REQUIRED) { 105 title = mContext.getText( 106 R.string.security_settings_face_enroll_must_re_enroll_title); 107 subtitle = mContext.getText( 108 R.string.security_settings_face_enroll_must_re_enroll_subtitle); 109 } else { 110 return new ListBuilder(mContext, CustomSliceRegistry.FACE_ENROLL_SLICE_URI, 111 ListBuilder.INFINITY).setIsError(true).build(); 112 } 113 114 final ListBuilder listBuilder = new ListBuilder(mContext, 115 CustomSliceRegistry.FACE_ENROLL_SLICE_URI, ListBuilder.INFINITY) 116 .setAccentColor(Utils.getColorAccentDefaultColor(mContext)); 117 final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_face_24dp); 118 return listBuilder.addRow(buildRowBuilder(title, subtitle, icon, mContext, getIntent())) 119 .build(); 120 } 121 122 @Override getUri()123 public Uri getUri() { 124 return CustomSliceRegistry.FACE_ENROLL_SLICE_URI; 125 } 126 127 @Override getIntent()128 public Intent getIntent() { 129 final boolean hasEnrolledTemplates = mFaceManager.hasEnrolledTemplates( 130 UserHandle.myUserId()); 131 if (!hasEnrolledTemplates) { 132 return SliceBuilderUtils.buildSearchResultPageIntent(mContext, 133 SecuritySettings.class.getName(), 134 FaceStatusPreferenceController.KEY_FACE_SETTINGS, 135 mContext.getText(R.string.security_settings_face_settings_enroll).toString(), 136 SettingsEnums.SLICE, this) 137 .setClassName(mContext.getPackageName(), SubSettings.class.getName()); 138 } else { 139 return new Intent(mContext, FaceReEnrollDialog.class); 140 } 141 } 142 143 @Override getSliceHighlightMenuRes()144 public int getSliceHighlightMenuRes() { 145 return R.string.menu_key_security; 146 } 147 buildRowBuilder(CharSequence title, CharSequence subTitle, IconCompat icon, Context context, Intent intent)148 private static RowBuilder buildRowBuilder(CharSequence title, CharSequence subTitle, 149 IconCompat icon, Context context, Intent intent) { 150 final SliceAction primarySliceAction = SliceAction.createDeeplink( 151 PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE), 152 icon, ListBuilder.ICON_IMAGE, title); 153 return new RowBuilder() 154 .setTitleItem(icon, ListBuilder.ICON_IMAGE) 155 .setTitle(title) 156 .setSubtitle(subTitle) 157 .setPrimaryAction(primarySliceAction); 158 } 159 getReEnrollSetting(Context context, int userId)160 public static int getReEnrollSetting(Context context, int userId) { 161 return Settings.Secure.getIntForUser(context.getContentResolver(), 162 Settings.Secure.FACE_UNLOCK_RE_ENROLL, FACE_NO_RE_ENROLL_REQUIRED, userId); 163 } 164 165 }