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.AlertDialog; 21 import android.app.Dialog; 22 import android.app.admin.DevicePolicyManager; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.Intent; 26 import android.content.res.Resources; 27 import android.os.Bundle; 28 import android.support.v7.preference.Preference; 29 import android.support.v7.widget.RecyclerView; 30 import android.util.Log; 31 import android.view.LayoutInflater; 32 import android.view.View; 33 import android.view.ViewGroup; 34 import android.view.accessibility.AccessibilityManager; 35 import android.widget.LinearLayout; 36 import android.widget.TextView; 37 38 import com.android.internal.logging.MetricsProto.MetricsEvent; 39 import com.android.settings.utils.SettingsDividerItemDecoration; 40 import com.android.setupwizardlib.GlifPreferenceLayout; 41 42 import java.util.List; 43 44 public class EncryptionInterstitial extends SettingsActivity { 45 private static final String TAG = EncryptionInterstitial.class.getSimpleName(); 46 47 protected static final String EXTRA_PASSWORD_QUALITY = "extra_password_quality"; 48 protected static final String EXTRA_UNLOCK_METHOD_INTENT = "extra_unlock_method_intent"; 49 public static final String EXTRA_REQUIRE_PASSWORD = "extra_require_password"; 50 private static final int CHOOSE_LOCK_REQUEST = 100; 51 52 @Override 53 public Intent getIntent() { 54 Intent modIntent = new Intent(super.getIntent()); 55 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, EncryptionInterstitialFragment.class.getName()); 56 return modIntent; 57 } 58 59 @Override 60 protected boolean isValidFragment(String fragmentName) { 61 return EncryptionInterstitialFragment.class.getName().equals(fragmentName); 62 } 63 64 public static Intent createStartIntent(Context ctx, int quality, 65 boolean requirePasswordDefault, Intent unlockMethodIntent) { 66 return new Intent(ctx, EncryptionInterstitial.class) 67 .putExtra(EXTRA_PASSWORD_QUALITY, quality) 68 .putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.encryption_interstitial_header) 69 .putExtra(EXTRA_REQUIRE_PASSWORD, requirePasswordDefault) 70 .putExtra(EXTRA_UNLOCK_METHOD_INTENT, unlockMethodIntent); 71 } 72 73 @Override 74 protected void onCreate(Bundle savedInstance) { 75 super.onCreate(savedInstance); 76 LinearLayout layout = (LinearLayout) findViewById(R.id.content_parent); 77 layout.setFitsSystemWindows(false); 78 } 79 80 public static class EncryptionInterstitialFragment extends SettingsPreferenceFragment 81 implements DialogInterface.OnClickListener { 82 83 private static final int ACCESSIBILITY_WARNING_DIALOG = 1; 84 private static final String KEY_ENCRYPT_REQUIRE_PASSWORD = "encrypt_require_password"; 85 private static final String KEY_ENCRYPT_DONT_REQUIRE_PASSWORD = 86 "encrypt_dont_require_password"; 87 88 private Preference mRequirePasswordToDecrypt; 89 private Preference mDontRequirePasswordToDecrypt; 90 private boolean mPasswordRequired; 91 private Intent mUnlockMethodIntent; 92 private int mRequestedPasswordQuality; 93 94 @Override 95 protected int getMetricsCategory() { 96 return MetricsEvent.ENCRYPTION; 97 } 98 99 @Override 100 public void onCreate(Bundle savedInstanceState) { 101 super.onCreate(savedInstanceState); 102 103 addPreferencesFromResource(R.xml.security_settings_encryption_interstitial); 104 105 // Used for testing purposes 106 findPreference(KEY_ENCRYPT_DONT_REQUIRE_PASSWORD) 107 .setViewId(R.id.encrypt_dont_require_password); 108 109 mRequirePasswordToDecrypt = findPreference(KEY_ENCRYPT_REQUIRE_PASSWORD); 110 mDontRequirePasswordToDecrypt = findPreference(KEY_ENCRYPT_DONT_REQUIRE_PASSWORD); 111 boolean forFingerprint = getActivity().getIntent().getBooleanExtra( 112 ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); 113 Intent intent = getActivity().getIntent(); 114 mRequestedPasswordQuality = intent.getIntExtra(EXTRA_PASSWORD_QUALITY, 0); 115 mUnlockMethodIntent = intent.getParcelableExtra(EXTRA_UNLOCK_METHOD_INTENT); 116 final int msgId; 117 final int enableId; 118 final int disableId; 119 switch (mRequestedPasswordQuality) { 120 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 121 msgId = forFingerprint ? 122 R.string.encryption_interstitial_message_pattern_for_fingerprint : 123 R.string.encryption_interstitial_message_pattern; 124 enableId = R.string.encrypt_require_pattern; 125 disableId = R.string.encrypt_dont_require_pattern; 126 break; 127 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 128 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: 129 msgId = forFingerprint ? 130 R.string.encryption_interstitial_message_pin_for_fingerprint : 131 R.string.encryption_interstitial_message_pin; 132 enableId = R.string.encrypt_require_pin; 133 disableId = R.string.encrypt_dont_require_pin; 134 break; 135 default: 136 msgId = forFingerprint ? 137 R.string.encryption_interstitial_message_password_for_fingerprint : 138 R.string.encryption_interstitial_message_password; 139 enableId = R.string.encrypt_require_password; 140 disableId = R.string.encrypt_dont_require_password; 141 break; 142 } 143 TextView message = (TextView) LayoutInflater.from(getActivity()).inflate( 144 R.layout.encryption_interstitial_header, null, false); 145 message.setText(msgId); 146 setHeaderView(message); 147 148 mRequirePasswordToDecrypt.setTitle(enableId); 149 150 mDontRequirePasswordToDecrypt.setTitle(disableId); 151 152 setRequirePasswordState(getActivity().getIntent().getBooleanExtra( 153 EXTRA_REQUIRE_PASSWORD, true)); 154 } 155 156 @Override 157 public void onViewCreated(View view, Bundle savedInstanceState) { 158 super.onViewCreated(view, savedInstanceState); 159 GlifPreferenceLayout layout = (GlifPreferenceLayout) view; 160 layout.setDividerItemDecoration(new SettingsDividerItemDecoration(getContext())); 161 162 layout.setIcon(getContext().getDrawable(R.drawable.ic_lock)); 163 layout.setHeaderText(getActivity().getTitle()); 164 165 // Use the dividers in SetupWizardRecyclerLayout. Suppress the dividers in 166 // PreferenceFragment. 167 setDivider(null); 168 } 169 170 @Override 171 public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, 172 Bundle savedInstanceState) { 173 GlifPreferenceLayout layout = (GlifPreferenceLayout) parent; 174 return layout.onCreateRecyclerView(inflater, parent, savedInstanceState); 175 } 176 177 protected void startLockIntent() { 178 if (mUnlockMethodIntent != null) { 179 mUnlockMethodIntent.putExtra(EXTRA_REQUIRE_PASSWORD, mPasswordRequired); 180 startActivityForResult(mUnlockMethodIntent, CHOOSE_LOCK_REQUEST); 181 } else { 182 Log.wtf(TAG, "no unlock intent to start"); 183 finish(); 184 } 185 } 186 187 @Override 188 public void onActivityResult(int requestCode, int resultCode, Intent data) { 189 super.onActivityResult(requestCode, resultCode, data); 190 if (requestCode == CHOOSE_LOCK_REQUEST && resultCode != RESULT_CANCELED) { 191 getActivity().setResult(resultCode, data); 192 finish(); 193 } 194 } 195 196 @Override 197 public boolean onPreferenceTreeClick(Preference preference) { 198 final String key = preference.getKey(); 199 if (key.equals(KEY_ENCRYPT_REQUIRE_PASSWORD)) { 200 final boolean accEn = AccessibilityManager.getInstance(getActivity()).isEnabled(); 201 if (accEn && !mPasswordRequired) { 202 setRequirePasswordState(false); // clear the UI state 203 showDialog(ACCESSIBILITY_WARNING_DIALOG); 204 } else { 205 setRequirePasswordState(true); 206 startLockIntent(); 207 } 208 } else { 209 setRequirePasswordState(false); 210 startLockIntent(); 211 } 212 return true; 213 } 214 215 @Override 216 public Dialog onCreateDialog(int dialogId) { 217 switch(dialogId) { 218 case ACCESSIBILITY_WARNING_DIALOG: { 219 final int titleId; 220 final int messageId; 221 switch (mRequestedPasswordQuality) { 222 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 223 titleId = R.string.encrypt_talkback_dialog_require_pattern; 224 messageId = R.string.encrypt_talkback_dialog_message_pattern; 225 break; 226 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 227 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: 228 titleId = R.string.encrypt_talkback_dialog_require_pin; 229 messageId = R.string.encrypt_talkback_dialog_message_pin; 230 break; 231 default: 232 titleId = R.string.encrypt_talkback_dialog_require_password; 233 messageId = R.string.encrypt_talkback_dialog_message_password; 234 break; 235 } 236 237 238 List<AccessibilityServiceInfo> list = 239 AccessibilityManager.getInstance(getActivity()) 240 .getEnabledAccessibilityServiceList( 241 AccessibilityServiceInfo.FEEDBACK_ALL_MASK); 242 final CharSequence exampleAccessibility; 243 if (list.isEmpty()) { 244 // This should never happen. But we shouldn't crash 245 exampleAccessibility = ""; 246 } else { 247 exampleAccessibility = list.get(0).getResolveInfo() 248 .loadLabel(getPackageManager()); 249 } 250 return new AlertDialog.Builder(getActivity()) 251 .setTitle(titleId) 252 .setMessage(getString(messageId, exampleAccessibility)) 253 .setCancelable(true) 254 .setPositiveButton(android.R.string.ok, this) 255 .setNegativeButton(android.R.string.cancel, this) 256 .create(); 257 } 258 default: throw new IllegalArgumentException(); 259 } 260 } 261 262 private void setRequirePasswordState(boolean required) { 263 mPasswordRequired = required; 264 } 265 266 @Override 267 public void onClick(DialogInterface dialog, int which) { 268 if (which == DialogInterface.BUTTON_POSITIVE) { 269 setRequirePasswordState(true); 270 startLockIntent(); 271 } else if (which == DialogInterface.BUTTON_NEGATIVE) { 272 setRequirePasswordState(false); 273 } 274 } 275 } 276 } 277