blob: f5f4633ea5077c725f0ae7aecdba356b1de9f270 [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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.ide.eclipse.adt.internal.preferences;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity;
import com.android.ide.eclipse.adt.internal.utils.FingerprintUtils;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.internal.build.DebugKeyProvider;
import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.FileFieldEditor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.RadioGroupFieldEditor;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Date;
/**
* Preference page for build options.
*
*/
public class BuildPreferencePage extends FieldEditorPreferencePage implements
IWorkbenchPreferencePage {
private IPreferenceStore mPrefStore = null;
// default key store
private ReadOnlyFieldEditor mDefaultKeyStore = null;
private LabelField mDefaultFingerprintMd5 = null;
private LabelField mDefaultFingerprintSha1 = null;
// custom key store
private KeystoreFieldEditor mCustomKeyStore = null;
private LabelField mCustomFingerprintMd5 = null;
private LabelField mCustomFingerprintSha1 = null;
public BuildPreferencePage() {
super(GRID);
mPrefStore = AdtPlugin.getDefault().getPreferenceStore();
setPreferenceStore(mPrefStore);
setDescription(Messages.BuildPreferencePage_Title);
}
@Override
protected void createFieldEditors() {
addField(new BooleanFieldEditor(AdtPrefs.PREFS_BUILD_RES_AUTO_REFRESH,
Messages.BuildPreferencePage_Auto_Refresh_Resources_on_Build,
getFieldEditorParent()));
addField(new BooleanFieldEditor(AdtPrefs.PREFS_BUILD_FORCE_ERROR_ON_NATIVELIB_IN_JAR,
"Force error when external jars contain native libraries",
getFieldEditorParent()));
addField(new BooleanFieldEditor(AdtPrefs.PREFS_BUILD_SKIP_POST_COMPILE_ON_FILE_SAVE,
"Skip packaging and dexing until export or launch. (Speeds up automatic builds on file save)",
getFieldEditorParent()));
RadioGroupFieldEditor rgfe = new RadioGroupFieldEditor(
AdtPrefs.PREFS_BUILD_VERBOSITY,
Messages.BuildPreferencePage_Build_Output, 1, new String[][] {
{ Messages.BuildPreferencePage_Silent, BuildVerbosity.ALWAYS.name() },
{ Messages.BuildPreferencePage_Normal, BuildVerbosity.NORMAL.name() },
{ Messages.BuildPreferencePage_Verbose, BuildVerbosity.VERBOSE.name() }
},
getFieldEditorParent(), true);
addField(rgfe);
// default debug keystore fingerprints
Fingerprints defaultFingerprints = getFingerprints(
mPrefStore.getString(AdtPrefs.PREFS_DEFAULT_DEBUG_KEYSTORE));
// default debug key store fields
mDefaultKeyStore = new ReadOnlyFieldEditor(AdtPrefs.PREFS_DEFAULT_DEBUG_KEYSTORE,
Messages.BuildPreferencePage_Default_KeyStore, getFieldEditorParent());
mDefaultFingerprintMd5 = new LabelField(
Messages.BuildPreferencePage_Default_Certificate_Fingerprint_MD5,
defaultFingerprints != null ? defaultFingerprints.md5 : "",
getFieldEditorParent());
mDefaultFingerprintSha1 = new LabelField(
Messages.BuildPreferencePage_Default_Certificate_Fingerprint_SHA1,
defaultFingerprints != null ? defaultFingerprints.sha1 : "",
getFieldEditorParent());
addField(mDefaultKeyStore);
addField(mDefaultFingerprintMd5);
addField(mDefaultFingerprintSha1);
// custom debug keystore fingerprints
Fingerprints customFingerprints = null;
String customDebugKeystorePath = mPrefStore.getString(AdtPrefs.PREFS_CUSTOM_DEBUG_KEYSTORE);
if (new File(customDebugKeystorePath).isFile()) {
customFingerprints = getFingerprints(customDebugKeystorePath);
} else {
// file does not exist.
setErrorMessage("Not a valid keystore path.");
}
// custom debug key store fields
mCustomKeyStore = new KeystoreFieldEditor(AdtPrefs.PREFS_CUSTOM_DEBUG_KEYSTORE,
Messages.BuildPreferencePage_Custom_Keystore, getFieldEditorParent());
mCustomFingerprintMd5 = new LabelField(
Messages.BuildPreferencePage_Default_Certificate_Fingerprint_MD5,
customFingerprints != null ? customFingerprints.md5 : "",
getFieldEditorParent());
mCustomFingerprintSha1 = new LabelField(
Messages.BuildPreferencePage_Default_Certificate_Fingerprint_SHA1,
customFingerprints != null ? customFingerprints.sha1 : "",
getFieldEditorParent());
// set fingerprint fields
mCustomKeyStore.setFingerprintMd5Field(mCustomFingerprintMd5);
mCustomKeyStore.setFingerprintSha1Field(mCustomFingerprintSha1);
addField(mCustomKeyStore);
addField(mCustomFingerprintMd5);
addField(mCustomFingerprintSha1);
}
/**
* MD5 & SHA1 fingerprints.
*/
private static class Fingerprints {
final String md5;
final String sha1;
Fingerprints(String md5Val, String sha1Val) {
md5 = md5Val;
sha1 = sha1Val;
}
}
private Fingerprints getFingerprints(String keystorePath) {
// attempt to load the debug key.
try {
DebugKeyProvider keyProvider = new DebugKeyProvider(keystorePath,
null /* storeType */, null /* key gen output */);
return new Fingerprints(
FingerprintUtils.getFingerprint(keyProvider.getCertificate(), "MD5"),
FingerprintUtils.getFingerprint(keyProvider.getCertificate(), "SHA1"));
} catch (GeneralSecurityException e) {
setErrorMessage(e.getMessage());
} catch (IOException e) {
setErrorMessage(e.getMessage());
} catch (KeytoolException e) {
setErrorMessage(e.getMessage());
} catch (AndroidLocationException e) {
setErrorMessage(e.getMessage());
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
*/
@Override
public void init(IWorkbench workbench) {
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.preference.FieldEditorPreferencePage#performDefaults
* (org.eclipse.jface.preference.PreferencePage#performDefaults)
*/
@Override
protected void performDefaults() {
super.performDefaults();
// restore the default key store fingerprints
Fingerprints defaultFingerprints = getFingerprints(mPrefStore
.getString(AdtPrefs.PREFS_DEFAULT_DEBUG_KEYSTORE));
mDefaultFingerprintMd5.setStringValue(defaultFingerprints.md5);
mDefaultFingerprintSha1.setStringValue(defaultFingerprints.sha1);
// set custom fingerprint fields to blank
mCustomFingerprintMd5.setStringValue("");
mCustomFingerprintSha1.setStringValue("");
}
/**
* A read-only string field editor.
*/
private static class ReadOnlyFieldEditor extends StringFieldEditor {
public ReadOnlyFieldEditor(String name, String labelText, Composite parent) {
super(name, labelText, parent);
}
@Override
protected void createControl(Composite parent) {
super.createControl(parent);
Text control = getTextControl();
control.setEditable(false);
}
}
/**
* A read-only string field.
*/
private static class LabelField extends StringFieldEditor {
private String text;
public LabelField(String labelText, String value, Composite parent) {
super("", labelText, parent);
text = value;
}
@Override
protected void createControl(Composite parent) {
super.createControl(parent);
Text control = getTextControl();
control.setEditable(false);
}
@Override
protected void doLoad() {
setStringValue(text);
}
@Override
protected void doStore() {
// Do nothing
}
}
/**
* Custom {@link FileFieldEditor} that checks that the keystore is valid.
*/
private static class KeystoreFieldEditor extends FileFieldEditor {
private StringFieldEditor fingerprintMd5 = null;
private StringFieldEditor fingerprintSha1 = null;
public void setFingerprintMd5Field(StringFieldEditor field) {
fingerprintMd5 = field;
}
public void setFingerprintSha1Field(StringFieldEditor field) {
fingerprintSha1 = field;
}
public KeystoreFieldEditor(String name, String label, Composite parent) {
super(name, label, parent);
setValidateStrategy(VALIDATE_ON_KEY_STROKE);
}
@Override
protected boolean checkState() {
String fileName = getTextControl().getText();
fileName = fileName.trim();
if (fingerprintMd5 != null) {
fingerprintMd5.setStringValue("");
}
if (fingerprintSha1 != null) {
fingerprintSha1.setStringValue("");
}
// empty values are considered ok.
if (fileName.length() > 0) {
File file = new File(fileName);
if (file.isFile()) {
// attempt to load the debug key.
try {
DebugKeyProvider provider = new DebugKeyProvider(fileName,
null /* storeType */, null /* key gen output */);
PrivateKey key = provider.getDebugKey();
X509Certificate certificate = (X509Certificate)provider.getCertificate();
if (key == null || certificate == null) {
showErrorMessage("Unable to find debug key in keystore!");
return false;
}
if (fingerprintMd5 != null) {
fingerprintMd5.setStringValue(
FingerprintUtils.getFingerprint(certificate, "MD5"));
}
if (fingerprintSha1 != null) {
fingerprintSha1.setStringValue(
FingerprintUtils.getFingerprint(certificate, "SHA1"));
}
Date today = new Date();
if (certificate.getNotAfter().compareTo(today) < 0) {
showErrorMessage("Certificate is expired!");
return false;
}
if (certificate.getNotBefore().compareTo(today) > 0) {
showErrorMessage("Certificate validity is in the future!");
return false;
}
// we're good!
clearErrorMessage();
return true;
} catch (GeneralSecurityException e) {
handleException(e);
return false;
} catch (IOException e) {
handleException(e);
return false;
} catch (KeytoolException e) {
handleException(e);
return false;
} catch (AndroidLocationException e) {
handleException(e);
return false;
}
} else {
// file does not exist.
showErrorMessage("Not a valid keystore path.");
return false; // Apply/OK must be disabled
}
}
clearErrorMessage();
return true;
}
@Override
public Text getTextControl(Composite parent) {
setValidateStrategy(VALIDATE_ON_KEY_STROKE);
return super.getTextControl(parent);
}
/**
* Set the error message from a {@link Throwable}. If the exception has no message, try
* to get the message from the cause.
* @param t the Throwable.
*/
private void handleException(Throwable t) {
String msg = t.getMessage();
if (msg == null) {
Throwable cause = t.getCause();
if (cause != null) {
handleException(cause);
} else {
setErrorMessage("Uknown error when getting the debug key!");
}
return;
}
// valid text, display it.
showErrorMessage(msg);
}
}
}