1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php 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.ide.eclipse.adt.internal.preferences; 18 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; 21 import com.android.prefs.AndroidLocation.AndroidLocationException; 22 import com.android.sdklib.internal.build.DebugKeyProvider; 23 import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException; 24 25 import org.eclipse.jface.preference.BooleanFieldEditor; 26 import org.eclipse.jface.preference.FieldEditorPreferencePage; 27 import org.eclipse.jface.preference.FileFieldEditor; 28 import org.eclipse.jface.preference.RadioGroupFieldEditor; 29 import org.eclipse.jface.preference.StringFieldEditor; 30 import org.eclipse.swt.widgets.Composite; 31 import org.eclipse.swt.widgets.Text; 32 import org.eclipse.ui.IWorkbench; 33 import org.eclipse.ui.IWorkbenchPreferencePage; 34 35 import java.io.File; 36 import java.io.IOException; 37 import java.security.GeneralSecurityException; 38 import java.security.PrivateKey; 39 import java.security.cert.X509Certificate; 40 import java.util.Date; 41 42 /** 43 * Preference page for build options. 44 * 45 */ 46 public class BuildPreferencePage extends FieldEditorPreferencePage implements 47 IWorkbenchPreferencePage { 48 BuildPreferencePage()49 public BuildPreferencePage() { 50 super(GRID); 51 setPreferenceStore(AdtPlugin.getDefault().getPreferenceStore()); 52 setDescription(Messages.BuildPreferencePage_Title); 53 } 54 55 @Override createFieldEditors()56 protected void createFieldEditors() { 57 addField(new BooleanFieldEditor(AdtPrefs.PREFS_BUILD_RES_AUTO_REFRESH, 58 Messages.BuildPreferencePage_Auto_Refresh_Resources_on_Build, 59 getFieldEditorParent())); 60 61 addField(new BooleanFieldEditor(AdtPrefs.PREFS_BUILD_FORCE_ERROR_ON_NATIVELIB_IN_JAR, 62 "Force error when external jars contain native libraries", 63 getFieldEditorParent())); 64 65 RadioGroupFieldEditor rgfe = new RadioGroupFieldEditor( 66 AdtPrefs.PREFS_BUILD_VERBOSITY, 67 Messages.BuildPreferencePage_Build_Output, 1, new String[][] { 68 { Messages.BuildPreferencePage_Silent, BuildVerbosity.ALWAYS.name() }, 69 { Messages.BuildPreferencePage_Normal, BuildVerbosity.NORMAL.name() }, 70 { Messages.BuildPreferencePage_Verbose, BuildVerbosity.VERBOSE.name() } 71 }, 72 getFieldEditorParent(), true); 73 addField(rgfe); 74 75 addField(new ReadOnlyFieldEditor(AdtPrefs.PREFS_DEFAULT_DEBUG_KEYSTORE, 76 Messages.BuildPreferencePage_Default_KeyStore, getFieldEditorParent())); 77 78 addField(new KeystoreFieldEditor(AdtPrefs.PREFS_CUSTOM_DEBUG_KEYSTORE, 79 Messages.BuildPreferencePage_Custom_Keystore, getFieldEditorParent())); 80 81 } 82 83 /* 84 * (non-Javadoc) 85 * 86 * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) 87 */ init(IWorkbench workbench)88 public void init(IWorkbench workbench) { 89 } 90 91 /** 92 * A read-only string field editor. 93 */ 94 private static class ReadOnlyFieldEditor extends StringFieldEditor { 95 ReadOnlyFieldEditor(String name, String labelText, Composite parent)96 public ReadOnlyFieldEditor(String name, String labelText, Composite parent) { 97 super(name, labelText, parent); 98 } 99 100 @Override createControl(Composite parent)101 protected void createControl(Composite parent) { 102 super.createControl(parent); 103 104 Text control = getTextControl(); 105 control.setEditable(false); 106 } 107 } 108 109 /** 110 * Custom {@link FileFieldEditor} that checks that the keystore is valid. 111 */ 112 private static class KeystoreFieldEditor extends FileFieldEditor { KeystoreFieldEditor(String name, String label, Composite parent)113 public KeystoreFieldEditor(String name, String label, Composite parent) { 114 super(name, label, parent); 115 setValidateStrategy(VALIDATE_ON_KEY_STROKE); 116 } 117 118 @Override checkState()119 protected boolean checkState() { 120 String fileName = getTextControl().getText(); 121 fileName = fileName.trim(); 122 123 // empty values are considered ok. 124 if (fileName.length() > 0) { 125 File file = new File(fileName); 126 if (file.isFile()) { 127 // attempt to load the debug key. 128 try { 129 DebugKeyProvider provider = new DebugKeyProvider(fileName, 130 null /* storeType */, null /* key gen output */); 131 PrivateKey key = provider.getDebugKey(); 132 X509Certificate certificate = (X509Certificate)provider.getCertificate(); 133 134 if (key == null || certificate == null) { 135 showErrorMessage("Unable to find debug key in keystore!"); 136 return false; 137 } 138 139 Date today = new Date(); 140 if (certificate.getNotAfter().compareTo(today) < 0) { 141 showErrorMessage("Certificate is expired!"); 142 return false; 143 } 144 145 if (certificate.getNotBefore().compareTo(today) > 0) { 146 showErrorMessage("Certificate validity is in the future!"); 147 return false; 148 } 149 150 // we're good! 151 clearErrorMessage(); 152 return true; 153 } catch (GeneralSecurityException e) { 154 handleException(e); 155 return false; 156 } catch (IOException e) { 157 handleException(e); 158 return false; 159 } catch (KeytoolException e) { 160 handleException(e); 161 return false; 162 } catch (AndroidLocationException e) { 163 handleException(e); 164 return false; 165 } 166 167 168 } else { 169 // file does not exist. 170 showErrorMessage("Not a valid keystore path."); 171 return false; // Apply/OK must be disabled 172 } 173 } 174 175 clearErrorMessage(); 176 return true; 177 } 178 179 @Override getTextControl(Composite parent)180 public Text getTextControl(Composite parent) { 181 setValidateStrategy(VALIDATE_ON_KEY_STROKE); 182 return super.getTextControl(parent); 183 } 184 185 /** 186 * Set the error message from a {@link Throwable}. If the exception has no message, try 187 * to get the message from the cause. 188 * @param t the Throwable. 189 */ handleException(Throwable t)190 private void handleException(Throwable t) { 191 String msg = t.getMessage(); 192 if (msg == null) { 193 Throwable cause = t.getCause(); 194 if (cause != null) { 195 handleException(cause); 196 } else { 197 setErrorMessage("Uknown error when getting the debug key!"); 198 } 199 200 return; 201 } 202 203 // valid text, display it. 204 showErrorMessage(msg); 205 } 206 } 207 } 208