Introduce a cert selector in exchange settings UI.
This simply allows the user to select a certificate from the KeyChain to use for credentials. Text and UI not finalized. Change-Id: Ib86abc3c2e899640218122caa12308dc9646dab6
This commit is contained in:
parent
22409fcffa
commit
7014f7d329
@ -87,12 +87,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:background="@color/account_setup_divider_color" />
|
||||
</LinearLayout>
|
||||
<!-- Note, this row is not a TableRow, and it will span the entire table - no columns -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
<CheckBox
|
||||
android:id="@+id/account_trust_certificates"
|
||||
android:layout_marginTop="16dip"
|
||||
@ -108,6 +102,16 @@
|
||||
android:layout_height="1px"
|
||||
android:background="@color/account_setup_divider_color"
|
||||
android:visibility="gone" />
|
||||
<include
|
||||
android:id="@+id/client_certificate_selector"
|
||||
layout="@layout/client_certificate_selector"
|
||||
android:visibility="gone" />
|
||||
<View
|
||||
android:id="@+id/client_certificate_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:background="@color/account_setup_divider_color"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
<TableRow
|
||||
android:paddingTop="32dip" >
|
||||
|
@ -69,6 +69,10 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:text="@string/account_setup_exchange_trust_certificates_label" />
|
||||
<include
|
||||
android:id="@+id/client_certificate_selector"
|
||||
layout="@layout/client_certificate_selector"
|
||||
android:visibility="gone" />
|
||||
<TextView
|
||||
android:text="@string/account_setup_exchange_device_id_label"
|
||||
android:layout_height="wrap_content"
|
||||
|
41
res/layout/client_certificate_selector.xml
Normal file
41
res/layout/client_certificate_selector.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<!-- A layout to select a certificate, akin to a file selector on web pages. -->
|
||||
<!-- Extends LinearLayout -->
|
||||
<com.android.email.view.CertificateSelector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dip"
|
||||
android:layout_marginBottom="8dip"
|
||||
android:layout_marginLeft="32dip"
|
||||
android:layout_marginRight="32dip"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/certificate_alias"
|
||||
android:layout_width="0dip"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone" />
|
||||
<Button
|
||||
android:id="@+id/select_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/account_setup_exchange_use_certificate" />
|
||||
|
||||
</com.android.email.view.CertificateSelector>
|
@ -688,6 +688,10 @@ save attachment.</string>
|
||||
<string name="account_setup_exchange_ssl_label">Use secure connection (SSL)</string>
|
||||
<!-- On "Exchange" setup screen, the trust ssl certificates checkbox label -->
|
||||
<string name="account_setup_exchange_trust_certificates_label">Accept all SSL certificates</string>
|
||||
<!-- On "Exchange" setup screen, a button label to include a client certificate [CHAR LIMIT=35] -->
|
||||
<string name="account_setup_exchange_use_certificate">Use client certificate</string>
|
||||
<!-- On "Exchange" setup screen, a button label to remove the currently used client certificate [CHAR LIMIT=35] -->
|
||||
<string name="account_setup_exchange_remove_certificate">Remove</string>
|
||||
<!-- On "Exchange" setup screen, the exchange device-id label [CHAR LIMIT=30] -->
|
||||
<string name="account_setup_exchange_device_id_label">Mobile Device ID</string>
|
||||
|
||||
|
@ -22,6 +22,7 @@ import com.android.email.R;
|
||||
import com.android.email.activity.UiUtilities;
|
||||
import com.android.email.mail.Store;
|
||||
import com.android.email.provider.AccountBackupRestore;
|
||||
import com.android.email.view.CertificateSelector;
|
||||
import com.android.emailcommon.Device;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
@ -63,6 +64,7 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment
|
||||
private EditText mServerView;
|
||||
private CheckBox mSslSecurityView;
|
||||
private CheckBox mTrustCertificatesView;
|
||||
private CertificateSelector mClientCertificateSelector;
|
||||
|
||||
// Support for lifecycle
|
||||
private boolean mStarted;
|
||||
@ -100,13 +102,13 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment
|
||||
View view = inflater.inflate(layoutId, container, false);
|
||||
Context context = getActivity();
|
||||
|
||||
mUsernameView = (EditText) UiUtilities.getView(view, R.id.account_username);
|
||||
mPasswordView = (EditText) UiUtilities.getView(view, R.id.account_password);
|
||||
mServerView = (EditText) UiUtilities.getView(view, R.id.account_server);
|
||||
mSslSecurityView = (CheckBox) UiUtilities.getView(view, R.id.account_ssl);
|
||||
mUsernameView = UiUtilities.getView(view, R.id.account_username);
|
||||
mPasswordView = UiUtilities.getView(view, R.id.account_password);
|
||||
mServerView = UiUtilities.getView(view, R.id.account_server);
|
||||
mSslSecurityView = UiUtilities.getView(view, R.id.account_ssl);
|
||||
mSslSecurityView.setOnCheckedChangeListener(this);
|
||||
mTrustCertificatesView = (CheckBox) UiUtilities.getView(view,
|
||||
R.id.account_trust_certificates);
|
||||
mTrustCertificatesView = UiUtilities.getView(view, R.id.account_trust_certificates);
|
||||
mClientCertificateSelector = UiUtilities.getView(view, R.id.client_certificate_selector);
|
||||
|
||||
// Calls validateFields() which enables or disables the Next button
|
||||
// based on the fields' validity.
|
||||
@ -146,6 +148,7 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment
|
||||
Log.d(Logging.LOG_TAG, "AccountSetupExchangeFragment onActivityCreated");
|
||||
}
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mClientCertificateSelector.setActivity(getActivity());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -275,7 +278,10 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment
|
||||
boolean trustCertificates = 0 != (hostAuth.mFlags & HostAuth.FLAG_TRUST_ALL);
|
||||
mSslSecurityView.setChecked(ssl);
|
||||
mTrustCertificatesView.setChecked(trustCertificates);
|
||||
showTrustCertificates(ssl);
|
||||
if (hostAuth.mClientCertAlias != null) {
|
||||
mClientCertificateSelector.setCertificate(hostAuth.mClientCertAlias);
|
||||
}
|
||||
onUseSslChanged(ssl);
|
||||
|
||||
mLoadedRecvAuth = hostAuth;
|
||||
mLoaded = true;
|
||||
@ -304,16 +310,19 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (buttonView.getId() == R.id.account_ssl) {
|
||||
showTrustCertificates(isChecked);
|
||||
onUseSslChanged(isChecked);
|
||||
}
|
||||
}
|
||||
|
||||
public void showTrustCertificates(boolean visible) {
|
||||
int mode = visible ? View.VISIBLE : View.GONE;
|
||||
public void onUseSslChanged(boolean useSsl) {
|
||||
int mode = useSsl ? View.VISIBLE : View.GONE;
|
||||
mTrustCertificatesView.setVisibility(mode);
|
||||
UiUtilities.setVisibilitySafe(getView(), R.id.account_trust_certificates_divider, mode);
|
||||
mClientCertificateSelector.setVisibility(mode);
|
||||
UiUtilities.setVisibilitySafe(getView(), R.id.client_certificate_divider, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -383,17 +392,18 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment
|
||||
if (mTrustCertificatesView.isChecked()) {
|
||||
flags |= HostAuth.FLAG_TRUST_ALL;
|
||||
}
|
||||
String certAlias = mClientCertificateSelector.getCertificate();
|
||||
String serverAddress = mServerView.getText().toString().trim();
|
||||
|
||||
int port = mSslSecurityView.isChecked() ? 443 : 80;
|
||||
HostAuth sendAuth = account.getOrCreateHostAuthSend(mContext);
|
||||
sendAuth.setLogin(userName, userPassword);
|
||||
sendAuth.setConnection(mBaseScheme, serverAddress, port, flags);
|
||||
sendAuth.setConnection(mBaseScheme, serverAddress, port, flags, certAlias);
|
||||
sendAuth.mDomain = null;
|
||||
|
||||
HostAuth recvAuth = account.getOrCreateHostAuthRecv(mContext);
|
||||
recvAuth.setLogin(userName, userPassword);
|
||||
recvAuth.setConnection(mBaseScheme, serverAddress, port, flags);
|
||||
recvAuth.setConnection(mBaseScheme, serverAddress, port, flags, certAlias);
|
||||
recvAuth.mDomain = null;
|
||||
|
||||
// Check for a duplicate account (requires async DB work) and if OK, proceed with check
|
||||
|
167
src/com/android/email/view/CertificateSelector.java
Normal file
167
src/com/android/email/view/CertificateSelector.java
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.email.view;
|
||||
|
||||
import com.android.email.R;
|
||||
import com.android.email.activity.UiUtilities;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.security.KeyChain;
|
||||
import android.security.KeyChainAliasCallback;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* A simple view that can be used to select a certificate from the system {@link KeyChain}.
|
||||
*
|
||||
* Host activities must register themselves view {@link #setActivity} for this selector to work,
|
||||
* since it requires firing system {@link Intent}s.
|
||||
*/
|
||||
public class CertificateSelector extends LinearLayout implements
|
||||
OnClickListener, KeyChainAliasCallback {
|
||||
|
||||
/** Button to select or remove the certificate. */
|
||||
private Button mSelectButton;
|
||||
private TextView mAliasText;
|
||||
|
||||
/** The host activity. */
|
||||
private Activity mActivity;
|
||||
|
||||
|
||||
public CertificateSelector(Context context) {
|
||||
super(context);
|
||||
}
|
||||
public CertificateSelector(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
public CertificateSelector(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
public void setActivity(Activity activity) {
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
mAliasText = UiUtilities.getView(this, R.id.certificate_alias);
|
||||
mSelectButton = UiUtilities.getView(this, R.id.select_button);
|
||||
mSelectButton.setOnClickListener(this);
|
||||
setCertificate(null);
|
||||
}
|
||||
|
||||
public void setCertificate(String alias) {
|
||||
mAliasText.setText(alias);
|
||||
mAliasText.setVisibility((alias == null) ? View.GONE : View.VISIBLE);
|
||||
mSelectButton.setText(getResources().getString(
|
||||
(alias == null)
|
||||
? R.string.account_setup_exchange_use_certificate
|
||||
: R.string.account_setup_exchange_remove_certificate));
|
||||
}
|
||||
|
||||
public boolean hasCertificate() {
|
||||
return mAliasText.getVisibility() == View.VISIBLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alias for the currently selected certificate, or null if one is not selected.
|
||||
*/
|
||||
public String getCertificate() {
|
||||
return hasCertificate() ? mAliasText.getText().toString() : null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onClick(View target) {
|
||||
if (target == mSelectButton && mActivity != null) {
|
||||
if (hasCertificate()) {
|
||||
// Handle the click on the button when it says "Remove"
|
||||
setCertificate(null);
|
||||
|
||||
} else {
|
||||
// We don't restrict the chooser for certificate types since 95% of the time the
|
||||
// user will probably only have one certificate installed and it'll be the right
|
||||
// "type". Just let them fail and select a different one if it doesn't match.
|
||||
KeyChain.choosePrivateKeyAlias(
|
||||
mActivity, this,
|
||||
null /* keytypes */, null /* issuers */, null /* host */, -1 /* port */);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// KeyChainAliasCallback
|
||||
@Override
|
||||
public void alias(String alias) {
|
||||
if (alias != null) {
|
||||
setCertificate(alias);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable parcel) {
|
||||
SavedState savedState = (SavedState) parcel;
|
||||
super.onRestoreInstanceState(savedState.getSuperState());
|
||||
setCertificate(savedState.mValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
return new SavedState(super.onSaveInstanceState(), getCertificate());
|
||||
}
|
||||
|
||||
public static class SavedState extends BaseSavedState {
|
||||
final String mValue;
|
||||
|
||||
SavedState(Parcelable superState, String value) {
|
||||
super(superState);
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeString(mValue);
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
public static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
mValue = in.readString();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user