1 /* 2 * Copyright (C) 2014 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; 18 19 import android.accessibilityservice.AccessibilityServiceInfo; 20 import android.app.Activity; 21 import android.app.Dialog; 22 import android.app.admin.DevicePolicyManager; 23 import android.app.settings.SettingsEnums; 24 import android.content.Context; 25 import android.content.DialogInterface; 26 import android.content.Intent; 27 import android.content.res.Resources; 28 import android.os.Bundle; 29 import android.util.Log; 30 import android.view.LayoutInflater; 31 import android.view.View; 32 import android.view.ViewGroup; 33 import android.view.accessibility.AccessibilityManager; 34 import android.widget.TextView; 35 36 import androidx.appcompat.app.AlertDialog; 37 38 import com.android.settings.core.InstrumentedFragment; 39 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 40 import com.android.settings.password.ChooseLockSettingsHelper; 41 42 import com.google.android.setupcompat.template.FooterBarMixin; 43 import com.google.android.setupcompat.template.FooterButton; 44 import com.google.android.setupdesign.GlifLayout; 45 46 import java.util.List; 47 48 public class EncryptionInterstitial extends SettingsActivity { 49 private static final String TAG = EncryptionInterstitial.class.getSimpleName(); 50 51 protected static final String EXTRA_PASSWORD_QUALITY = "extra_password_quality"; 52 protected static final String EXTRA_UNLOCK_METHOD_INTENT = "extra_unlock_method_intent"; 53 public static final String EXTRA_REQUIRE_PASSWORD = "extra_require_password"; 54 private static final int CHOOSE_LOCK_REQUEST = 100; 55 56 @Override getIntent()57 public Intent getIntent() { 58 Intent modIntent = new Intent(super.getIntent()); 59 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, EncryptionInterstitialFragment.class.getName()); 60 return modIntent; 61 } 62 63 @Override onApplyThemeResource(Resources.Theme theme, int resid, boolean first)64 protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) { 65 resid = SetupWizardUtils.getTheme(getIntent()); 66 super.onApplyThemeResource(theme, resid, first); 67 } 68 69 @Override isValidFragment(String fragmentName)70 protected boolean isValidFragment(String fragmentName) { 71 return EncryptionInterstitialFragment.class.getName().equals(fragmentName); 72 } 73 createStartIntent(Context ctx, int quality, boolean requirePasswordDefault, Intent unlockMethodIntent)74 public static Intent createStartIntent(Context ctx, int quality, 75 boolean requirePasswordDefault, Intent unlockMethodIntent) { 76 return new Intent(ctx, EncryptionInterstitial.class) 77 .putExtra(EXTRA_PASSWORD_QUALITY, quality) 78 .putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.encryption_interstitial_header) 79 .putExtra(EXTRA_REQUIRE_PASSWORD, requirePasswordDefault) 80 .putExtra(EXTRA_UNLOCK_METHOD_INTENT, unlockMethodIntent); 81 } 82 83 @Override onCreate(Bundle savedInstance)84 protected void onCreate(Bundle savedInstance) { 85 super.onCreate(savedInstance); 86 findViewById(R.id.content_parent).setFitsSystemWindows(false); 87 } 88 89 public static class EncryptionInterstitialFragment extends InstrumentedFragment { 90 91 private boolean mPasswordRequired; 92 private Intent mUnlockMethodIntent; 93 private int mRequestedPasswordQuality; 94 95 @Override getMetricsCategory()96 public int getMetricsCategory() { 97 return SettingsEnums.ENCRYPTION; 98 } 99 100 @Override onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)101 public View onCreateView( 102 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 103 return inflater.inflate(R.layout.encryption_interstitial, container, false); 104 } 105 106 @Override onViewCreated(View view, Bundle savedInstanceState)107 public void onViewCreated(View view, Bundle savedInstanceState) { 108 super.onViewCreated(view, savedInstanceState); 109 110 final boolean forFingerprint = getActivity().getIntent().getBooleanExtra( 111 ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); 112 final boolean forFace = getActivity().getIntent() 113 .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false); 114 Intent intent = getActivity().getIntent(); 115 mRequestedPasswordQuality = intent.getIntExtra(EXTRA_PASSWORD_QUALITY, 0); 116 mUnlockMethodIntent = intent.getParcelableExtra(EXTRA_UNLOCK_METHOD_INTENT); 117 final int msgId; 118 switch (mRequestedPasswordQuality) { 119 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 120 msgId = forFingerprint ? 121 R.string.encryption_interstitial_message_pattern_for_fingerprint : 122 forFace ? 123 R.string.encryption_interstitial_message_pattern_for_face : 124 R.string.encryption_interstitial_message_pattern; 125 break; 126 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 127 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: 128 msgId = forFingerprint ? 129 R.string.encryption_interstitial_message_pin_for_fingerprint : 130 forFace ? 131 R.string.encryption_interstitial_message_pin_for_face : 132 R.string.encryption_interstitial_message_pin; 133 break; 134 default: 135 msgId = forFingerprint ? 136 R.string.encryption_interstitial_message_password_for_fingerprint : 137 forFace ? 138 R.string.encryption_interstitial_message_password_for_face : 139 R.string.encryption_interstitial_message_password; 140 break; 141 } 142 TextView message = (TextView) getActivity().findViewById(R.id.sud_layout_description); 143 message.setText(msgId); 144 145 setRequirePasswordState(getActivity().getIntent().getBooleanExtra( 146 EXTRA_REQUIRE_PASSWORD, true)); 147 148 GlifLayout layout = (GlifLayout) view; 149 layout.setHeaderText(getActivity().getTitle()); 150 151 final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class); 152 mixin.setSecondaryButton( 153 new FooterButton.Builder(getContext()) 154 .setText(R.string.encryption_interstitial_no) 155 .setListener(this::onNoButtonClicked) 156 .setButtonType(FooterButton.ButtonType.SKIP) 157 .setTheme(R.style.SudGlifButton_Secondary) 158 .build() 159 ); 160 161 mixin.setPrimaryButton( 162 new FooterButton.Builder(getContext()) 163 .setText(R.string.encryption_interstitial_yes) 164 .setListener(this::onYesButtonClicked) 165 .setButtonType(FooterButton.ButtonType.NEXT) 166 .setTheme(R.style.SudGlifButton_Primary) 167 .build() 168 ); 169 } 170 startLockIntent()171 protected void startLockIntent() { 172 if (mUnlockMethodIntent != null) { 173 mUnlockMethodIntent.putExtra(EXTRA_REQUIRE_PASSWORD, mPasswordRequired); 174 startActivityForResult(mUnlockMethodIntent, CHOOSE_LOCK_REQUEST); 175 } else { 176 Log.wtf(TAG, "no unlock intent to start"); 177 finish(); 178 } 179 } 180 181 @Override onActivityResult(int requestCode, int resultCode, Intent data)182 public void onActivityResult(int requestCode, int resultCode, Intent data) { 183 super.onActivityResult(requestCode, resultCode, data); 184 if (requestCode == CHOOSE_LOCK_REQUEST && resultCode != RESULT_CANCELED) { 185 getActivity().setResult(resultCode, data); 186 finish(); 187 } 188 } 189 onYesButtonClicked(View view)190 private void onYesButtonClicked(View view) { 191 final boolean accEn = AccessibilityManager.getInstance(getActivity()).isEnabled(); 192 if (accEn && !mPasswordRequired) { 193 setRequirePasswordState(false); // clear the UI state 194 AccessibilityWarningDialogFragment.newInstance(mRequestedPasswordQuality) 195 .show( 196 getChildFragmentManager(), 197 AccessibilityWarningDialogFragment.TAG); 198 } else { 199 setRequirePasswordState(true); 200 startLockIntent(); 201 } 202 } 203 onNoButtonClicked(View view)204 private void onNoButtonClicked(View view) { 205 setRequirePasswordState(false); 206 startLockIntent(); 207 } 208 setRequirePasswordState(boolean required)209 private void setRequirePasswordState(boolean required) { 210 mPasswordRequired = required; 211 } 212 finish()213 public void finish() { 214 Activity activity = getActivity(); 215 if (activity == null) return; 216 if (getFragmentManager().getBackStackEntryCount() > 0) { 217 getFragmentManager().popBackStack(); 218 } else { 219 activity.finish(); 220 } 221 } 222 } 223 224 public static class AccessibilityWarningDialogFragment extends InstrumentedDialogFragment 225 implements DialogInterface.OnClickListener { 226 227 public static final String TAG = "AccessibilityWarningDialog"; 228 newInstance(int passwordQuality)229 public static AccessibilityWarningDialogFragment newInstance(int passwordQuality) { 230 AccessibilityWarningDialogFragment fragment = new AccessibilityWarningDialogFragment(); 231 Bundle args = new Bundle(1); 232 args.putInt(EXTRA_PASSWORD_QUALITY, passwordQuality); 233 fragment.setArguments(args); 234 return fragment; 235 } 236 237 @Override onCreateDialog(Bundle savedInstanceState)238 public Dialog onCreateDialog(Bundle savedInstanceState) { 239 final int titleId; 240 final int messageId; 241 switch (getArguments().getInt(EXTRA_PASSWORD_QUALITY)) { 242 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 243 titleId = R.string.encrypt_talkback_dialog_require_pattern; 244 messageId = R.string.encrypt_talkback_dialog_message_pattern; 245 break; 246 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 247 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: 248 titleId = R.string.encrypt_talkback_dialog_require_pin; 249 messageId = R.string.encrypt_talkback_dialog_message_pin; 250 break; 251 default: 252 titleId = R.string.encrypt_talkback_dialog_require_password; 253 messageId = R.string.encrypt_talkback_dialog_message_password; 254 break; 255 } 256 257 258 final Activity activity = getActivity(); 259 List<AccessibilityServiceInfo> list = 260 AccessibilityManager.getInstance(activity) 261 .getEnabledAccessibilityServiceList( 262 AccessibilityServiceInfo.FEEDBACK_ALL_MASK); 263 final CharSequence exampleAccessibility; 264 if (list.isEmpty()) { 265 // This should never happen. But we shouldn't crash 266 exampleAccessibility = ""; 267 } else { 268 exampleAccessibility = list.get(0).getResolveInfo() 269 .loadLabel(activity.getPackageManager()); 270 } 271 return new AlertDialog.Builder(activity) 272 .setTitle(titleId) 273 .setMessage(getString(messageId, exampleAccessibility)) 274 .setCancelable(true) 275 .setPositiveButton(android.R.string.ok, this) 276 .setNegativeButton(android.R.string.cancel, this) 277 .create(); 278 } 279 280 @Override getMetricsCategory()281 public int getMetricsCategory() { 282 return SettingsEnums.DIALOG_ENCRYPTION_INTERSTITIAL_ACCESSIBILITY; 283 } 284 285 @Override onClick(DialogInterface dialog, int which)286 public void onClick(DialogInterface dialog, int which) { 287 EncryptionInterstitialFragment fragment = 288 (EncryptionInterstitialFragment) getParentFragment(); 289 if (fragment != null) { 290 if (which == DialogInterface.BUTTON_POSITIVE) { 291 fragment.setRequirePasswordState(true); 292 fragment.startLockIntent(); 293 } else if (which == DialogInterface.BUTTON_NEGATIVE) { 294 fragment.setRequirePasswordState(false); 295 } 296 } 297 } 298 } 299 } 300