Files
app_Settings/src/com/android/settings/CredentialStorage.java
Brian Carlstrom 435e45e616 Move to KeyChain.bind
Change-Id: Ic12e84bdc2e391c4a08a0f854d0e0f7315fc31a3
2011-05-17 16:22:06 -07:00

278 lines
10 KiB
Java

/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
import android.security.IKeyChainService;
import android.security.KeyStore;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.io.UnsupportedEncodingException;
public class CredentialStorage extends Activity implements TextWatcher,
DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
public static final String ACTION_UNLOCK = "com.android.credentials.UNLOCK";
public static final String ACTION_SET_PASSWORD = "com.android.credentials.SET_PASSWORD";
public static final String ACTION_INSTALL = "com.android.credentials.INSTALL";
public static final String ACTION_RESET = "com.android.credentials.RESET";
private static final String TAG = "CredentialStorage";
private KeyStore mKeyStore = KeyStore.getInstance();
private boolean mPositive = false;
private boolean mNeutral = false;
private Bundle mBundle;
private TextView mOldPassword;
private TextView mNewPassword;
private TextView mConfirmPassword;
private TextView mError;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String action = intent.getAction();
int state = mKeyStore.test();
if (ACTION_RESET.equals(action)) {
showResetDialog();
} else if (ACTION_SET_PASSWORD.equals(action)) {
showPasswordDialog(state == KeyStore.UNINITIALIZED);
} else {
if (ACTION_INSTALL.equals(action) &&
"com.android.certinstaller".equals(getCallingPackage())) {
mBundle = intent.getExtras();
}
if (state == KeyStore.UNINITIALIZED) {
showPasswordDialog(true);
} else if (state == KeyStore.LOCKED) {
showUnlockDialog();
} else {
install();
finish();
}
}
}
private void install() {
if (mBundle != null && !mBundle.isEmpty()) {
try {
for (String key : mBundle.keySet()) {
byte[] value = mBundle.getByteArray(key);
if (value != null && !mKeyStore.put(key.getBytes("UTF-8"), value)) {
Log.e(TAG, "Failed to install " + key);
return;
}
}
setResult(RESULT_OK);
} catch (UnsupportedEncodingException e) {
// Should never happen.
throw new RuntimeException(e);
}
}
}
private void showResetDialog() {
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(android.R.string.dialog_alert_title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.credentials_reset_hint)
.setNeutralButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, this)
.create();
dialog.setOnDismissListener(this);
dialog.show();
}
private void showPasswordDialog(boolean firstTime) {
View view = View.inflate(this, R.layout.credentials_dialog, null);
((TextView) view.findViewById(R.id.hint)).setText(R.string.credentials_password_hint);
if (!firstTime) {
view.findViewById(R.id.old_password_prompt).setVisibility(View.VISIBLE);
mOldPassword = (TextView) view.findViewById(R.id.old_password);
mOldPassword.setVisibility(View.VISIBLE);
mOldPassword.addTextChangedListener(this);
}
view.findViewById(R.id.new_passwords).setVisibility(View.VISIBLE);
mNewPassword = (TextView) view.findViewById(R.id.new_password);
mNewPassword.addTextChangedListener(this);
mConfirmPassword = (TextView) view.findViewById(R.id.confirm_password);
mConfirmPassword.addTextChangedListener(this);
mError = (TextView) view.findViewById(R.id.error);
AlertDialog dialog = new AlertDialog.Builder(this)
.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();
mButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
mButton.setEnabled(false);
}
private void showUnlockDialog() {
View view = View.inflate(this, R.layout.credentials_dialog, null);
((TextView) view.findViewById(R.id.hint)).setText(R.string.credentials_unlock_hint);
mOldPassword = (TextView) view.findViewById(R.id.old_password);
mOldPassword.setVisibility(View.VISIBLE);
mOldPassword.addTextChangedListener(this);
mError = (TextView) view.findViewById(R.id.error);
AlertDialog dialog = new AlertDialog.Builder(this)
.setView(view)
.setTitle(R.string.credentials_unlock)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, this)
.create();
dialog.setOnDismissListener(this);
dialog.show();
mButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
mButton.setEnabled(false);
}
public void afterTextChanged(Editable editable) {
if ((mOldPassword == null || mOldPassword.getText().length() > 0) &&
(mNewPassword == null || mNewPassword.getText().length() >= 8) &&
(mConfirmPassword == null || mConfirmPassword.getText().length() >= 8)) {
mButton.setEnabled(true);
} else {
mButton.setEnabled(false);
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s,int start, int before, int count) {
}
public void onClick(DialogInterface dialog, int button) {
mPositive = (button == DialogInterface.BUTTON_POSITIVE);
mNeutral = (button == DialogInterface.BUTTON_NEUTRAL);
}
public void onDismiss(DialogInterface dialog) {
if (mPositive) {
mPositive = false;
mError.setVisibility(View.VISIBLE);
if (mNewPassword == null) {
mKeyStore.unlock(mOldPassword.getText().toString());
} else {
String newPassword = mNewPassword.getText().toString();
String confirmPassword = mConfirmPassword.getText().toString();
if (!newPassword.equals(confirmPassword)) {
mError.setText(R.string.credentials_passwords_mismatch);
((AlertDialog) dialog).show();
return;
} else if (mOldPassword == null) {
mKeyStore.password(newPassword);
} else {
mKeyStore.password(mOldPassword.getText().toString(), newPassword);
}
}
int error = mKeyStore.getLastError();
if (error == KeyStore.NO_ERROR) {
Toast.makeText(this, R.string.credentials_enabled, Toast.LENGTH_SHORT).show();
install();
} else if (error == KeyStore.UNINITIALIZED) {
Toast.makeText(this, R.string.credentials_erased, Toast.LENGTH_SHORT).show();
} else if (error >= KeyStore.WRONG_PASSWORD) {
int count = error - KeyStore.WRONG_PASSWORD + 1;
if (count > 3) {
mError.setText(R.string.credentials_wrong_password);
} else if (count == 1) {
mError.setText(R.string.credentials_reset_warning);
} else {
mError.setText(getString(R.string.credentials_reset_warning_plural, count));
}
((AlertDialog) dialog).show();
return;
}
}
if (mNeutral) {
mNeutral = false;
new ResetKeyStoreAndKeyChain().execute();
return;
}
finish();
}
private class ResetKeyStoreAndKeyChain extends AsyncTask<Void, Void, Boolean> {
@Override protected Boolean doInBackground(Void... unused) {
mKeyStore.reset();
try {
KeyChainConnection keyChainConnection = KeyChain.bind(CredentialStorage.this);
try {
return keyChainConnection.getService().reset();
} catch (RemoteException e) {
return false;
} finally {
keyChainConnection.close();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
@Override protected void onPostExecute(Boolean success) {
if (success) {
Toast.makeText(CredentialStorage.this,
R.string.credentials_erased, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(CredentialStorage.this,
R.string.credentials_not_erased, Toast.LENGTH_SHORT).show();
}
finish();
}
}
}