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.AdtConstants; 20 import com.android.ide.eclipse.adt.AdtPlugin; 21 import com.android.jarutils.DebugKeyProvider; 22 import com.android.jarutils.DebugKeyProvider.KeytoolException; 23 import com.android.prefs.AndroidLocation.AndroidLocationException; 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 49 final static String BUILD_STR_SILENT = "silent"; //$NON-NLS-1$ 50 final static String BUILD_STR_NORMAL = "normal"; //$NON-NLS-1$ 51 final static String BUILD_STR_VERBOSE = "verbose"; //$NON-NLS-1$ 52 BuildPreferencePage()53 public BuildPreferencePage() { 54 super(GRID); 55 setPreferenceStore(AdtPlugin.getDefault().getPreferenceStore()); 56 setDescription(Messages.BuildPreferencePage_Title); 57 } 58 getBuildLevel(String buildPrefValue)59 public static int getBuildLevel(String buildPrefValue) { 60 if (BUILD_STR_SILENT.equals(buildPrefValue)) { 61 return AdtConstants.BUILD_ALWAYS; 62 } else if (BUILD_STR_VERBOSE.equals(buildPrefValue)) { 63 return AdtConstants.BUILD_VERBOSE; 64 } 65 66 return AdtConstants.BUILD_NORMAL; 67 } 68 69 @Override createFieldEditors()70 protected void createFieldEditors() { 71 addField(new BooleanFieldEditor(AdtPlugin.PREFS_RES_AUTO_REFRESH, 72 Messages.BuildPreferencePage_Auto_Refresh_Resources_on_Build, 73 getFieldEditorParent())); 74 75 RadioGroupFieldEditor rgfe = new RadioGroupFieldEditor( 76 AdtPlugin.PREFS_BUILD_VERBOSITY, 77 Messages.BuildPreferencePage_Build_Output, 1, new String[][] { 78 { Messages.BuildPreferencePage_Silent, BUILD_STR_SILENT }, 79 { Messages.BuildPreferencePage_Normal, BUILD_STR_NORMAL }, 80 { Messages.BuildPreferencePage_Verbose, BUILD_STR_VERBOSE } 81 }, 82 getFieldEditorParent(), true); 83 addField(rgfe); 84 85 addField(new ReadOnlyFieldEditor(AdtPlugin.PREFS_DEFAULT_DEBUG_KEYSTORE, 86 Messages.BuildPreferencePage_Default_KeyStore, getFieldEditorParent())); 87 88 addField(new KeystoreFieldEditor(AdtPlugin.PREFS_CUSTOM_DEBUG_KEYSTORE, 89 Messages.BuildPreferencePage_Custom_Keystore, getFieldEditorParent())); 90 91 } 92 93 /* 94 * (non-Javadoc) 95 * 96 * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) 97 */ init(IWorkbench workbench)98 public void init(IWorkbench workbench) { 99 } 100 101 /** 102 * A read-only string field editor. 103 */ 104 private static class ReadOnlyFieldEditor extends StringFieldEditor { 105 ReadOnlyFieldEditor(String name, String labelText, Composite parent)106 public ReadOnlyFieldEditor(String name, String labelText, Composite parent) { 107 super(name, labelText, parent); 108 } 109 110 @Override createControl(Composite parent)111 protected void createControl(Composite parent) { 112 super.createControl(parent); 113 114 Text control = getTextControl(); 115 control.setEditable(false); 116 } 117 } 118 119 /** 120 * Custom {@link FileFieldEditor} that checks that the keystore is valid. 121 */ 122 private static class KeystoreFieldEditor extends FileFieldEditor { KeystoreFieldEditor(String name, String label, Composite parent)123 public KeystoreFieldEditor(String name, String label, Composite parent) { 124 super(name, label, parent); 125 setValidateStrategy(VALIDATE_ON_KEY_STROKE); 126 } 127 128 @Override checkState()129 protected boolean checkState() { 130 String fileName = getTextControl().getText(); 131 fileName = fileName.trim(); 132 133 // empty values are considered ok. 134 if (fileName.length() > 0) { 135 File file = new File(fileName); 136 if (file.isFile()) { 137 // attempt to load the debug key. 138 try { 139 DebugKeyProvider provider = new DebugKeyProvider(fileName, 140 null /* storeType */, null /* key gen output */); 141 PrivateKey key = provider.getDebugKey(); 142 X509Certificate certificate = (X509Certificate)provider.getCertificate(); 143 144 if (key == null || certificate == null) { 145 showErrorMessage("Unable to find debug key in keystore!"); 146 return false; 147 } 148 149 Date today = new Date(); 150 if (certificate.getNotAfter().compareTo(today) < 0) { 151 showErrorMessage("Certificate is expired!"); 152 return false; 153 } 154 155 if (certificate.getNotBefore().compareTo(today) > 0) { 156 showErrorMessage("Certificate validity is in the future!"); 157 return false; 158 } 159 160 // we're good! 161 clearErrorMessage(); 162 return true; 163 } catch (GeneralSecurityException e) { 164 handleException(e); 165 return false; 166 } catch (IOException e) { 167 handleException(e); 168 return false; 169 } catch (KeytoolException e) { 170 handleException(e); 171 return false; 172 } catch (AndroidLocationException e) { 173 handleException(e); 174 return false; 175 } 176 177 178 } else { 179 // file does not exist. 180 showErrorMessage("Not a valid keystore path."); 181 return false; // Apply/OK must be disabled 182 } 183 } 184 185 clearErrorMessage(); 186 return true; 187 } 188 189 @Override getTextControl(Composite parent)190 public Text getTextControl(Composite parent) { 191 setValidateStrategy(VALIDATE_ON_KEY_STROKE); 192 return super.getTextControl(parent); 193 } 194 195 /** 196 * Set the error message from a {@link Throwable}. If the exception has no message, try 197 * to get the message from the cause. 198 * @param t the Throwable. 199 */ handleException(Throwable t)200 private void handleException(Throwable t) { 201 String msg = t.getMessage(); 202 if (msg == null) { 203 Throwable cause = t.getCause(); 204 if (cause != null) { 205 handleException(cause); 206 } else { 207 setErrorMessage("Uknown error when getting the debug key!"); 208 } 209 210 return; 211 } 212 213 // valid text, display it. 214 showErrorMessage(msg); 215 } 216 } 217 } 218