Merge "New Settings assets" into honeycomb
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c7fbfa4..f822ff6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1080,6 +1080,21 @@
</intent-filter>
</activity>
+ <!-- Pseudo-activity used to provide an intent-filter entry point to encryption settings -->
+ <activity android:name="Settings$CryptKeeperSettingsActivity"
+ android:theme="@android:style/Theme.Holo"
+ android:label="@string/crypt_keeper_encrypt_title">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.app.action.START_ENCRYPTION" />
+ <category android:name="android.intent.category.DEFAULT" /> />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.CryptKeeperSettings" />
+ <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
+ android:resource="@id/security_settings" />
+ </activity>
+
<receiver android:name=".widget.SettingsAppWidgetProvider"
android:label="@string/gadget_title"
android:exported="false"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 472b391..9724e60 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -587,12 +587,12 @@
<string name="crypt_keeper_encrypt_summary">Requires you to set a device unlock pin or password</string>
<string name="crypt_keeper_confirm_title">Confirm encrypt</string>
- <string name="crypt_keeper_desc">Device encryption will convert user data to an ecrypted state, including your accounts, system data, downloaded applications and data, photos, movies, musics, etc.\n\nEncyrption cannot be undone without performing a factory data reset, which would then erase all data.\n\nYou must set up a device lock pin or password to proceed.\n\nThis operation may take up to an hour and may not be interrupted. You must have a fully charged battery and plug in the device to initiate encryption. Running out of power during encryption will cause data loss.</string>
+ <string name="crypt_keeper_desc">You can encrypt your accounts, settings, downloaded applications and their data, media, and other files. Once you encrypt your tablet, you can\'t unencrypt it except by performing a factory data reset, erasing all the data on your tablet.\n\nEncryption takes up to an hour. You must start with a charged battery and keep your tablet plugged in until encryption is complete. If you interrupt the encryption process, you will lose some or all of your data.</string>
<string name="crypt_keeper_button_text" product="tablet">Encrypt tablet</string>
<string name="crypt_keeper_button_text" product="default">Encrypt phone</string>
- <string name="crypt_keeper_final_desc">Encrypt user data? This operation is not reversible and may not be interrupted without loos of data! Encryption may take up to an hour.</string>
+ <string name="crypt_keeper_final_desc">Encrypt user data? This operation is not reversible and may not be interrupted without loss of data! Encryption may take up to an hour.</string>
<string name="crypt_keeper_setup_title">Encrypting</string>
@@ -3054,7 +3054,7 @@
<!-- Message shown when users select EAP in WiFi settings for SetupWizard,
saying EAP can't be configured in SetupWizard flow.
[CHAR LIMIT=NONE] -->
- <string name="wifi_setup_eap_not_supported">You can\u0027t configure an EAP Wi-Fi connection during setup. After setup, you can do that in Settings, under Wireless & Networks.</string>
+ <string name="wifi_setup_eap_not_supported">You can\u0027t configure an EAP Wi-Fi connection during setup. After setup, you can do that in Settings, under <b>Wireless & networks</b>.</string>
<!-- Message shown when the device is connecting a network [CHAR LIMIT=NONE] -->
<string name="wifi_setup_description_connecting">Connecting can take a few minutes...</string>
<!-- Message shown when the device is connected to a network [CHAR LIMIT=NONE] -->
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 88b344e..3917b76 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -30,6 +30,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.os.PowerManager;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.storage.IMountService;
@@ -46,7 +47,7 @@
public class CryptKeeper extends Activity implements TextView.OnEditorActionListener {
private static final String TAG = "CryptKeeper";
-
+
private static final String DECRYPT_STATE = "trigger_restart_framework";
private static final int UPDATE_PROGRESS = 1;
@@ -60,40 +61,40 @@
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
-
+
switch (msg.what) {
-
+
case UPDATE_PROGRESS:
String state = SystemProperties.get("vold.encrypt_progress");
-
+
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
progressBar.setProgress(0);
-
+
try {
int progress = Integer.parseInt(state);
progressBar.setProgress(progress);
} catch (Exception e) {
Log.w(TAG, "Error parsing progress: " + e.toString());
}
-
- // Check the status every 1 second
- sendEmptyMessageDelayed(0, 1000);
+
+ // Check the status every 5 second
+ sendEmptyMessageDelayed(UPDATE_PROGRESS, 5000);
break;
-
+
case COOLDOWN:
TextView tv = (TextView) findViewById(R.id.status);
if (mCooldown <= 0) {
// Re-enable the password entry
EditText passwordEntry = (EditText) findViewById(R.id.passwordEntry);
passwordEntry.setEnabled(true);
-
+
tv.setText(R.string.try_again);
-
+
} else {
-
+
CharSequence tempalte = getText(R.string.crypt_keeper_cooldown);
tv.setText(TextUtils.expandTemplate(tempalte, Integer.toString(mCooldown)));
-
+
mCooldown--;
mHandler.sendEmptyMessageDelayed(COOLDOWN, 1000); // Tick every second
}
@@ -101,44 +102,60 @@
}
}
};
-
+
private int mFailedAttempts = 0;
private int mCooldown;
-
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
+
String state = SystemProperties.get("vold.decrypt");
if ("".equals(state) || DECRYPT_STATE.equals(state)) {
- // Disable the crypt keeper.
+ // Disable the crypt keeper.
PackageManager pm = getPackageManager();
ComponentName name = new ComponentName(this, CryptKeeper.class);
pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
return;
}
-
+
// Check to see why we were started.
String progress = SystemProperties.get("vold.encrypt_progress");
- if ("startup".equals(progress)) {
+
+ if (!"".equals(progress)) {
setContentView(R.layout.crypt_keeper_progress);
encryptionProgressInit();
} else {
setContentView(R.layout.crypt_keeper_password_entry);
passwordEntryInit();
}
+
+ // Disable the status bar
+ StatusBarManager sbm = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
+ sbm.disable(StatusBarManager.DISABLE_EXPAND | StatusBarManager.DISABLE_NOTIFICATION_ICONS
+ | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+ | StatusBarManager.DISABLE_SYSTEM_INFO | StatusBarManager.DISABLE_NAVIGATION);
}
-
+
private void encryptionProgressInit() {
+ // Accquire a partial wakelock to prevent the device from sleeping. Note
+ // we never release this wakelock as we will be restarted after the device
+ // is encrypted.
+
+ PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+ wakeLock.acquire();
+
mHandler.sendEmptyMessage(UPDATE_PROGRESS);
}
-
+
private void passwordEntryInit() {
TextView passwordEntry = (TextView) findViewById(R.id.passwordEntry);
passwordEntry.setOnEditorActionListener(this);
-
+
KeyboardView keyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
-
+
PasswordEntryKeyboardHelper keyboardHelper = new PasswordEntryKeyboardHelper(this,
keyboardView, passwordEntry, false);
keyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
@@ -150,12 +167,6 @@
String dateFormatString = getString(com.android.internal.R.string.full_wday_month_day_no_year);
TextView date = (TextView) findViewById(R.id.date);
date.setText(DateFormat.format(dateFormatString, new Date()));
-
- // Disable the status bar
- StatusBarManager sbm = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
- sbm.disable(StatusBarManager.DISABLE_EXPAND | StatusBarManager.DISABLE_NOTIFICATION_ICONS
- | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
- | StatusBarManager.DISABLE_SYSTEM_INFO | StatusBarManager.DISABLE_NAVIGATION);
}
private IMountService getMountService() {
@@ -175,7 +186,7 @@
if (TextUtils.isEmpty(password)) {
return true;
}
-
+
// Now that we have the password clear the password field.
v.setText(null);
@@ -183,12 +194,10 @@
try {
service.decryptStorage(password);
- // For now the only way to get here is for the password to be
- // wrong.
+ if (mFailedAttempts == 0) {
+ // Success. Do something here within 2 seconds
- mFailedAttempts++;
-
- if (mFailedAttempts == MAX_FAILED_ATTEMPTS) {
+ } else if (mFailedAttempts == MAX_FAILED_ATTEMPTS) {
// Factory reset the device.
sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
} else if ((mFailedAttempts % COOL_DOWN_ATTEMPTS) == 0) {
@@ -203,7 +212,7 @@
} catch (Exception e) {
Log.e(TAG, "Error while decrypting...", e);
}
-
+
return true;
}
return false;
diff --git a/src/com/android/settings/CryptKeeperSettings.java b/src/com/android/settings/CryptKeeperSettings.java
index 8b60ca7..d26e5ff 100644
--- a/src/com/android/settings/CryptKeeperSettings.java
+++ b/src/com/android/settings/CryptKeeperSettings.java
@@ -17,9 +17,15 @@
package com.android.settings;
import android.app.Activity;
+import android.app.AlertDialog;
import android.app.Fragment;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Resources;
+import android.os.BatteryManager;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
@@ -45,6 +51,93 @@
private View mContentView;
private Button mInitiateButton;
+ private IntentFilter mIntentFilter;
+
+ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+ int level = intent.getIntExtra("level", 0);
+ int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);
+
+ if (status == BatteryManager.BATTERY_STATUS_CHARGING && level >= 80) {
+ mInitiateButton.setEnabled(true);
+ } else {
+ mInitiateButton.setEnabled(false);
+ }
+ }
+ }
+ };
+
+ /**
+ * If the user clicks to begin the reset sequence, we next require a
+ * keyguard confirmation if the user has currently enabled one. If there
+ * is no keyguard available, we prompt the user to set a password.
+ */
+ private Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
+
+ public void onClick(View v) {
+ if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
+ // TODO remove with proper flow
+ new AlertDialog.Builder(getActivity())
+ .setTitle("No password set")
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage("Before you enable encryption you must set a device password.")
+ .setPositiveButton(android.R.string.ok, null)
+ .create()
+ .show();
+ }
+ }
+ };
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ mContentView = inflater.inflate(R.layout.crypt_keeper_settings, null);
+
+ mIntentFilter = new IntentFilter();
+ mIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
+
+ mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_encrypt);
+ mInitiateButton.setOnClickListener(mInitiateListener);
+ mInitiateButton.setEnabled(false);
+
+ return mContentView;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ getActivity().registerReceiver(mIntentReceiver, mIntentFilter);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ getActivity().unregisterReceiver(mIntentReceiver);
+ }
+
+ /**
+ * If encryption is already started, and this launched via a "start encryption" intent,
+ * then exit immediately - it's already up and running, so there's no point in "starting" it.
+ */
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ Activity activity = getActivity();
+ Intent intent = activity.getIntent();
+ if (DevicePolicyManager.ACTION_START_ENCRYPTION.equals(intent.getAction())) {
+ DevicePolicyManager dpm = (DevicePolicyManager)
+ activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (dpm != null) {
+ int status = dpm.getStorageEncryptionStatus();
+ if (status != DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE) {
+ // There is nothing to do here, so simply finish() (which returns to caller)
+ activity.finish();
+ }
+ }
+ }
+ }
/**
* Keyguard validation is run using the standard {@link ConfirmLockPattern}
@@ -67,14 +160,12 @@
if (requestCode != KEYGUARD_REQUEST) {
return;
}
-
+
// If the user entered a valid keyguard trace, present the final
// confirmation prompt; otherwise, go back to the initial state.
if (resultCode == Activity.RESULT_OK) {
String password = data.getStringExtra("password");
showFinalConfirmation(password);
- } else {
- establishInitialState();
}
}
@@ -85,45 +176,5 @@
preference.getExtras().putString("password", password);
((PreferenceActivity) getActivity()).onPreferenceStartFragment(null, preference);
}
-
- /**
- * If the user clicks to begin the reset sequence, we next require a
- * keyguard confirmation if the user has currently enabled one. If there
- * is no keyguard available, we simply go to the final confirmation prompt.
- */
- private Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
-
- public void onClick(View v) {
- if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
- // TODO: Need to request a password
- // showFinalConfirmation();
- }
- }
- };
-
- /**
- * In its initial state, the activity presents a button for the user to
- * click in order to initiate a confirmation sequence. This method is
- * called from various other points in the code to reset the activity to
- * this base state.
- *
- * <p>Reinflating views from resources is expensive and prevents us from
- * caching widget pointers, so we use a single-inflate pattern: we lazy-
- * inflate each view, caching all of the widget pointers we'll need at the
- * time, then simply reuse the inflated views directly whenever we need
- * to change contents.
- */
- private void establishInitialState() {
- mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_encrypt);
- mInitiateButton.setOnClickListener(mInitiateListener);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
- mContentView = inflater.inflate(R.layout.crypt_keeper_settings, null);
-
- establishInitialState();
- return mContentView;
- }
}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 5bb169e..aaaf265 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -21,38 +21,25 @@
import com.android.internal.widget.LockPatternUtils;
-import android.app.AlertDialog;
-import android.app.Dialog;
import android.app.admin.DevicePolicyManager;
import android.content.ContentQueryMap;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.location.LocationManager;
import android.os.Bundle;
-import android.os.IBinder;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.Vibrator;
-import android.os.storage.IMountService;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.PreferenceCategory;
import android.preference.PreferenceGroup;
-import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.provider.Settings;
-import android.security.Credentials;
import android.security.KeyStore;
import android.telephony.TelephonyManager;
import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
-import android.widget.Toast;
import java.util.ArrayList;
import java.util.Observable;
@@ -410,90 +397,6 @@
createPreferenceHierarchy();
}
- private class Encryption implements DialogInterface.OnClickListener,
- DialogInterface.OnDismissListener {
-
- private boolean mSubmit;
-
- public void showPasswordDialog() {
- View view = View.inflate(SecuritySettings.this.getActivity(),
- R.layout.credentials_dialog, null);
- view.findViewById(R.id.new_passwords).setVisibility(View.VISIBLE);
-
- Dialog dialog = new AlertDialog.Builder(SecuritySettings.this.getActivity())
- .setView(view).setTitle(R.string.credentials_set_password)
- .setPositiveButton(android.R.string.ok, this)
- .setNegativeButton(android.R.string.cancel, this).create();
- dialog.setOnDismissListener(this);
- dialog.show();
- }
-
- public void onClick(DialogInterface dialog, int button) {
- if (button == DialogInterface.BUTTON_POSITIVE) {
- mSubmit = true;
- }
- }
-
- public void onDismiss(DialogInterface dialog) {
- if (mSubmit) {
- mSubmit = false;
- if (!checkPassword((Dialog) dialog)) {
- ((Dialog) dialog).show();
- return;
- }
- }
- }
-
- // Return true if there is no error.
- private boolean checkPassword(Dialog dialog) {
- String newPassword = getText(dialog, R.id.new_password);
- String confirmPassword = getText(dialog, R.id.confirm_password);
-
- if (newPassword == null || confirmPassword == null || newPassword.length() == 0
- || confirmPassword.length() == 0) {
- showError(dialog, R.string.credentials_passwords_empty);
- } else if (!newPassword.equals(confirmPassword)) {
- showError(dialog, R.string.credentials_passwords_mismatch);
- } else {
-
- IBinder service = ServiceManager.getService("mount");
- if (service == null) {
- return false;
- }
-
- IMountService mountService = IMountService.Stub.asInterface(service);
- try {
- mountService.encryptStorage(newPassword);
- } catch (Exception e) {
- Log.e(TAG, "Error while encrypting...", e);
- }
-
- return true;
- }
-
- return false;
- }
-
- private String getText(Dialog dialog, int viewId) {
- TextView view = (TextView) dialog.findViewById(viewId);
- return (view == null || view.getVisibility() == View.GONE) ? null : view.getText()
- .toString();
- }
-
- private void showError(Dialog dialog, int stringId, Object... formatArgs) {
- TextView view = (TextView) dialog.findViewById(R.id.error);
- if (view != null) {
- if (formatArgs == null || formatArgs.length == 0) {
- view.setText(stringId);
- } else {
- view.setText(getString(stringId, formatArgs));
- }
- view.setVisibility(View.VISIBLE);
- }
- }
-
- }
-
public boolean onPreferenceChange(Preference preference, Object value) {
if (preference == mLockAfter) {
int timeout = Integer.parseInt((String) value);
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 11d8c57..1e54504 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -332,4 +332,5 @@
public static class PowerUsageSummaryActivity extends Settings { }
public static class AccountSyncSettingsActivity extends Settings { }
public static class AccountSyncSettingsInAddAccountActivity extends Settings { }
+ public static class CryptKeeperSettingsActivity extends Settings { }
}