summaryrefslogtreecommitdiff
path: root/src/plugins/certmanager/src
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/certmanager/src')
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/CertificateManagerActivator.java146
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/AbstractHandler2.java63
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/BackupHandler.java265
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CertificatePropertiesHandler.java69
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangeKeyStoreTypeHandler.java88
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeyHandler.java186
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeystoreHandler.java157
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeyHandler.java50
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeystoreHandler.java51
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeyHandler.java137
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeystoreHandler.java120
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeyStoreEntriesHandler.java98
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeystoreHandler.java52
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RefreshHandler.java39
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RestoreBackupHandler.java306
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/SignExternalPackagesHandler.java39
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/UnsignExternalPackagesHandler.java40
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/BackwardKeystoreManager.java164
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreManager.java303
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtils.java686
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtilsTest.java243
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/PasswordProvider.java484
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManager.java328
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManagerTest.java156
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/IKeyStoreModelListener.java62
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEvent.java67
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEventManager.java116
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/InvalidPasswordException.java53
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/KeyStoreManagerException.java53
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/CertificateManagerNLS.java522
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/certificateManagerNLS.properties285
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/job/CreateKeyJob.java191
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/PackageFile.java648
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ISignConstants.java77
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestDigester.java185
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestEntry.java243
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/PackageFileSigner.java263
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignException.java45
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureBlockFile.java264
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java226
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/property/tester/TreeNodeTester.java50
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/PopupMenuActionDelegate.java224
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/RemoveSignatureAction.java69
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/SignCreatedPackageAction.java84
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/CertificateBlock.java495
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/KeyPropertiesBlock.java74
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/NewKeyBlock.java303
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupContentProvider.java53
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupDialog.java400
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupLabelProvider.java66
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/CertificateInfoDialog.java139
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/RestoreBackupDialog.java437
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ConvertKeyStoreTypeDialog.java633
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ImportEntriesDialog.java675
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/AbstractTreeNode.java139
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/CertificateDetailsInfo.java140
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryDummyNode.java71
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java546
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStore.java132
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStoreEntry.java87
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/ITreeNode.java118
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreNode.java786
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreRootNode.java126
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/SigningAndKeysModelManager.java148
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/ExpiresInColumnLabelProvider.java55
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/KeystoreManagerTreeContentProvider.java132
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/LastBackupDateColumnLabelProvider.java46
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/NameAliasColumnLabelProvider.java135
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/PathColumnLabelProvider.java37
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/TypeColumnLabelProvider.java39
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizard.java107
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizardPage.java284
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystorePage.java672
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystoreWizard.java122
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystorePage.java417
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystoreWizard.java72
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignaturePage.java686
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignatureWizard.java282
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystorePage.java200
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystoreWizard.java141
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackagePage.java559
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackageWizard.java346
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/views/KeystoreManagerView.java378
83 files changed, 18275 insertions, 0 deletions
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/CertificateManagerActivator.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/CertificateManagerActivator.java
new file mode 100644
index 0000000..156c5f3
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/CertificateManagerActivator.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager;
+
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class CertificateManagerActivator extends AbstractUIPlugin
+{
+
+ public static final String PLUGIN_ID = "com.motorolamobility.studio.android.certmanager"; //$NON-NLS-1$
+
+ public static final String UNSIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID = PLUGIN_ID
+ + ".unsign_external_pkg_wiz";
+
+ public static final String REMOVE_SIGNATURE_WIZ_BAN = "icons/wizban/unsign_package_wiz.png";
+
+ public static final String SIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID = PLUGIN_ID
+ + ".sign_external_pkg_wiz";
+
+ public static final String SIGNATURE_WIZ_BAN = "icons/wizban/sign_package_wiz.png";
+
+ /**
+ * The manifest version
+ */
+ public static final String MANIFEST_VERSION = "1.0";
+
+ /**
+ * Manifest attribute created by
+ */
+ public static final String CREATED_BY_FIELD = "Created-By";
+
+ /**
+ * Value of Created by attribute
+ */
+ public static final String CREATED_BY_FIELD_VALUE = "MOTODEV Studio for Android";
+
+ /**
+ * Package metainf directory name
+ */
+ public static final String METAFILES_DIR = "META-INF";
+
+ /**
+ * The package manifest file name
+ */
+ public static final String MANIFEST_FILE_NAME = "MANIFEST.MF";
+
+ /**
+ * Jar separator
+ */
+ public static final String JAR_SEPARATOR = "/";
+
+ /**
+ * Prefix to be used in temp files.
+ * */
+ public static final String TEMP_FILE_PREFIX = "tmppkg_";
+
+ /**
+ * The package extension.
+ */
+ public static final String PACKAGE_EXTENSION = "apk";
+
+ /**
+ * The default package destination extension
+ */
+ public static final String PACKAGE_PROJECT_DESTINATION = "dist";
+
+ // The shared instance
+ private static CertificateManagerActivator plugin;
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception
+ {
+ StudioLogger.debug(CertificateManagerActivator.class,
+ "Starting MOTODEV Studio for Android Key Manager Plugin...");
+
+ super.start(context);
+ plugin = this;
+
+ StudioLogger.debug(CertificateManagerActivator.class,
+ "MOTODEV Studio for Android Key Manager Plugin started.");
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception
+ {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static CertificateManagerActivator getDefault()
+ {
+ return plugin;
+ }
+
+ /**
+ * The certificate manager plugin declares one view that is used to show the keystores.
+ * */
+ public static KeystoreManagerView getKeyStoremManagerView()
+ {
+ IViewPart view = EclipseUtils.getActiveView(KeystoreManagerView.ID);
+
+ if (view instanceof KeystoreManagerView)
+ {
+ return (KeystoreManagerView) view;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/AbstractHandler2.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/AbstractHandler2.java
new file mode 100644
index 0000000..358c511
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/AbstractHandler2.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * This abstract handler adds convenient methods, like methods to retrieve the current selection.
+ */
+public abstract class AbstractHandler2 extends AbstractHandler implements IHandler2
+{
+
+ /**
+ * Retrieves the list of selected nodes.
+ * */
+ @SuppressWarnings("unchecked")
+ protected List<ITreeNode> getSelection()
+ {
+ List<ITreeNode> selectedNodes = new ArrayList<ITreeNode>(1);
+ ISelection selection =
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService()
+ .getSelection();
+ if (selection instanceof IStructuredSelection)
+ {
+ IStructuredSelection treeSelection = (IStructuredSelection) selection;
+ List<Object> selectedElements = treeSelection.toList();
+
+ for (Object selectedObject : selectedElements)
+ {
+ if (selectedObject instanceof ITreeNode)
+ {
+ selectedNodes.add((ITreeNode) selectedObject);
+ }
+ }
+ }
+
+ return selectedNodes;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/BackupHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/BackupHandler.java
new file mode 100644
index 0000000..925a69d
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/BackupHandler.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.FileUtil;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.dialogs.BackupDialog;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * Handler to execute the backup wizard.
+ * */
+public class BackupHandler extends AbstractHandler2 implements IHandler
+{
+
+ public static final String KS_TYPES_FILENAME = "KsTypes.csv"; //$NON-NLS-1$
+
+ private static final String KEYSTORE_EXT = ".keystore"; //$NON-NLS-1$
+
+ private static Date lastBackupDate = new Date();
+
+ private final Calendar cal = GregorianCalendar.getInstance();
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ BackupDialog dialog =
+ new BackupDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
+ try
+ {
+ List<IKeyStore> keyStores = KeyStoreManager.getInstance().getKeyStores();
+ List<String> initialInputList = new ArrayList<String>(keyStores.size());
+ for (int i = 0; i < keyStores.size(); i++)
+ {
+ boolean insert = true;
+ IKeyStore keyStore = keyStores.get(i);
+ if (keyStore instanceof ITreeNode)
+ {
+ ITreeNode ksNode = (ITreeNode) keyStore;
+ IStatus nodeStatus = ksNode.getNodeStatus();
+ if (!nodeStatus.isOK()
+ && (nodeStatus.getCode() == IKeyStore.WRONG_KEYSTORE_TYPE_ERROR_CODE))
+ {
+ insert = false;
+ }
+ }
+ if (insert)
+ {
+ initialInputList.add(keyStore.getFile().getAbsolutePath());
+ }
+ }
+
+ dialog.setInput(initialInputList.toArray(new String[initialInputList.size()]));
+ dialog.selectKeyStores(getSelection());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ throw new ExecutionException(e.getLocalizedMessage());
+ }
+
+ int diagReturn = dialog.open();
+ if (diagReturn == Dialog.OK)
+ {
+ File archiveFile = dialog.getArchiveFile();
+ List<String> selectedKeyStores = dialog.getSelectedKeyStores();
+ if (FileUtil.canWrite(archiveFile))
+ {
+ try
+ {
+ updateBackupDate(selectedKeyStores);
+ createZipArchive(archiveFile, selectedKeyStores);
+
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.BackupHandler_Error_BackUp_Title,
+ CertificateManagerNLS.BackupHandler_Error_Setting_Date);
+ }
+ catch (IOException e)
+ {
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.BackupHandler_Error_BackUp_Title, NLS.bind(
+ CertificateManagerNLS.BackupHandler_Error_Writing_Archive,
+ archiveFile));
+ }
+ }
+ else
+ {
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.BackupHandler_Error_BackUp_Title, NLS.bind(
+ CertificateManagerNLS.BackupHandler_Error_Writing_Archive,
+ archiveFile));
+ }
+
+ }
+ return null;
+ }
+
+ private void updateBackupDate(List<String> selectedKeyStores) throws KeyStoreManagerException
+ {
+ KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();
+ List<IKeyStore> keyStores = keyStoreManager.getKeyStores();
+ Long lastDateInMillis = cal.getTimeInMillis();
+ lastBackupDate.setTime(lastDateInMillis);
+
+ for (IKeyStore keyStore : keyStores)
+ {
+ if (selectedKeyStores.contains(keyStore.getFile().getAbsolutePath()))
+ {
+ keyStore.setLastBackupDate(lastBackupDate);
+ }
+ }
+
+ }
+
+ private void createZipArchive(File zipFile, List<String> filePaths) throws IOException,
+ KeyStoreManagerException
+ {
+ ZipOutputStream zos = null;
+ FileInputStream in = null;
+ try
+ {
+ zos = new ZipOutputStream(new FileOutputStream(zipFile));
+ Iterator<String> it = filePaths.iterator();
+ List<String> entriesNames = new ArrayList<String>(filePaths.size());
+ Properties typeProperties = new Properties();
+
+ int nameSuffix = 1;
+ while (it.hasNext())
+ {
+ String keyStore = it.next();
+ File keyStoreFile = new File(keyStore);
+ if (keyStoreFile.exists())
+ {
+ String entryName = keyStoreFile.getName();
+ while (entriesNames.contains(entryName))
+ {
+ if (entryName.toLowerCase().endsWith(KEYSTORE_EXT))
+ {
+ entryName =
+ entryName
+ .replace(KEYSTORE_EXT, "_" + nameSuffix + KEYSTORE_EXT); //$NON-NLS-1$
+ }
+ else
+ {
+ entryName = entryName.concat(Integer.toString(nameSuffix));
+ }
+ nameSuffix++;
+ }
+ putKsType(typeProperties, entryName, keyStore);
+ ZipEntry zipEntry = new ZipEntry(entryName);
+ zos.putNextEntry(zipEntry);
+ entriesNames.add(entryName);
+
+ byte[] buf = new byte[1024 * 4];
+ int len;
+ in = new FileInputStream(keyStoreFile);
+ try
+ {
+ while ((len = in.read(buf)) > 0)
+ {
+ zos.write(buf, 0, len);
+ }
+ }
+ finally
+ {
+ if (in != null)
+ {
+ in.close();
+ }
+ }
+ zos.flush();
+ }
+ }
+ zos.putNextEntry(new ZipEntry(KS_TYPES_FILENAME));
+ putLastBackupDate(typeProperties);
+ typeProperties.store(zos, "KeyStore types"); //$NON-NLS-1$
+ }
+ finally
+ {
+ if (zos != null)
+ {
+ try
+ {
+ zos.flush();
+ zos.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close steam while creating zip archive. "
+ + e.getMessage());
+ }
+ }
+ }
+ }
+
+ private void putKsType(Properties properties, String entryName, String filePaths)
+ throws KeyStoreManagerException
+ {
+ List<IKeyStore> keyStores = KeyStoreManager.getInstance().getKeyStores();
+ for (IKeyStore keyStore : keyStores)
+ {
+ String keyStorePath = keyStore.getFile().getAbsolutePath();
+ if (filePaths.contains(keyStorePath))
+ {
+ String type = keyStore.getType();
+ if (type != null)
+ {
+ properties.put(entryName, type);
+ }
+ break;
+ }
+ }
+
+ }
+
+ private void putLastBackupDate(Properties properties)
+ {
+ Long time = lastBackupDate.getTime();
+ String timeString = time.toString();
+ properties.put("lastBackupDate", timeString);
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CertificatePropertiesHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CertificatePropertiesHandler.java
new file mode 100644
index 0000000..e50aeac
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CertificatePropertiesHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.composite.KeyPropertiesBlock;
+import com.motorolamobility.studio.android.certmanager.ui.dialogs.CertificateInfoDialog;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * This class implements the command to display certificate properties
+ * */
+public class CertificatePropertiesHandler extends AbstractHandler2 implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ //retrieves the first element of the selection
+ //note that this command should be enabled only when selection.count == 1.
+ ITreeNode node = getSelection().get(0);
+
+ if (node instanceof IKeyStoreEntry)
+ {
+ final EntryNode keyStoreEntry = (EntryNode) node;
+ PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow ww = workbench.getActiveWorkbenchWindow();
+ Shell shell = ww.getShell();
+
+ CertificateInfoDialog dialog =
+ new CertificateInfoDialog(shell, new KeyPropertiesBlock(),
+ keyStoreEntry);
+
+ dialog.open();
+ }
+ });
+ }
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangeKeyStoreTypeHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangeKeyStoreTypeHandler.java
new file mode 100644
index 0000000..794831b
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangeKeyStoreTypeHandler.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import java.io.File;
+import java.util.Map;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.ui.dialogs.importks.ConvertKeyStoreTypeDialog;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * Handler to execute the change keystore type wizard.
+ * */
+public class ChangeKeyStoreTypeHandler extends AbstractHandler2
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ ITreeNode node = getSelection().get(0);
+
+ if (node instanceof IKeyStore)
+ {
+ ConvertKeyStoreTypeDialog dialog =
+ new ConvertKeyStoreTypeDialog(PlatformUI.getWorkbench()
+ .getModalDialogShellProvider().getShell(), (IKeyStore) node);
+ int diagStatus = dialog.open();
+ if (diagStatus == Dialog.OK)
+ {
+ IKeyStore keyStore = dialog.getKeyStore();
+ String newType = dialog.getNewType();
+ Map<String, String> aliases = dialog.getAliases();
+ String password = dialog.getKeystorePassword();
+
+ File keyStoreFile = keyStore.getFile();
+ try
+ {
+ if (password != null)
+ {
+ //user entered some password
+ KeyStoreUtils.changeKeyStoreType(keyStoreFile, password.toCharArray(),
+ keyStore.getType(), newType, aliases);
+ keyStore.setType(newType);
+ keyStore.forceReload(password.toCharArray(), false);
+ KeyStoreModelEventManager.getInstance().fireEvent((ITreeNode) keyStore,
+ EventType.UPDATE);
+
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog(e);
+ }
+ catch (InvalidPasswordException e)
+ {
+ EclipseUtils.showErrorDialog(e);
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeyHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeyHandler.java
new file mode 100644
index 0000000..19c1574
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeyHandler.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import java.security.KeyStore;
+import java.security.KeyStore.Entry;
+import java.security.UnrecoverableKeyException;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.window.Window;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.ui.PasswordInputDialog;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * This class changes the password of a key/certificate from the tree of the {@link KeystoreManagerView}
+ * */
+public class ChangePasswordKeyHandler extends AbstractHandler2 implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+
+ //retrieves the first element of the selection
+ //note that this command should be enabled only when selection.count == 1.
+ ITreeNode entry = getSelection().get(0);
+
+ if (entry instanceof EntryNode)
+ {
+ //must enter old and new password
+ KeyStoreNode keyStoreNode = (KeyStoreNode) entry.getParent();
+ PasswordProvider passwordProvider = new PasswordProvider(keyStoreNode.getFile());
+ EntryNode entryNode = (EntryNode) entry;
+
+ PasswordInputDialog passwordInputDialog = null;
+
+ boolean cancelledOrChangedPassword = false;
+
+ do
+ {
+ passwordInputDialog =
+ new PasswordInputDialog(PlatformUI.getWorkbench()
+ .getActiveWorkbenchWindow().getShell(),
+ CertificateManagerNLS.PasswordInput_EnterOldKeyPasssword_Message,
+ true, null, EntryNode.KEY_PASSWORD_MIN_SIZE);
+ if (passwordInputDialog.open() == Window.OK)
+ {
+ String newPassword = passwordInputDialog.getNewPassword();
+ String oldPassword = passwordInputDialog.getOldPassword();
+
+ if ((newPassword != null) && (oldPassword != null))
+ {
+ try
+ {
+ Entry keyEntry = entryNode.getKeyEntry(oldPassword);
+ if (keyEntry != null)
+ {
+ boolean tryAgain = false;
+ boolean useSavedPass = true;
+ String keystorePassword = null;
+ KeyStore keyStore = null;
+ do
+ {
+ if (tryAgain)
+ {
+ useSavedPass = false;
+ }
+ keystorePassword =
+ passwordProvider
+ .getKeyStorePassword(true, useSavedPass);
+ tryAgain = false;
+ if (keystorePassword != null)
+ {
+ try
+ {
+ if (keyStoreNode.isPasswordValid(keystorePassword))
+ {
+ keyStore =
+ keyStoreNode.getKeyStore(keystorePassword);
+ }
+ else
+ {
+ tryAgain = true;
+ }
+ }
+ catch (InvalidPasswordException e)
+ {
+ tryAgain = true;
+ }
+ }
+ }
+ while (tryAgain);
+ if (keyStore != null)
+ {
+ KeyStoreUtils.changeEntryPassword(keyStore,
+ keystorePassword.toCharArray(), keyStoreNode.getFile(),
+ entryNode.getAlias(), keyEntry,
+ newPassword.toCharArray());
+
+ //delete old save password - if there is one
+ if (passwordProvider.isPasswordSaved(entryNode.getAlias()))
+ {
+ passwordProvider.deleteSavedPassword(entryNode.getAlias());
+ }
+
+ if (passwordInputDialog.needToStorePassword())
+ {
+ //store new password at provider
+ passwordProvider.savePassword(entryNode.getAlias(),
+ newPassword);
+ }
+
+ //success
+ cancelledOrChangedPassword = true;
+ EclipseUtils.showInformationDialog(
+ CertificateManagerNLS.PasswordChanged_Info_Title,
+ CertificateManagerNLS.PasswordChanged_KeyInfo_Message);
+
+ //update tooltip and image
+ KeyStoreModelEventManager.getInstance().fireEvent(entryNode,
+ EventType.UPDATE);
+ }
+ }
+ }
+ catch (UnrecoverableKeyException e)
+ {
+ //error - notify on screen
+ cancelledOrChangedPassword = false;
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.ChangePasswordKeyHandler_Error_WrongOldKeyPassword,
+ CertificateManagerNLS.ChangePasswordKeyHandler_Wrong_Key_Password);
+ }
+ catch (Exception e)
+ {
+ //error - notify on screen
+ cancelledOrChangedPassword = false;
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.ChangePasswordKeyHandler_Error_WrongOldKeyPassword,
+ e.getMessage());
+ }
+ }
+ }
+ else
+ {
+ //user cancelled screen
+ cancelledOrChangedPassword = true;
+ }
+
+ }
+ while (!cancelledOrChangedPassword);
+
+ }
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeystoreHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeystoreHandler.java
new file mode 100644
index 0000000..9b1948b
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeystoreHandler.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import java.security.KeyStore;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.ui.PasswordInputDialog;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * This class deletes the keystore from the tree of the {@link KeystoreManagerView}
+ * */
+public class ChangePasswordKeystoreHandler extends AbstractHandler2 implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+
+ //retrieves the first element of the selection
+ //note that this command should be enabled only when selection.count == 1.
+ ITreeNode node = getSelection().get(0);
+
+ if (node instanceof KeyStoreNode)
+ {
+ KeyStoreNode keyStoreNode = (KeyStoreNode) node;
+ PasswordProvider passwordProvider = new PasswordProvider(keyStoreNode.getFile());
+
+ //must enter old and new password
+ PasswordInputDialog passwordInputDialog = null;
+
+ boolean cancelledOrChangedPassword = false;
+
+ do
+ {
+ passwordInputDialog =
+ new PasswordInputDialog(
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ NLS.bind(
+ CertificateManagerNLS.Passwordinput_EnterOldKeystorePasssword_Message,
+ keyStoreNode.getName()), true, null,
+ IKeyStore.KEYSTORE_PASSWORD_MIN_SIZE);
+ if (passwordInputDialog.open() == Window.OK)
+ {
+ String newPassword = passwordInputDialog.getNewPassword();
+ String oldPassword = passwordInputDialog.getOldPassword();
+
+ if ((newPassword != null) && (oldPassword != null))
+ {
+ KeyStore keyStore = null;
+ try
+ {
+ keyStore =
+ KeyStoreUtils.loadKeystore(keyStoreNode.getFile(),
+ oldPassword.toCharArray(), keyStoreNode.getType());
+
+ try
+ {
+ //rewrite keystore with new password
+ KeyStoreUtils.changeKeystorePasswd(keyStore,
+ keyStoreNode.getFile(), oldPassword.toCharArray(),
+ newPassword.toCharArray());
+
+ //deletes old password from provider
+ if (passwordProvider.isPasswordSaved())
+ {
+ passwordProvider.deleteKeyStoreSavedPassword();
+ }
+
+ if (passwordInputDialog.needToStorePassword())
+ {
+ //store new password at provider
+ passwordProvider.saveKeyStorePassword(newPassword);
+ }
+
+ //success
+ cancelledOrChangedPassword = true;
+ EclipseUtils.showInformationDialog(
+ CertificateManagerNLS.PasswordChanged_Info_Title,
+ CertificateManagerNLS.bind(
+ CertificateManagerNLS.PasswordChanged_Info_Message,
+ keyStoreNode.getFile()));
+
+ //update tooltip and image
+ KeyStoreModelEventManager.getInstance().fireEvent(node,
+ EventType.UPDATE);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ //error to change password - notify on screen
+ cancelledOrChangedPassword = false;
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.ChangePasswordKeystoreHandler_Error_ChangingKeystorePassword,
+ e.getMessage());
+ }
+ }
+ catch (Exception e1)
+ {
+ //invalid old password
+ StudioLogger.error(ChangePasswordKeystoreHandler.class,
+ e1.getMessage(), e1);
+ cancelledOrChangedPassword = false;
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.ChangePasswordKeystoreHandler_Error_WrongOldKeystorePassword,
+ CertificateManagerNLS
+ .bind(CertificateManagerNLS.ChangePasswordKeystoreHandler_InvalidOldPassword,
+ keyStoreNode.getFile()));
+ }
+ }
+ }
+ else
+ {
+ //user cancelled screen
+ cancelledOrChangedPassword = true;
+ }
+
+ }
+ while (!cancelledOrChangedPassword);
+ }
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeyHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeyHandler.java
new file mode 100644
index 0000000..37a91d5
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeyHandler.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+
+import com.motorola.studio.android.common.utilities.ui.WidgetsUtil;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeyWizard;
+
+/**
+ * Handler to execute the create key wizard.
+ */
+public class CreateKeyHandler extends AbstractHandler2 implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ //retrieves the first element of the selection
+ //note that this command should be enabled only when selection.count == 1.
+ ITreeNode node = getSelection().get(0);
+
+ if (node instanceof IKeyStore)
+ {
+ //get keystore where to create the new key
+ final IKeyStore keyStore = (IKeyStore) node;
+ CreateKeyWizard createKeyWizard = new CreateKeyWizard(keyStore);
+ WidgetsUtil.runWizard(createKeyWizard);
+ }
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeystoreHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeystoreHandler.java
new file mode 100644
index 0000000..d56981f
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeystoreHandler.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeystoreWizard;
+
+/**
+ * Handler to execute the create keystore wizard.
+ * */
+public class CreateKeystoreHandler extends AbstractHandler implements IHandler2
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+
+ CreateKeystoreWizard createKeystoreWizard = new CreateKeystoreWizard();
+
+ WizardDialog dialog = new WizardDialog(shell, createKeystoreWizard);
+
+ //open the wizard to create keystores
+ //the result doesn't need to be handled as it is self-contained
+ dialog.create();
+ dialog.open();
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeyHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeyHandler.java
new file mode 100644
index 0000000..ab73f89
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeyHandler.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * This class deletes the key entry from the tree of the {@link KeystoreManagerView}
+ * */
+public class DeleteKeyHandler extends AbstractHandler2 implements IHandler
+{
+
+ /*
+ * Question dialog confirming deletion of the key with a toggle
+ * asking if the key should also be deleted from the filesystem
+ * @return true if the deletion is confirmed, false otherwise and true in the
+ * toggleState if it can also be deleted from the filesystem, false otherwise
+ */
+ private boolean showQuestion(List<ITreeNode> nodesToDelete)
+ {
+
+ final Boolean[] reply = new Boolean[1];
+
+ final String entryName = nodesToDelete.size() == 1 ? nodesToDelete.get(0).getName() : null;
+
+ PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow ww = workbench.getActiveWorkbenchWindow();
+ Shell shell = ww.getShell();
+
+ reply[0] =
+ MessageDialog
+ .openQuestion(
+ shell,
+ CertificateManagerNLS.DeleteKeyHandler_ConfirmationQuestionDialog_Title,
+ entryName != null
+ ? CertificateManagerNLS
+ .bind(CertificateManagerNLS.DeleteKeyHandler_ConfirmationQuestionDialog_Description,
+ entryName)
+ : CertificateManagerNLS.DeleteKeyHandler_Delete_Selected_Keys);
+ }
+ });
+
+ return reply[0];
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ List<ITreeNode> nodesToDelete = getSelection();
+
+ if (!nodesToDelete.isEmpty())
+ {
+ boolean shouldProceed = showQuestion(nodesToDelete);
+ if (shouldProceed)
+ {
+ Map<IKeyStore, List<String>> deleteNodesMap = getKeysMap(nodesToDelete);
+
+ for (IKeyStore keyStore : deleteNodesMap.keySet())
+ {
+ try
+ {
+ keyStore.removeKeys(deleteNodesMap.get(keyStore));
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog(e);
+ throw new ExecutionException(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ nodesToDelete.clear();
+
+ return null;
+ }
+
+ private Map<IKeyStore, List<String>> getKeysMap(List<ITreeNode> nodesToDelete)
+ {
+ Map<IKeyStore, List<String>> deleteNodesMap = new HashMap<IKeyStore, List<String>>();
+ for (ITreeNode node2Delete : nodesToDelete)
+ {
+ if (node2Delete instanceof EntryNode)
+ {
+ EntryNode entryNode = (EntryNode) node2Delete;
+ IKeyStore iKeyStore = (IKeyStore) entryNode.getParent();
+ List<String> keyList = deleteNodesMap.get(iKeyStore);
+ if (keyList == null)
+ {
+ keyList = new ArrayList<String>();
+ }
+ keyList.add(entryNode.getAlias());
+ deleteNodesMap.put(iKeyStore, keyList);
+ }
+ }
+ return deleteNodesMap;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeystoreHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeystoreHandler.java
new file mode 100644
index 0000000..4188408
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeystoreHandler.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * This class deletes the keystore from the tree of the {@link KeystoreManagerView}
+ * */
+public class DeleteKeystoreHandler extends AbstractHandler2 implements IHandler2
+{
+
+ private static boolean toggleState = false;
+
+ /*
+ * Question dialog confirming deletion of the keystore with a toggle
+ * asking if the keystore should also be deleted from the filesystem
+ * @return true if the deletion is confirmed, false otherwise and true in the
+ * toggleState if it can also be deleted from the filesystem, false otherwise
+ */
+ private boolean showQuestion(List<ITreeNode> nodesToDelete)
+ {
+
+ final Boolean[] reply = new Boolean[2];
+
+ final String keystoreName =
+ nodesToDelete.size() == 1 ? nodesToDelete.get(0).getName() : null;
+
+ PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow ww = workbench.getActiveWorkbenchWindow();
+ Shell shell = ww.getShell();
+
+ MessageDialogWithToggle dialog =
+ MessageDialogWithToggle
+ .openYesNoQuestion(
+ shell,
+ CertificateManagerNLS.DeleteKeystoreHandler_ConfirmationQuestionDialog_Title,
+ keystoreName != null
+ ? CertificateManagerNLS
+ .bind(CertificateManagerNLS.DeleteKeystoreHandler_ConfirmationQuestionDialog_Description,
+ keystoreName)
+ : CertificateManagerNLS.DeleteKeystoreHandler_Delete_Selected_Keystores,
+ CertificateManagerNLS.DeleteKeystoreHandler_ConfirmationQuestionDialog_Toggle,
+ false, null, null);
+ reply[0] = (dialog.getReturnCode() == IDialogConstants.YES_ID);
+ reply[1] = dialog.getToggleState();
+ }
+ });
+
+ toggleState = reply[1];
+
+ return reply[0];
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ List<ITreeNode> nodesToDelete = getSelection();
+
+ if (!nodesToDelete.isEmpty())
+ {
+ boolean shouldProceed = showQuestion(nodesToDelete);
+ if (shouldProceed)
+ {
+ for (ITreeNode node2Delete : nodesToDelete)
+ {
+ KeyStoreNode keyStoreNode = (KeyStoreNode) node2Delete;
+
+ // remove from the tree
+ SigningAndKeysModelManager.getInstance().unmapKeyStore(keyStoreNode);
+
+ if (toggleState)
+ {
+ keyStoreNode.getFile().delete();
+ }
+ }
+ }
+ }
+
+ nodesToDelete.clear();
+
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeyStoreEntriesHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeyStoreEntriesHandler.java
new file mode 100644
index 0000000..c915318
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeyStoreEntriesHandler.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import java.util.Map;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.ui.dialogs.importks.ImportEntriesDialog;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * Handler to execute the wizard that import keys from one keystore to another.
+ * */
+public class ImportKeyStoreEntriesHandler extends AbstractHandler2
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ ITreeNode node = getSelection().get(0);
+
+ if (node instanceof IKeyStore)
+ {
+ IKeyStore keyStore = (IKeyStore) node;
+ ImportEntriesDialog dialog =
+ new ImportEntriesDialog(PlatformUI.getWorkbench().getModalDialogShellProvider()
+ .getShell(), keyStore);
+ int diagStatus = dialog.open();
+ if (diagStatus == Dialog.OK)
+ {
+ IKeyStore sourceKeyStore = dialog.getKeyStore();
+ String sourcePassword = dialog.getPassword();
+ Map<String, String> aliases = dialog.getAliases();
+ IKeyStore targetKeyStore = dialog.getTargetKeyStore();
+
+ PasswordProvider passwordProvider = targetKeyStore.getPasswordProvider();
+ String password;
+ boolean invalidPassword = false;
+ do
+ {
+ try
+ {
+ password = passwordProvider.getKeyStorePassword(true);
+ if (password != null)
+ {
+ KeyStoreUtils
+ .importKeys(targetKeyStore.getKeyStore(),
+ targetKeyStore.getFile(), targetKeyStore.getType(),
+ password.toCharArray(), sourceKeyStore.getKeyStore(),
+ sourceKeyStore.getFile(), sourcePassword.toCharArray(),
+ aliases);
+ invalidPassword = false;
+ targetKeyStore.forceReload(password.toCharArray(), true);
+ }
+ else
+ {
+ break;
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog(e);
+ }
+ catch (InvalidPasswordException e)
+ {
+ invalidPassword = true;
+ }
+ }
+ while (invalidPassword);
+
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeystoreHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeystoreHandler.java
new file mode 100644
index 0000000..6c83e66
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeystoreHandler.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.wizards.ImportKeystoreWizard;
+
+/**
+ * This class maps the keystore file into the tree of the KeyStore Manager View.
+ * */
+public class ImportKeystoreHandler extends AbstractHandler implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+
+ ImportKeystoreWizard createKeystoreWizard = new ImportKeystoreWizard();
+
+ WizardDialog dialog = new WizardDialog(shell, createKeystoreWizard);
+
+ //open the wizard to import keystores
+ //the result doesn't need to be handled as it is self-contained
+ dialog.create();
+ dialog.open();
+
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RefreshHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RefreshHandler.java
new file mode 100644
index 0000000..908f7ea
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RefreshHandler.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+
+/**
+ * Handler to execute the refresh operation.
+ * */
+public class RefreshHandler extends AbstractHandler2 implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ KeyStoreModelEventManager.getInstance().fireEvent(getSelection().get(0), EventType.REFRESH);
+
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RestoreBackupHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RestoreBackupHandler.java
new file mode 100644
index 0000000..33ada45
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RestoreBackupHandler.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.FileUtil;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.dialogs.RestoreBackupDialog;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+
+/**
+ * Handler to execute the restore backup wizard.
+ * */
+public class RestoreBackupHandler extends AbstractHandler implements IHandler
+{
+
+ Date lastBackupDate = new Date();
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ RestoreBackupDialog dialog =
+ new RestoreBackupDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow()
+ .getShell());
+
+ int diagReturn = dialog.open();
+ if (diagReturn == Dialog.OK)
+ {
+ File archiveFile = dialog.getArchiveFile();
+ File destinationFile = dialog.getDestinationDir();
+ List<String> selectedKeyStores = dialog.getSelectedKeyStores();
+
+ restoreBackup(archiveFile, destinationFile, selectedKeyStores);
+ }
+
+ return null;
+ }
+
+ private void restoreBackup(File archiveFile, File destinationFile,
+ List<String> selectedKeyStores)
+ {
+ boolean extractionSuccess = false;
+ File typePropertiesFile = new File(destinationFile, BackupHandler.KS_TYPES_FILENAME); //$NON-NLS-1$
+ try
+ {
+ extractionSuccess =
+ FileUtil.extractZipArchive(archiveFile, destinationFile,
+ Arrays.asList(new String[]
+ {
+ BackupHandler.KS_TYPES_FILENAME
+ }), new NullProgressMonitor());
+
+ extractionSuccess =
+ FileUtil.extractZipArchive(archiveFile, destinationFile, selectedKeyStores,
+ new NullProgressMonitor());
+ }
+ catch (IOException e)
+ {
+ //roll back: delete files, if they were created
+ rollBackDeleteExtractedFiles(destinationFile, selectedKeyStores);
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.RestoreBackupHandler_Error_Restoring_Backup_Title,
+ NLS.bind(
+ CertificateManagerNLS.RestoreBackupHandler_Error_Restoring_Backup_Message,
+ archiveFile),
+ new Status(
+ IStatus.ERROR,
+ CertificateManagerNLS.RestoreBackupHandler_Error_Restoring_Backup_Status,
+ CertificateManagerActivator.PLUGIN_ID, e));
+ }
+
+ if (extractionSuccess)
+ {
+ Properties properties = null;
+
+ if ((typePropertiesFile != null) && !typePropertiesFile.exists())
+ {
+ showWarningAboutNonIdentifiedKeystoreType(selectedKeyStores);
+ }
+ properties = loadTypeProperties(typePropertiesFile, properties);
+ //recover last backup date
+ getDateFromProperties(properties);
+
+ List<String> nonIdentifiedKeystoreTypes = new ArrayList<String>();
+
+ for (String keyStoreFileName : selectedKeyStores)
+ {
+ File keyStoreFile = new File(destinationFile, keyStoreFileName);
+ String ksType = null;
+ if (properties != null)
+ {
+ ksType = (String) properties.get(keyStoreFileName);
+ if (ksType == null)
+ {
+ //type not found at metadata
+ nonIdentifiedKeystoreTypes.add(keyStoreFileName);
+ }
+ }
+
+ if (ksType == null)
+ {
+ ksType = KeyStoreManager.getInstance().getDefaultType(); // set the keystore type to be the default type
+ }
+ KeyStoreNode keyStoreNode = new KeyStoreNode(keyStoreFile, ksType);
+ keyStoreNode.setLastBackupDate(lastBackupDate);
+
+ boolean map = true;
+ try
+ {
+ List<IKeyStore> keyStores = KeyStoreManager.getInstance().getKeyStores();
+ for (IKeyStore keyStore : keyStores)
+ {
+ if (keyStore.getFile().equals(keyStoreFile))
+ {
+ //updates keystore type if necessary
+ if ((ksType != null)
+ && (ksType.compareToIgnoreCase(keyStore.getType()) != 0))
+ {
+ keyStore.setType(ksType);
+ }
+ KeyStoreModelEventManager.getInstance().fireEvent((ITreeNode) keyStore,
+ EventType.COLLAPSE);
+ map = false;
+ keyStore.setLastBackupDate(lastBackupDate);
+ }
+ }
+
+ if (map)
+ {
+ SigningAndKeysModelManager.getInstance().mapKeyStore(keyStoreNode);
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.RestoreBackupHandler_Error_Mapping_Title,
+ CertificateManagerNLS.RestoreBackupHandler_Error_Mapping_Message,
+ new Status(
+ IStatus.ERROR,
+ CertificateManagerNLS.RestoreBackupHandler_Error_Mapping_Status,
+ CertificateManagerActivator.PLUGIN_ID, e));
+ if (map)
+ {
+ //roll back operation - undo mapping if keystore was mapped during backup
+ SigningAndKeysModelManager.getInstance().unmapKeyStore(keyStoreNode);
+ }
+ }
+ }
+
+ if ((nonIdentifiedKeystoreTypes != null) && !nonIdentifiedKeystoreTypes.isEmpty())
+ {
+ showWarningAboutNonIdentifiedKeystoreType(nonIdentifiedKeystoreTypes);
+ }
+
+ }
+ else
+ {
+ //roll back: delete files, if they were created
+ rollBackDeleteExtractedFiles(destinationFile, selectedKeyStores);
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.RestoreBackupHandler_Error_Restoring_Backup_Title,
+ NLS.bind(
+ CertificateManagerNLS.RestoreBackupHandler_Error_Restoring_Backup_Message,
+ archiveFile));
+ }
+ }
+
+ private void rollBackDeleteExtractedFiles(File destinationFile, List<String> selectedKeyStores)
+ {
+ //roll back: delete files, if they were created
+ File ksTypeDest = new File(destinationFile, BackupHandler.KS_TYPES_FILENAME);
+ if (ksTypeDest.exists())
+ {
+ //roll back: delete Kstypes
+ ksTypeDest.delete();
+ }
+ for (String keyStoreFileName : selectedKeyStores)
+ {
+ //roll back: delete extract files
+ File keyStoreFile = new File(destinationFile, keyStoreFileName);
+ if (keyStoreFile.exists())
+ {
+ keyStoreFile.delete();
+ }
+ }
+ }
+
+ private void getDateFromProperties(Properties properties)
+ {
+ if (properties != null)
+ {
+ //KsTypes.csv available
+ String lastString = properties.getProperty("lastBackupDate");
+ Long time = new Long(lastString);
+ lastBackupDate.setTime(time);
+ }
+ else
+ {
+ //KsTypes.csv not available
+ StudioLogger.debug("KsTypes.csv not available to get lastBackupDate properties");
+ }
+ }
+
+ /**
+ * Shows warning stating that some keystores will use default keystore type.
+ * @param selectedKeyStores
+ */
+ private void showWarningAboutNonIdentifiedKeystoreType(List<String> selectedKeyStores)
+ {
+ EclipseUtils
+ .showWarningDialog(
+ CertificateManagerNLS.RestoreBackupHandler_RestoreIssue_WarningTitle,
+ CertificateManagerNLS
+ .bind(CertificateManagerNLS.RestoreBackupHandler_RestoreIssue_MissingMetadataFile_WarningDescription,
+ selectedKeyStores, KeyStore.getDefaultType()));
+ }
+
+ private Properties loadTypeProperties(File typePropertiesFile, Properties properties)
+ {
+ if ((typePropertiesFile != null) && typePropertiesFile.exists())
+ {
+ FileInputStream propInStream = null;
+ properties = new Properties();
+ try
+ {
+ propInStream = new FileInputStream(typePropertiesFile);
+ properties.load(propInStream);
+
+ typePropertiesFile.delete();
+ }
+ catch (FileNotFoundException e)
+ {
+ properties = null;
+ }
+ catch (IOException e)
+ {
+ properties = null;
+ }
+ finally
+ {
+ if (propInStream != null)
+ {
+ try
+ {
+ propInStream.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close steam while loading type properties. "
+ + e.getMessage());
+ }
+ typePropertiesFile.delete();
+ }
+ }
+
+ }
+ return properties;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/SignExternalPackagesHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/SignExternalPackagesHandler.java
new file mode 100644
index 0000000..3551842
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/SignExternalPackagesHandler.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.jface.action.Action;
+
+import com.motorolamobility.studio.android.certmanager.ui.action.SignCreatedPackageAction;
+
+/**
+ * Handler to execute the sign package wizard.
+ * */
+public class SignExternalPackagesHandler extends AbstractHandler2 implements IHandler2
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ Action action = new SignCreatedPackageAction();
+ action.run();
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/UnsignExternalPackagesHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/UnsignExternalPackagesHandler.java
new file mode 100644
index 0000000..72ae028
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/UnsignExternalPackagesHandler.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.action.Action;
+
+import com.motorolamobility.studio.android.certmanager.ui.action.RemoveSignatureAction;
+
+/**
+ * Handler to execute the unsign package wizard.
+ * */
+public class UnsignExternalPackagesHandler extends AbstractHandler implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ Action action = new RemoveSignatureAction();
+ action.run();
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/BackwardKeystoreManager.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/BackwardKeystoreManager.java
new file mode 100644
index 0000000..319e46c
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/BackwardKeystoreManager.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.core;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.equinox.security.storage.ISecurePreferences;
+import org.eclipse.equinox.security.storage.SecurePreferencesFactory;
+import org.eclipse.equinox.security.storage.StorageException;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+
+/**
+ * Manages old MOTODEV keystore available at <user_home>\motodevstudio\tools\motodev.keystore
+ * (to keep backward compatibility)
+ */
+public class BackwardKeystoreManager
+{
+ /**
+ * MOTODEV Studio directory.
+ */
+ private static final String MOTODEV_TOOLS_PATH = File.separator
+ + "motodevstudio" + File.separator + "tools"; //$NON-NLS-1$ //$NON-NLS-2$
+
+ /**
+ * Path to user home directory.
+ */
+ private static final String USER_HOME_PATH = System.getProperty("user.home"); //$NON-NLS-1$
+
+ /**
+ * Full path where the files will be.
+ */
+ private static final String TOOLS_FULL_PATH = USER_HOME_PATH + MOTODEV_TOOLS_PATH;
+
+ private static final String KS_FILENAME_NEW = TOOLS_FULL_PATH + File.separatorChar
+ + "motodev.keystore"; //$NON-NLS-1$
+
+ /**
+ * The constant contains the keysotre type.
+ */
+ private static final String KS_TYPE = "JCEKS"; //$NON-NLS-1$
+
+ /**
+ * The constant contains the keystore password.
+ */
+ private static final String KS_DEFAULT_PASSWD = "passwd"; //$NON-NLS-1$
+
+ /**
+ * The constant contains the keystore password node on secure storage.
+ */
+ private static final String KS_PASSWD_NODE = "com.motorola.studio.platform.tools.sign.core"; //$NON-NLS-1$
+
+ /**
+ * The constant contains the keystore password attribute on secure storage.
+ */
+ private static final String KS_PASSWD_ATTRIBUTE = "kspasswd"; //$NON-NLS-1$
+
+ /*
+ * Removes old keystore password from Eclipse secure preferences (old format)
+ * @return the stored password (before removal),
+ * {@link SigningCoreConstants#KS_DEFAULT_PASSWD} if found node {@link SigningCoreConstants#KS_PASSWD_NODE} but {@link SigningCoreConstants#KS_PASSWD_ATTRIBUTE} does not exist,
+ * null if node {@link SigningCoreConstants#KS_PASSWD_NODE} not found
+ */
+ private String removeOldKeystorePassword()
+ {
+ String oldPassword = KS_DEFAULT_PASSWD;
+ ISecurePreferences preferences = SecurePreferencesFactory.getDefault();
+ ISecurePreferences node = null;
+ try
+ {
+ if (preferences.nodeExists(KS_PASSWD_NODE))
+ {
+ //old format node exists = try to get from attribute
+ node = preferences.node(KS_PASSWD_NODE);
+ try
+ {
+ oldPassword = node.get(KS_PASSWD_ATTRIBUTE, KS_DEFAULT_PASSWD);
+ }
+ catch (StorageException e)
+ {
+ oldPassword = KS_DEFAULT_PASSWD;
+ }
+ node.remove(KS_PASSWD_ATTRIBUTE);
+ preferences.remove(KS_PASSWD_NODE);
+ node.flush();
+ }
+ else
+ {
+ //node already removed => password is in the new format
+ oldPassword = null;
+ }
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(BackwardKeystoreManager.class, e.getMessage(), e);
+ }
+ return oldPassword;
+ }
+
+ /**
+ * Maps old keystore if the <user_home>\motodevstudio\tools\motodev.keystore file exists.
+ */
+ public void mapOldKeystore()
+ {
+ File motodevKeystoreFile = new File(KS_FILENAME_NEW);
+ if (motodevKeystoreFile.exists())
+ {
+ //we found backward (old default MOTODEV keystore) => import it
+ KeyStoreNode keyStoreNode = new KeyStoreNode(motodevKeystoreFile, KS_TYPE);
+
+ try
+ {
+ SigningAndKeysModelManager.getInstance().mapKeyStore(keyStoreNode);
+
+ //remove old password from keystore
+ String oldPassword = removeOldKeystorePassword();
+
+ if (oldPassword != null)
+ {
+ //oldPassword was in old format => add password for keystore in the new format
+ PasswordProvider passwordProvider =
+ new PasswordProvider(keyStoreNode.getFile());
+ passwordProvider.saveKeyStorePassword(oldPassword);
+
+ //for each child key (save the same password as the keystore to maintain backward compatibility)
+ List<IKeyStoreEntry> iKeyStoreEntries = keyStoreNode.getEntries(oldPassword);
+ if (iKeyStoreEntries != null)
+ {
+ for (IKeyStoreEntry keyStoreEntry : iKeyStoreEntries)
+ {
+ passwordProvider.savePassword(keyStoreEntry.getAlias(), oldPassword);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ //error
+ EclipseUtils.showErrorDialog(CertificateManagerNLS.bind(
+ CertificateManagerNLS.KeystoreManagerView_ErrorImportingBackwardKeystore,
+ motodevKeystoreFile), e.getMessage());
+ }
+ }
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreManager.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreManager.java
new file mode 100644
index 0000000..1d8bae6
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreManager.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreRootNode;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Provides a common interface to manipulate keystores.
+ * Other plugins need to use it (to avoid knowing {@link KeyStoreRootNode} model and {@link SaveStateManager}).
+ *
+ * The {@link KeystoreManagerView} also need to call its methods to guarantee persistence of its operations.
+ */
+public class KeyStoreManager
+{
+ public static final String KEYSTORE_TYPE_PKCS12 = "PKCS12";
+
+ public static final String KEYSTORE_TYPE_JCEKS = "JCEKS";
+
+ public static final String KEYSTORE_TYPE_JKS = "JKS";
+
+ private static final String ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE =
+ "Error to access keystore mapping persistence";
+
+ private static KeyStoreManager _instance;
+
+ private List<IKeyStore> keyStores = null;
+
+ /**
+ * This class is a singleton.
+ * @return The unique instance of this class.
+ * */
+ public synchronized static KeyStoreManager getInstance()
+ {
+ if (_instance == null)
+ {
+ _instance = new KeyStoreManager();
+ }
+ return _instance;
+ }
+
+ private KeyStoreManager()
+ {
+ }
+
+ /**
+ * Add a new keystore to the manager.
+ * @param keystore The keystore to be added.
+ * @throws KeyStoreManagerException if an error occurs while accessing persistence file where keystores are mapped.
+ */
+ public void addKeyStore(IKeyStore keystore) throws KeyStoreManagerException
+ {
+ SaveStateManager manager = null;
+ try
+ {
+ manager = SaveStateManager.getInstance();
+ manager.addEntry(keystore.getFile(), keystore.getType());
+ getKeyStores().add(keystore);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e);
+ }
+ }
+
+ /**
+ * Remove a keystore from the manager.
+ * @param keystore The keystore to be removed.
+ * @throws KeyStoreManagerException if an error occurs while accessing persistence file where keystores are mapped.
+ */
+ public void removeKeyStore(IKeyStore keystore) throws KeyStoreManagerException
+ {
+ SaveStateManager manager = null;
+ try
+ {
+ manager = SaveStateManager.getInstance();
+ manager.removeEntry(keystore.getFile());
+ getKeyStores().remove(keystore);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e);
+ }
+ }
+
+ /**
+ * Set the date which the keystore was added to a backup file.
+ * @param keyStore The keystore to be set.
+ * @param backupDate The date of the backup.
+ * @throws KeyStoreManagerException If there were problems while persisting the information.
+ * */
+ public void setBackupDate(IKeyStore keyStore, Date backupDate) throws KeyStoreManagerException
+ {
+ if ((keyStore != null) && (backupDate != null))
+ {
+ try
+ {
+ SaveStateManager manager = SaveStateManager.getInstance();
+ manager.setBackupDate(keyStore.getFile(), backupDate);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e);
+ }
+ }
+ }
+
+ /**
+ * Update the type of a managed keystore, using solely the information provided by the keystore.
+ * @param keystore The keystore which type needs to be updated.
+ * @throws KeyStoreManagerException If there were problems while persisting the information.
+ * */
+ public void updateKeyStoreType(IKeyStore keyStore) throws KeyStoreManagerException
+ {
+ SaveStateManager manager;
+ try
+ {
+ manager = SaveStateManager.getInstance();
+ if (manager.isKeystoreMapped(keyStore.getFile()))
+ {
+ manager.addEntry(keyStore.getFile(), keyStore.getType());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e);
+ }
+
+ }
+
+ /**
+ * @return The list of mapped keystores in the persistence, or empty list if there is no keystore mapped.
+ * @throws KeyStoreManagerException if an error occurs to access persistence file where keystores are mapped.
+ */
+ public List<IKeyStore> getKeyStores() throws KeyStoreManagerException
+ {
+ if (keyStores == null)
+ {
+ keyStores = new ArrayList<IKeyStore>();
+ SaveStateManager manager = null;
+ try
+ {
+ manager = SaveStateManager.getInstance();
+ if (manager.getMappedKeystores() != null)
+ {
+ for (File keystoreFile : manager.getMappedKeystores())
+ {
+ SaveStateManager.ViewStateEntry stateEntry = manager.getEntry(keystoreFile);
+ if (stateEntry != null)
+ {
+ IKeyStore keyStoreNode = new KeyStoreNode(keystoreFile);
+ keyStoreNode.setType(stateEntry.getKeystoreType());
+ keyStoreNode.setLastBackupDate(stateEntry.getBackupDate());
+ keyStores.add(keyStoreNode);
+ }
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e);
+ }
+ }
+ return keyStores;
+ }
+
+ /**
+ * Check if a keystore file is already mapped.
+ * The input parameter is a File, instead of a String, to ensure that File.getCanonicalPath() will be used in the filenames comparison.
+ * @param keystoreFile A file representing the keystore.
+ * @return True if the file is already mapped, false otherwise.
+ * */
+ public boolean isKeystoreMapped(File keystoreFile)
+ {
+ boolean result = false;
+ SaveStateManager manager = null;
+
+ try
+ {
+ manager = SaveStateManager.getInstance();
+ if (manager.getMappedKeystores() != null)
+ {
+ for (File mappedKeystoreFile : manager.getMappedKeystores())
+ {
+ if (mappedKeystoreFile.getCanonicalPath().equals(
+ keystoreFile.getCanonicalPath()))
+ {
+ result = true;
+ break;
+ }
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ result = false;
+ StudioLogger
+ .error(getClass(),
+ "IOException while trying to check if a file is mapped on Signing and Keys view.");
+ }
+
+ return result;
+ }
+
+ /**
+ * The current available keystore types are:
+ * <ul>
+ * <li>JKS</li>
+ * <li>JCEKS</li>
+ * <li>PKCS12</li>
+ * </ul>
+ * @return The list of available keystore types.
+ * */
+ public List<String> getAvailableTypes()
+ {
+ List<String> availableKeystoreTypes = new ArrayList<String>();
+
+ availableKeystoreTypes.add(KEYSTORE_TYPE_JKS);
+ availableKeystoreTypes.add(KEYSTORE_TYPE_JCEKS);
+ availableKeystoreTypes.add(KEYSTORE_TYPE_PKCS12);
+
+ if (!availableKeystoreTypes.contains(getDefaultType()))
+ {
+ availableKeystoreTypes.add(getDefaultType());
+ }
+
+ return availableKeystoreTypes;
+ }
+
+ /**
+ * When no store type is specified, the manager define a type that should be used as the default one.
+ * @return The default keystore type used in the Signing and Keys view.
+ * */
+ public String getDefaultType()
+ {
+ return KeyStore.getDefaultType().toUpperCase();
+ }
+
+ /**
+ * Create a new keystore given a file, a store type and a password.
+ */
+ public static IKeyStore createKeyStore(File keyStoreFile, String keyStoreType, char[] password)
+ throws KeyStoreManagerException
+ {
+ IKeyStore keyStoreNode = null;
+ try
+ {
+ KeyStore keyStore = KeyStoreUtils.createKeystore(keyStoreFile, keyStoreType, password);
+ keyStoreNode = new KeyStoreNode(keyStoreFile, keyStore);
+ }
+ catch (InvalidPasswordException e)
+ {
+ StudioLogger.error("Invalid password when creating a keystore: " + e.getMessage());
+ }
+ return keyStoreNode;
+ }
+
+ /**
+ * Create a new keystore given a file and a password.
+ * The store type is set to be the default.
+ */
+ public static IKeyStore createKeyStore(File keyStoreFile, char[] password)
+ throws KeyStoreManagerException
+ {
+ IKeyStore keyStoreNode = null;
+ try
+ {
+ KeyStore keyStore = KeyStoreUtils.createKeystore(keyStoreFile, password);
+ keyStoreNode = new KeyStoreNode(keyStoreFile, keyStore);
+ }
+ catch (InvalidPasswordException e)
+ {
+ StudioLogger.error("Invalid password when creating a keystore: " + e.getMessage());
+ }
+
+ return keyStoreNode;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtils.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtils.java
new file mode 100644
index 0000000..46f6fc5
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtils.java
@@ -0,0 +1,686 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.core;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStore.Builder;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.PasswordProtection;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStore.ProtectionParameter;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Map;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.X500NameBuilder;
+import org.bouncycastle.asn1.x500.style.BCStrictStyle;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.bc.BcContentSignerBuilder;
+import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.eclipse.osgi.util.NLS;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.FileUtil;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.CertificateDetailsInfo;
+
+public class KeyStoreUtils
+{
+ private static final String ERROR_DELETING_ALIAS =
+ CertificateManagerNLS.KeyStoreUtils_ErrorDeletingAlias;
+
+ /**
+ * Creates a new empty KeyStore, from the default type, located at keyStoreFile with the password, password
+ * @param keyStoreFile The file pointing o where the new KeyStore will be located
+ * @param password the password for the new KeyStore
+ * @return the {@link KeyStore} representing the new KeyStore
+ * @throws InvalidPasswordException
+ * @throws KeyStoreException if KeyStore can't be created
+ */
+ public static KeyStore createKeystore(File keyStoreFile, char[] password)
+ throws KeyStoreManagerException, InvalidPasswordException
+ {
+ return createKeystore(keyStoreFile, KeyStore.getDefaultType(), password);
+ }
+
+ /**
+ * Creates a new empty KeyStore, located at keyStoreFile with the password, password
+ * @param keyStoreFile The file pointing o where the new KeyStore will be located
+ * @param keyStoreType The type of the new KeyStore
+ * @param password the password for the new KeyStore
+ * @return the {@link KeyStore} representing the new KeyStore
+ * @throws InvalidPasswordException
+ * @throws KeyStoreException if KeyStore can't be created
+ */
+ public static KeyStore createKeystore(File keyStoreFile, String keyStoreType, char[] password)
+ throws KeyStoreManagerException, InvalidPasswordException
+ {
+ KeyStore keyStore = null;
+ if ((keyStoreFile != null) && !keyStoreFile.exists())
+ {
+ keyStore = loadKeystore(keyStoreFile, password, keyStoreType);
+ try
+ {
+ writeKeyStore(keyStore, password, keyStoreFile);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(NLS.bind(
+ CertificateManagerNLS.KeyStoreUtils_Error_WriteKeyStore, keyStoreFile), e);
+ }
+ }
+ else
+ {
+ throw new KeyStoreManagerException(NLS.bind(
+ CertificateManagerNLS.KeyStoreUtils_Error_FileAlreadyExists, keyStoreFile));
+ }
+
+ return keyStore;
+ }
+
+ public static void writeKeyStore(KeyStore keyStore, char[] password, File keyStoreFile)
+ throws FileNotFoundException, KeyStoreException, IOException, NoSuchAlgorithmException,
+ CertificateException, KeyStoreManagerException, InvalidPasswordException
+ {
+
+ writeKeyStore(keyStore, null, password, keyStoreFile);
+ }
+
+ private static void writeKeyStore(KeyStore keyStore, char[] oldPassword, char[] newPassword,
+ File keyStoreFile) throws FileNotFoundException, KeyStoreException, IOException,
+ NoSuchAlgorithmException, CertificateException, KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ FileOutputStream fos = null;
+ try
+ {
+ if (oldPassword != null)
+ {
+ if (loadKeystore(keyStoreFile, oldPassword, keyStore.getType()) != null)
+ {
+ fos = new FileOutputStream(keyStoreFile);
+ keyStore.store(fos, newPassword);
+ }
+ }
+ else
+ {
+ fos = new FileOutputStream(keyStoreFile);
+ keyStore.store(fos, newPassword);
+ }
+ }
+ finally
+ {
+ if (fos != null)
+ {
+ try
+ {
+ fos.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close steam while writing keystore file. "
+ + e.getMessage());
+ }
+ }
+ }
+ }
+
+ /**
+ * Loads a KeyStore from a given file from the default type, usually JKS.
+ * If keyStoreFile path don't exist then a new empty KeyStore will be created on the given location.
+ * <b>Note:</b> Calling this method is the same as calling loadKeystore(keyStoreFile, password, KeyStore.getDefaultType())
+ * @param keyStoreFile The keyStore location.
+ * @param password The KeyStore password
+ * @return the {@link KeyStore} representing the file.
+ * @throws KeyStoreManagerException
+ * @throws InvalidPasswordException
+ */
+ public static KeyStore loadKeystore(File keyStoreFile, char[] password)
+ throws KeyStoreManagerException, InvalidPasswordException
+ {
+ return loadKeystore(keyStoreFile, password, KeyStore.getDefaultType());
+ }
+
+ /**
+ * Loads a KeyStore from a given file.
+ * If keyStoreFile path don't exist then a new empty KeyStore will be created on memory.
+ * If you want o create a new KeyStore file, calling createStore is recommended.
+ * @param keyStoreFile The keyStore location.
+ * @param password The KeyStore password
+ * @param storeType The Type of the keystore o be loaded.
+ * @return the {@link KeyStore} representing the file.
+ * @throws KeyStoreManagerException
+ * @throws InvalidPasswordException
+ */
+ public static KeyStore loadKeystore(File keyStoreFile, char[] password, String storeType)
+ throws KeyStoreManagerException, InvalidPasswordException
+ {
+ KeyStore keyStore = null;
+ FileInputStream fis = null;
+ try
+ {
+ keyStore = KeyStore.getInstance(storeType);
+
+ if ((keyStoreFile != null) && keyStoreFile.exists() && (keyStoreFile.length() > 0))
+ {
+ fis = new FileInputStream(keyStoreFile);
+ }
+
+ //fis = null means a new keyStore will be created
+ keyStore.load(fis, password);
+ }
+ catch (IOException e)
+ {
+ if (e.getMessage().contains("password was incorrect")
+ || (e.getCause() instanceof UnrecoverableKeyException))
+ {
+ throw new InvalidPasswordException(e.getMessage());
+ }
+ else
+ {
+ throw new KeyStoreManagerException(NLS.bind(
+ CertificateManagerNLS.KeyStoreUtils_Error_LoadKeyStore, keyStoreFile), e);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(NLS.bind(
+ CertificateManagerNLS.KeyStoreUtils_Error_LoadKeyStore, keyStoreFile), e);
+ }
+ finally
+ {
+ if (fis != null)
+ {
+ try
+ {
+ fis.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close steam while loading keystore. "
+ + e.getMessage());
+ }
+ }
+ }
+
+ return keyStore;
+ }
+
+ /**
+ * Simply deletes the KeyStore File
+ * @param keyStoreFile teh KeyStore file to be deleted.
+ * @throws KeyStoreException If any error occur.
+ */
+ public static void deleteKeystore(File keyStoreFile) throws KeyStoreManagerException
+ {
+ try
+ {
+ FileUtil.deleteFile(keyStoreFile);
+ }
+ catch (IOException e)
+ {
+ throw new KeyStoreManagerException(NLS.bind(
+ CertificateManagerNLS.KeyStoreUtils_Error_DeleteKeyStore, keyStoreFile), e);
+ }
+ }
+
+ /**
+ * Write the keyStore in to the given file, protecting it with password.
+ * Warn: Since there's actually no way to change the password this method will overwrite the existing file with the keyStore contents,
+ * without further warning.
+ * @param keyStore the {@link KeyStore} to be written.
+ * @param keyStoreFile The KeyStore location
+ * @param oldPassword
+ * @param sourcePassword the new Password
+ * @throws KeyStoreException If file could no be write.
+ */
+ public static void changeKeystorePasswd(KeyStore keyStore, File keyStoreFile,
+ char[] oldPassword, char[] newPassword) throws KeyStoreManagerException
+ {
+ try
+ {
+ keyStore = loadKeystore(keyStoreFile, oldPassword, keyStore.getType());
+ writeKeyStore(keyStore, oldPassword, newPassword, keyStoreFile);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(NLS.bind(
+ CertificateManagerNLS.KeyStoreUtils_Error_WriteKeyStore, keyStoreFile), e);
+ }
+ }
+
+ /**
+ * Adds a new enty to a given keyStore.
+ * @param keyStore The Keystore that will receive the entry
+ * @param keyStorePassword The KeyStore password
+ * @param keyStoreFile The KeyStore file path
+ * @param alias The new entry alias
+ * @param entry The Entry to be added
+ * @param entryPassword The password to protect the entry
+ * @throws KeyStoreManagerException if any error occurs.
+ */
+ public static void addEntry(KeyStore keyStore, char[] keyStorePassword, File keyStoreFile,
+ String alias, Entry entry, char[] entryPassword) throws KeyStoreManagerException
+ {
+ try
+ {
+ PasswordProtection passwordProtection = new KeyStore.PasswordProtection(entryPassword);
+ keyStore = loadKeystore(keyStoreFile, keyStorePassword, keyStore.getType());
+
+ if (!keyStore.containsAlias(alias))
+ {
+ keyStore.setEntry(alias, entry, passwordProtection);
+ writeKeyStore(keyStore, keyStorePassword, keyStoreFile);
+ }
+ else
+ {
+ throw new KeyStoreManagerException(NLS.bind("Alias \"{0}\" already exists.", alias));
+ }
+
+ }
+ catch (KeyStoreManagerException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(NLS.bind(
+ CertificateManagerNLS.KeyStoreUtils_Error_AddEntryToKeyStore, alias), e);
+ }
+ }
+
+ /**
+ * Adds a new enty to a given keyStore.
+ * @param keyStore The Keystore that will receive the entry
+ * @param keyStorePassword The KeyStore password
+ * @param keyStoreFile The KeyStore file path
+ * @param alias The new entry alias
+ * @param entry The Entry to be added
+ * @param entryPassword The password to protect the entry
+ * @throws KeyStoreManagerException if any error occurs.
+ */
+ public static void changeEntryPassword(KeyStore keyStore, char[] keyStorePassword,
+ File keyStoreFile, String alias, Entry entry, char[] entryPassword)
+ throws KeyStoreManagerException
+ {
+ try
+ {
+ PasswordProtection passwordProtection = new KeyStore.PasswordProtection(entryPassword);
+ keyStore.setEntry(alias, entry, passwordProtection);
+ writeKeyStore(keyStore, keyStorePassword, keyStoreFile);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(NLS.bind(
+ "Error attempting to change password for {0}", alias), e);
+ }
+ }
+
+ /**
+ * Create a new X509 certificate for a given KeyPair
+ * @param keyPair the {@link KeyPair} used to create the certificate,
+ * RSAPublicKey and RSAPrivateKey are mandatory on keyPair, IllegalArgumentExeption will be thrown otherwise.
+ * @param issuerName The issuer name to be used on the certificate
+ * @param ownerName The owner name to be used on the certificate
+ * @param expireDate The expire date
+ * @return The {@link X509Certificate}
+ * @throws IOException
+ * @throws OperatorCreationException
+ * @throws CertificateException
+ */
+ public static X509Certificate createX509Certificate(KeyPair keyPair,
+ CertificateDetailsInfo certDetails) throws IOException, OperatorCreationException,
+ CertificateException
+ {
+
+ PublicKey publicKey = keyPair.getPublic();
+ PrivateKey privateKey = keyPair.getPrivate();
+ if (!(publicKey instanceof RSAPublicKey) || !(privateKey instanceof RSAPrivateKey))
+ {
+ throw new IllegalArgumentException(
+ CertificateManagerNLS.KeyStoreUtils_RSA_Keys_Expected);
+ }
+
+ RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
+ RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
+
+ //Transform the PublicKey into the BouncyCastle expected format
+ ASN1InputStream asn1InputStream = null;
+ X509Certificate x509Certificate = null;
+
+ try
+ {
+ asn1InputStream =
+ new ASN1InputStream(new ByteArrayInputStream(rsaPublicKey.getEncoded()));
+ SubjectPublicKeyInfo pubKey =
+ new SubjectPublicKeyInfo((ASN1Sequence) asn1InputStream.readObject());
+
+ X500NameBuilder nameBuilder = new X500NameBuilder(new BCStrictStyle());
+ addField(BCStyle.C, certDetails.getCountry(), nameBuilder);
+ addField(BCStyle.ST, certDetails.getState(), nameBuilder);
+ addField(BCStyle.L, certDetails.getLocality(), nameBuilder);
+ addField(BCStyle.O, certDetails.getOrganization(), nameBuilder);
+ addField(BCStyle.OU, certDetails.getOrganizationUnit(), nameBuilder);
+ addField(BCStyle.CN, certDetails.getCommonName(), nameBuilder);
+
+ X500Name subjectName = nameBuilder.build();
+ X500Name issuerName = subjectName;
+ X509v3CertificateBuilder certBuilder =
+ new X509v3CertificateBuilder(issuerName, BigInteger.valueOf(new SecureRandom()
+ .nextInt()), GregorianCalendar.getInstance().getTime(),
+ certDetails.getExpirationDate(), subjectName, pubKey);
+
+ AlgorithmIdentifier sigAlgId =
+ new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA"); //$NON-NLS-1$
+ AlgorithmIdentifier digAlgId =
+ new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+ BcContentSignerBuilder sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
+
+ //Create RSAKeyParameters, the private key format expected by Bouncy Castle
+ RSAKeyParameters keyParams =
+ new RSAKeyParameters(true, rsaPrivateKey.getPrivateExponent(),
+ rsaPrivateKey.getModulus());
+
+ ContentSigner contentSigner = sigGen.build(keyParams);
+ X509CertificateHolder certificateHolder = certBuilder.build(contentSigner);
+
+ //Convert the X509Certificate from BouncyCastle format to the java.security format
+ JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter();
+ x509Certificate = certConverter.getCertificate(certificateHolder);
+ }
+ finally
+ {
+ if (asn1InputStream != null)
+ {
+ try
+ {
+ asn1InputStream.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream while creating X509 certificate. "
+ + e.getMessage());
+ }
+ }
+ }
+
+ return x509Certificate;
+ }
+
+ private static void addField(ASN1ObjectIdentifier objectId, String value,
+ X500NameBuilder nameBuilder)
+ {
+ if (value.length() > 0)
+ {
+ nameBuilder.addRDN(objectId, value);
+ }
+ }
+
+ /**
+ * Creates a new RSA KeyPair
+ * @return the new {@link KeyPair}
+ */
+ public static KeyPair genKeyPair() throws NoSuchAlgorithmException
+ {
+ KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); //$NON-NLS-1$
+ keyPairGen.initialize(2048); //As recommended by Android guys, key is created with 2048 bits.
+ KeyPair keyPair = keyPairGen.genKeyPair();
+ return keyPair;
+ }
+
+ /**
+ * Create a new private key entry inside the key pair
+ * @param keyPair
+ * @param x509Certificate
+ * @return
+ */
+ public static PrivateKeyEntry createPrivateKeyEntry(KeyPair keyPair,
+ X509Certificate x509Certificate)
+ {
+ Certificate[] certChain = new Certificate[]
+ {
+ x509Certificate
+ };
+ PrivateKeyEntry privateKeyEntry =
+ new KeyStore.PrivateKeyEntry(keyPair.getPrivate(), certChain);
+ return privateKeyEntry;
+ }
+
+ public static void deleteEntry(KeyStore keyStore, char[] password, File keyStoreFile,
+ String alias) throws KeyStoreManagerException
+ {
+ try
+ {
+ keyStore = loadKeystore(keyStoreFile, password, keyStore.getType());
+
+ keyStore.deleteEntry(alias);
+ writeKeyStore(keyStore, password, keyStoreFile);
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(KeyStoreUtils.class, ERROR_DELETING_ALIAS + alias, e);
+ throw new KeyStoreManagerException(ERROR_DELETING_ALIAS + alias, e);
+ }
+ }
+
+ /**
+ * Change a keyStore type.
+ * @param keyStoreFile The KeyStoreFile
+ * @param password The KeyStore Password
+ * @param originalType the original Type
+ * @param destinationType the new KeyStore Type
+ * @throws KeyStoreManagerException If any error occurs, the operation will be canceled and reverted automatically.
+ * @throws InvalidPasswordException
+ */
+ public static void changeKeyStoreType(File keyStoreFile, char[] password, String originalType,
+ String destinationType, Map<String, String> aliases) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ boolean rollBack = false;
+ String timeStamp = Long.toString(Calendar.getInstance().getTimeInMillis());
+ File oldKsFile = new File(keyStoreFile.getAbsolutePath() + "_" + timeStamp);
+ oldKsFile.delete();
+ boolean renamed = false;
+ renamed = keyStoreFile.renameTo(oldKsFile);
+ if (renamed)
+ {
+ try
+ {
+ Builder oldKsBuilder =
+ KeyStore.Builder.newInstance(originalType, null, oldKsFile,
+ new PasswordProtection(password));
+ KeyStore oldKeyStore = oldKsBuilder.getKeyStore();
+
+ KeyStore newKeyStore = createKeystore(keyStoreFile, destinationType, password);
+ for (String alias : aliases.keySet())
+ {
+ ProtectionParameter protectionParameter =
+ new PasswordProtection(aliases.get(alias).toCharArray());
+ Entry entry = oldKeyStore.getEntry(alias, protectionParameter);
+ newKeyStore.setEntry(alias, entry, protectionParameter);
+ }
+ writeKeyStore(newKeyStore, password, keyStoreFile);
+ }
+ catch (InvalidPasswordException e)
+ {
+ rollBack = true;
+ StudioLogger
+ .error(KeyStoreUtils.class,
+ "Invalid password while trying to create a new keystore, changing a keyStore type.",
+ e);
+
+ }
+ catch (Exception e)
+ {
+ if (e.getMessage().contains("password was incorrect")
+ || e.getCause().getMessage().contains("password was incorrect"))
+ {
+ keyStoreFile.delete();
+ oldKsFile.renameTo(keyStoreFile);
+ throw new InvalidPasswordException(e.getMessage());
+ }
+ else
+ {
+ StudioLogger.error(KeyStoreUtils.class,
+ "Exception occurred while attempting to change a keyStore type.", e);
+ rollBack = true;
+ }
+ }
+
+ if (rollBack)
+ {
+ keyStoreFile.delete();
+ oldKsFile.renameTo(keyStoreFile);
+
+ throw new KeyStoreManagerException(NLS.bind(
+ "Could not convert the KeyStore {0} to type {1}", keyStoreFile,
+ destinationType));
+ }
+ }
+ else
+ {
+ throw new KeyStoreManagerException(
+ NLS.bind(
+ "Could not convert the KeyStore {0} to type {1}, could not backup the current keyStore file, maybe it's in use by another program.",
+ keyStoreFile, destinationType));
+ }
+ oldKsFile.delete();
+ }
+
+ /**
+ * Import a set of entries from sourcekeystore into the targetkeystore.
+ * If alias already exists on the target keystore then the alias is concatenated with the
+ * source keystore file name.
+ * @param targetKeyStore
+ * @param targetFile
+ * @param targetType
+ * @param targetPasswd
+ * @param sourceKeyStore
+ * @param sourceKeyStoreFile
+ * @param sourcePasswd
+ * @param aliases a map<String, String> containing alias as key and its password as value. this method assume that the password is correct
+ * @throws InvalidPasswordException
+ * @throws KeyStoreManagerException
+ */
+ public static void importKeys(KeyStore targetKeyStore, File targetFile, String targetType,
+ char[] targetPasswd, KeyStore sourceKeyStore, File sourceKeyStoreFile,
+ char[] sourcePasswd, Map<String, String> aliases) throws InvalidPasswordException,
+ KeyStoreManagerException
+ {
+ if (!isValidKeyStorePasswd(targetFile, targetType, targetPasswd))
+ {
+ throw new InvalidPasswordException(
+ CertificateManagerNLS.PasswordChanged_InvalidKeystorePassword);
+ }
+
+ try
+ {
+ for (String alias : aliases.keySet())
+ {
+ if (sourceKeyStore.containsAlias(alias))
+ {
+ ProtectionParameter protectionParameter =
+ new PasswordProtection(aliases.get(alias).toCharArray());
+ Entry entry = sourceKeyStore.getEntry(alias, protectionParameter);
+ if (targetKeyStore.containsAlias(alias))
+ {
+ alias += "_" + sourceKeyStoreFile.getName();
+ }
+ int i = 1;
+ while (targetKeyStore.containsAlias(alias))
+ {
+ alias += "_" + i;
+ i++;
+ }
+ targetKeyStore.setEntry(alias, entry, protectionParameter);
+ }
+ else
+ {
+ StudioLogger
+ .error(KeyStoreUtils.class,
+ NLS.bind(
+ "Alias {0} could not be imported because it doesn't exists on originKeyStore",
+ alias));
+ }
+ }
+ writeKeyStore(targetKeyStore, targetPasswd, targetFile);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException("Could not import the selected aliases into "
+ + targetFile.getName(), e);
+ }
+ }
+
+ /**
+ * Verifies if the password if valid
+ * @param keyStoreFile
+ * @param keyStoreType
+ * @param passwd
+ * @return true if password is valid, false otherwise.
+ * @throws KeyStoreManagerException
+ */
+ public static boolean isValidKeyStorePasswd(File keyStoreFile, String keyStoreType,
+ char[] passwd) throws KeyStoreManagerException
+ {
+ KeyStore keystore = null;
+ try
+ {
+ keystore = loadKeystore(keyStoreFile, passwd, keyStoreType);
+ }
+ catch (InvalidPasswordException e)
+ {
+ //Do nothing, password is invalid
+ }
+ return keystore != null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtilsTest.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtilsTest.java
new file mode 100644
index 0000000..9ec1abf
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtilsTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.bouncycastle.operator.OperatorCreationException;
+import org.junit.Test;
+
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.ui.model.CertificateDetailsInfo;
+
+public class KeyStoreUtilsTest extends TestCase
+{
+
+ File keyStoreFile = null;
+
+ private String passwd;
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ keyStoreFile = File.createTempFile("testKeystore", ".tmp");
+ passwd = "passwd";
+ super.setUp();
+ }
+
+ @Test
+ public void testCreateKeystore()
+ {
+
+ KeyStore keyStore = null;
+ try
+ {
+ keyStore = KeyStoreUtils.createKeystore(keyStoreFile, passwd.toCharArray());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ assert (false);
+ }
+ catch (InvalidPasswordException e)
+ {
+ assert (false);
+ }
+
+ assert (keyStore != null);
+ assert (keyStoreFile.length() > 0);
+
+ }
+
+ @Test
+ public void testLoadKeyStore()
+ {
+ try
+ {
+ KeyStore keyStore =
+ KeyStoreUtils.loadKeystore(keyStoreFile, passwd.toCharArray(), "JKS");
+ keyStore.aliases();
+ }
+ catch (KeyStoreException e)
+ {
+ assert false;
+ }
+ catch (KeyStoreManagerException e)
+ {
+ assert false;
+ }
+ catch (InvalidPasswordException e)
+ {
+ assert false;
+ }
+ }
+
+ @Test
+ public void testCreateCertificate()
+ {
+ try
+ {
+ KeyStore keyStore =
+ KeyStoreUtils.loadKeystore(keyStoreFile, passwd.toCharArray(), "JKS");
+
+ KeyPair keyPair = KeyStoreUtils.genKeyPair();
+ X509Certificate x509Certificate =
+ KeyStoreUtils.createX509Certificate(keyPair, new CertificateDetailsInfo("test",
+ "nome", "org", "orgUn", "testUni", "country", "Estate", "30", ""));
+
+ PrivateKeyEntry privateKeyEntry =
+ KeyStoreUtils.createPrivateKeyEntry(keyPair, x509Certificate);
+
+ KeyStoreUtils.addEntry(keyStore, passwd.toCharArray(), keyStoreFile, "aliasTest",
+ privateKeyEntry, "aliaspass".toCharArray());
+ }
+ catch (Exception e)
+ {
+ assert (false);
+ }
+ }
+
+ @Test
+ public void testChangePasswd()
+ {
+
+ KeyStore keyStore = null;
+ try
+ {
+ keyStore = KeyStoreUtils.loadKeystore(keyStoreFile, passwd.toCharArray());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ assert false;
+ }
+ catch (InvalidPasswordException e)
+ {
+ assert false;
+ }
+
+ File keyStoreFile2 = new File(keyStoreFile + "_2");
+ try
+ {
+ KeyStoreUtils.changeKeystorePasswd(keyStore, keyStoreFile2, passwd.toCharArray(),
+ "newPasswd2".toCharArray());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ assert (false);
+ }
+
+ assert (keyStore != null);
+ assert (keyStoreFile2.length() > 0);
+ }
+
+ @Test
+ public void testChangeKsType()
+ {
+ try
+ {
+ KeyStoreUtils.createKeystore(keyStoreFile, "JKS", passwd.toCharArray());
+ KeyStoreUtils.changeKeyStoreType(keyStoreFile, passwd.toCharArray(), "JKS", "JCEKS",
+ new HashMap<String, String>(0));
+ }
+ catch (KeyStoreManagerException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InvalidPasswordException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void testImportKeys()
+ {
+ File keyStoreFile1 = new File(keyStoreFile.getAbsolutePath() + "_import");
+ try
+ {
+ KeyStoreUtils.createKeystore(keyStoreFile1, "pass1".toCharArray());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InvalidPasswordException e)
+ {
+ e.printStackTrace();
+ }
+ try
+ {
+ KeyStore keyStore =
+ KeyStoreUtils.loadKeystore(keyStoreFile, passwd.toCharArray(), "JKS");
+ KeyPair keyPair = KeyStoreUtils.genKeyPair();
+ X509Certificate x509Certificate =
+ KeyStoreUtils.createX509Certificate(keyPair, new CertificateDetailsInfo("test",
+ "nome", "org", "orgUn", "testUni", "country", "Estate", "30", ""));
+
+ PrivateKeyEntry privateKeyEntry =
+ KeyStoreUtils.createPrivateKeyEntry(keyPair, x509Certificate);
+
+ KeyStoreUtils.addEntry(keyStore, passwd.toCharArray(), keyStoreFile, "aliasTest",
+ privateKeyEntry, passwd.toCharArray());
+
+ keyStore = KeyStoreUtils.loadKeystore(keyStoreFile, passwd.toCharArray(), "JKS");
+
+ Map<String, String> aliases = new HashMap<String, String>(1);
+ aliases.put("aliasTest", passwd);
+ // KeyStoreUtils.importKeys(keyStore1, keyStoreFile1, "pass1".toCharArray(), keyStore, keyStoreFile1
+ // passwd.toCharArray(), aliases);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InvalidPasswordException e)
+ {
+ e.printStackTrace();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ e.printStackTrace();
+ }
+ catch (OperatorCreationException e)
+ {
+ e.printStackTrace();
+ }
+ catch (CertificateException e)
+ {
+ e.printStackTrace();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/PasswordProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/PasswordProvider.java
new file mode 100644
index 0000000..ce73f09
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/PasswordProvider.java
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.eclipse.equinox.security.storage.ISecurePreferences;
+import org.eclipse.equinox.security.storage.SecurePreferencesFactory;
+import org.eclipse.equinox.security.storage.StorageException;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+/**
+ * This class is responsible to retrieve passwords for a keystore and its entries.
+ * Usage:
+ * Instantiate with a keyStoreFile, call the methods getPassword.
+ * If needed a dialog will be shown, asking user to type the password.
+ */
+public class PasswordProvider
+{
+
+ private static final String PREF_ROOT_NODE = CertificateManagerActivator.PLUGIN_ID
+ + "_passwords"; //$NON-NLS-1$
+
+ private static final String KS_PASSWORD_KEY = "KS_PASSWORD"; //$NON-NLS-1$
+
+ private final class KeyStorePasswdDialog extends Dialog
+ {
+ private final File keyStoreFile;
+
+ private String passwd;
+
+ private boolean savePasswd;
+
+ private Text paswordText;
+
+ private Button saveCheckBox;
+
+ private final String alias;
+
+ private KeyStorePasswdDialog(Shell parentShell, File keyStoreFile, String alias)
+ {
+ super(parentShell);
+ this.keyStoreFile = keyStoreFile;
+ this.alias = alias;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+
+ Composite mainComposite = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout(2, false);
+ mainComposite.setLayout(gridLayout);
+
+ //Creates the message
+ Label messageLabel = new Label(mainComposite, SWT.NONE);
+ GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 2);
+ messageLabel.setLayoutData(gridData);
+
+ if (this.alias.equals(KS_PASSWORD_KEY))
+ {
+ getShell().setText(CertificateManagerNLS.PasswordProvider_DialogTitle);
+ messageLabel.setText(NLS.bind(CertificateManagerNLS.PasswordProvider_MessageLabel,
+ keyStoreFile.getName()));
+ }
+ else
+ {
+ getShell().setText(CertificateManagerNLS.CertificateBlock_KeyPassword_Label);
+ messageLabel.setText(NLS.bind(
+ CertificateManagerNLS.PasswordProvider_Key_MessageLabel, alias));
+ }
+
+ //Creates the text field label
+ Label passwdLabel = new Label(mainComposite, SWT.NONE);
+ gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false);
+ passwdLabel.setLayoutData(gridData);
+ passwdLabel.setText(CertificateManagerNLS.PasswordProvider_PasswordLabel);
+
+ //Creates the password text
+ paswordText = new Text(mainComposite, SWT.BORDER | SWT.PASSWORD);
+ gridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ paswordText.setLayoutData(gridData);
+
+ //Creates the save password checkbox
+ saveCheckBox = new Button(mainComposite, SWT.CHECK);
+ saveCheckBox.setText(CertificateManagerNLS.PasswordProvider_SaveThisPassword);
+ saveCheckBox.setSelection(false);
+ gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
+ saveCheckBox.setLayoutData(gridData);
+ saveCheckBox.setVisible(KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile));
+
+ return super.createDialogArea(parent);
+ }
+
+ @Override
+ protected void okPressed()
+ {
+ passwd = paswordText.getText();
+ savePasswd = saveCheckBox.getSelection();
+ super.okPressed();
+ }
+
+ public String getPasswd()
+ {
+ return passwd;
+ }
+
+ public boolean mustSavePasswd()
+ {
+ return savePasswd;
+ }
+ }
+
+ private final File keyStoreFile;
+
+ private final ISecurePreferences securePreferences;
+
+ private boolean canSavePassword = true;
+
+ public PasswordProvider(File keyStoreFile)
+ {
+ this(keyStoreFile, KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile));
+ }
+
+ public PasswordProvider(File keyStoreFile, boolean canSavePassword)
+ {
+ this.keyStoreFile = keyStoreFile;
+ this.securePreferences = SecurePreferencesFactory.getDefault();
+ this.canSavePassword = canSavePassword;
+ }
+
+ /**
+ * Retrieves the KeyStore password.
+ * @param promptPassword whether the password entry dialog will be shown or not
+ * @param useSavedPassword whether to use the keyStore saved password
+ * @return the password string or null if user canceled the dialog
+ * @throws KeyStoreManagerException
+ */
+ public String getKeyStorePassword(boolean promptPassword, boolean useSavedPassword)
+ throws KeyStoreManagerException
+ {
+ return getPassword(KS_PASSWORD_KEY, promptPassword, useSavedPassword);
+ }
+
+ /**
+ * Retrieves the KeyStore password.
+ * This method will always attempt to retrieve the saved password.
+ * It's behavior is the same as of calling the method getPassword(promptPassword, true)
+ * @param promptPassword whether the password entry dialog will be shown or not
+ * @return the password string or null if user canceled the dialog
+ * @throws KeyStoreManagerException
+ */
+ public String getKeyStorePassword(boolean promptPassword) throws KeyStoreManagerException
+ {
+ return getPassword(KS_PASSWORD_KEY, promptPassword, true);
+ }
+
+ /**
+ * Retrieves the password for a given alias within a keyStore.
+ * This method will always attempt to retrieve the saved password.
+ * It's behavior is the same as of calling the method getPassword(promptPassword, true)
+ * @param promptPassword whether the password entry dialog will be shown or not
+ * @return the password string or null if user canceled the dialog
+ * @throws KeyStoreManagerException
+ */
+ public String getPassword(String alias, boolean promptPassword) throws KeyStoreManagerException
+ {
+ return getPassword(alias, promptPassword, true);
+ }
+
+ /**
+ * Retrieves the password for a given alias within a keyStore.
+ * This method will always attempt to retrieve the saved password.
+ * It's behavior is the same as of calling the method getPassword(promptPassword, true)
+ * @param promptPassword whether the password entry dialog will be shown or not
+ * @param useSavedPassword whether to use the keyStore saved password
+ * @return the password string or null if user canceled the dialog
+ * @throws KeyStoreManagerException
+ */
+ public String getPassword(String alias, boolean promptPassword, boolean useSavedPassword)
+ throws KeyStoreManagerException
+ {
+ String password = null;
+
+ if (useSavedPassword)
+ {
+ if (securePreferences != null)
+ {
+ String prefKey = alias;
+ password = getSavedPasswd(prefKey);
+ }
+ else
+ {
+ throw new KeyStoreManagerException(
+ CertificateManagerNLS.PasswordProvider_Error_WhileSaving);
+ }
+ }
+
+ if ((password == null) && promptPassword)
+ {
+ password = promptPassword(alias);
+ }
+
+ return password;
+ }
+
+ private String getSavedPasswd(String prefKey)
+ {
+ String password = null;
+ // Try to get the password from secure storage
+ if (securePreferences.nodeExists(PREF_ROOT_NODE))
+ {
+ ISecurePreferences node = securePreferences.node(PREF_ROOT_NODE);
+ try
+ {
+ if (node.nodeExists(keyStoreFile.getAbsolutePath()))
+ {
+ ISecurePreferences ksNode = node.node(keyStoreFile.getAbsolutePath());
+ password = ksNode.get(prefKey, null);
+ }
+ }
+ catch (StorageException e)
+ {
+ //Do nothing, password will be null.
+ }
+ }
+ return password;
+ }
+
+ private String promptPassword(final String alias) throws KeyStoreManagerException
+ {
+ final String[] result = new String[1];
+ final Boolean[] canProceed = new Boolean[1];
+
+ Display.getDefault().syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ KeyStorePasswdDialog dialog =
+ new KeyStorePasswdDialog(PlatformUI.getWorkbench()
+ .getModalDialogShellProvider().getShell(), keyStoreFile, alias);
+
+ int diagStatus = dialog.open();
+
+ if (diagStatus == Dialog.OK)
+ {
+ //Read the values from the dialog and do the actions, return passwd and save if required
+ result[0] = dialog.getPasswd();
+
+ canSavePassword = KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile);
+ canProceed[0] = dialog.mustSavePasswd();
+ }
+ else
+ {
+ //dialog cancelled
+ canProceed[0] = false;
+ result[0] = null;
+ }
+ }
+ });
+
+ if (canProceed[0] && canSavePassword)
+ {
+ if (securePreferences != null)
+ {
+ savePassword(alias, result[0]);
+ }
+ else
+ {
+ EclipseUtils.showWarningDialog(CertificateManagerNLS.PasswordProvider_DialogTitle,
+ CertificateManagerNLS.PasswordProvider_Error_WhileSaving);
+ }
+ }
+
+ return result[0];
+ }
+
+ public void saveKeyStorePassword(String password) throws KeyStoreManagerException
+ {
+ savePassword(KS_PASSWORD_KEY, password);
+ }
+
+ public void savePassword(final String alias, String password) throws KeyStoreManagerException
+ {
+ String prefKey;
+ canSavePassword = KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile);
+ if (canSavePassword) //protect from saving
+ {
+ if (alias != null)
+ {
+ prefKey = alias;
+ }
+ else
+ {
+ prefKey = KS_PASSWORD_KEY;
+ }
+
+ ISecurePreferences rootNode = securePreferences.node(PREF_ROOT_NODE);
+ try
+ {
+ ISecurePreferences ksNode = rootNode.node(keyStoreFile.getAbsolutePath());
+ ksNode.put(prefKey, password, true);
+ ksNode.flush();
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(
+ CertificateManagerNLS.PasswordProvider_Error_WhileSaving);
+ }
+ }
+ }
+
+ /**
+ * Deletes the entire node (including KS_PASSWORD_KEY and children aliases)
+ * @throws KeyStoreManagerException
+ */
+ public void deleteKeyStoreSavedPasswordNode() throws KeyStoreManagerException
+ {
+ deleteSavedPassword(null);
+ }
+
+ /**
+ * Deletes only KS_PASSWORD_KEY (not children aliases)
+ */
+ public void deleteKeyStoreSavedPassword() throws KeyStoreManagerException
+ {
+ deleteSavedPassword(KS_PASSWORD_KEY);
+ }
+
+ public void deleteSavedPassword(String alias) throws KeyStoreManagerException
+ {
+
+ ISecurePreferences ksNode = getKeyStoreNode();
+ if (ksNode != null)
+ {
+ if (alias == null)
+ {
+ ksNode.removeNode();
+ }
+ else
+ {
+ ksNode.remove(alias);
+ //if no item has no child, then we can remove the node
+ if (ksNode.keys().length == 0)
+ {
+ ksNode.removeNode();
+ }
+ }
+
+ try
+ {
+ ksNode.flush();
+ }
+ catch (IllegalStateException e)
+ {
+ //Do nothing, node has already been removed
+ }
+ catch (IOException e)
+ {
+ throw new KeyStoreManagerException(NLS.bind(
+ CertificateManagerNLS.PasswordProvider_Error_WhileRemovingPassword,
+ keyStoreFile.getName()));
+ }
+ }
+ }
+
+ /**
+ * This method will remove all saved entries for this keystore file that is not listed on the aliasList.
+ * The idea is to remove all saved passwords that makes reference to non-existant entries.
+ * @param aliasList the list of alias to be kept if available on the security keystore
+ * @throws KeyStoreManagerException if writing the security keystore fails for some reason
+ */
+ public void cleanModel(List<String> aliasList) throws KeyStoreManagerException
+ {
+ ISecurePreferences keyStoreNode = getKeyStoreNode();
+ if (keyStoreNode != null)
+ {
+ String[] savedKeys = keyStoreNode.keys();
+ for (String savedAlias : savedKeys)
+ {
+ if (!savedAlias.equals(KS_PASSWORD_KEY) && !aliasList.contains(savedAlias))
+ {
+ keyStoreNode.remove(savedAlias);
+ }
+ }
+ try
+ {
+ keyStoreNode.flush();
+ }
+ catch (IOException e)
+ {
+ throw new KeyStoreManagerException(NLS.bind(
+ CertificateManagerNLS.PasswordProvider_Error_WhileRemovingPassword,
+ keyStoreFile.getName()));
+ }
+ }
+ }
+
+ /*
+ * @return the keystore node if it exists
+ */
+ private ISecurePreferences getKeyStoreNode()
+ {
+ ISecurePreferences ksNode = null;
+ if (securePreferences.nodeExists(PREF_ROOT_NODE))
+ {
+ ISecurePreferences rootNode = securePreferences.node(PREF_ROOT_NODE);
+
+ if (rootNode.nodeExists(keyStoreFile.getAbsolutePath()))
+ {
+ ksNode = rootNode.node(keyStoreFile.getAbsolutePath());
+ }
+ }
+ return ksNode;
+ }
+
+ /**
+ * If keystore password is saved.
+ */
+ public boolean isPasswordSaved()
+ {
+ return isPasswordSaved(KS_PASSWORD_KEY);
+ }
+
+ /**
+ * If alias password is saved.
+ */
+ public boolean isPasswordSaved(String prefKey)
+ {
+ ISecurePreferences ksNode = null;
+ boolean isSaved = false;
+ if (securePreferences.nodeExists(PREF_ROOT_NODE))
+ {
+ ISecurePreferences rootNode = securePreferences.node(PREF_ROOT_NODE);
+ ksNode = rootNode.node(keyStoreFile.getAbsolutePath());
+ try
+ {
+ String value = ksNode.get(prefKey, null);
+ isSaved = value != null; //password is saved if it is not the default value (because password length should be at least 6
+ }
+ catch (StorageException e)
+ {
+ StudioLogger.debug("It was not possible to get if the " + prefKey
+ + " is saved or not");
+ isSaved = false;
+ }
+ }
+ return isSaved;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManager.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManager.java
new file mode 100644
index 0000000..f482d4c
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManager.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.core;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Saves the state of the {@link KeystoreManagerView} with:
+ * - the keystores mapped
+ * - the last backup date from a keystore
+ */
+class SaveStateManager
+{
+ private static final String FILE_COMMENT = "-- Signing and keys view persistence --";
+
+ private static final String STATE_FILENAME = "state.properties";
+
+ private final File persistenceFile = new File(System.getProperty("user.home") + File.separator
+ + "." + CertificateManagerActivator.PLUGIN_ID, STATE_FILENAME);
+
+ private static final String KEYSTORE_TYPE = "keystore_type=";
+
+ private static final String BACKUP_DATE = "backup_date=";
+
+ protected class ViewStateEntry
+ {
+ private final File keystoreFile;
+
+ private String keystoreType;
+
+ private Date backupDate;
+
+ public ViewStateEntry(File keystoreFile)
+ {
+
+ this.keystoreFile = keystoreFile;
+ }
+
+ public ViewStateEntry(File keystoreFile, String keystoreType)
+ {
+
+ this.keystoreFile = keystoreFile;
+ this.keystoreType = keystoreType;
+ }
+
+ /**
+ * @return the backupDate
+ */
+ public Date getBackupDate()
+ {
+ return backupDate;
+ }
+
+ /**
+ * @param backupDate the backupDate to set
+ */
+ public void setBackupDate(Date backupDate)
+ {
+ this.backupDate = backupDate;
+ }
+
+ /**
+ * @return the keystoreType
+ */
+ public String getKeystoreType()
+ {
+ return keystoreType;
+ }
+
+ /**
+ * @param keystoreType the keystoreType to set
+ */
+ public void setKeystoreType(String keystoreType)
+ {
+ this.keystoreType = keystoreType;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return "ViewStateEntry [keystoreFile=" + keystoreFile + ", keystoreType="
+ + keystoreType + ", backupDate=" + backupDate + "]";
+ }
+
+ /**
+ * @return the keystoreFile
+ */
+ protected File getKeystoreFile()
+ {
+ return keystoreFile;
+ }
+ }
+
+ private static SaveStateManager _instance;
+
+ /**
+ * This class is a singleton.
+ * @return The unique instance of this class.
+ * */
+ public synchronized static SaveStateManager getInstance() throws IOException
+ {
+ if (_instance == null)
+ {
+ _instance = new SaveStateManager();
+ }
+ return _instance;
+ }
+
+ private SaveStateManager() throws IOException
+ {
+ //create folder if it does not exist
+ if (!persistenceFile.getParentFile().exists())
+ {
+ persistenceFile.getParentFile().mkdirs();
+ }
+ if (!persistenceFile.exists())
+ {
+ //init file
+ persistenceFile.createNewFile();
+ store(new Properties());
+ }
+ }
+
+ private String write(ViewStateEntry entry)
+ {
+ StringBuffer buffer = new StringBuffer();
+ if (entry.getKeystoreType() != null)
+ {
+ buffer.append(KEYSTORE_TYPE + entry.getKeystoreType() + File.pathSeparator);
+ }
+ if (entry.getBackupDate() != null)
+ {
+ buffer.append(BACKUP_DATE + entry.getBackupDate().getTime());
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * List all mapped keystores.
+ * @throws IOException If there are problems loading the persistence file.
+ */
+ public Set<File> getMappedKeystores() throws IOException
+ {
+ Set<File> mappedKeystores = new HashSet<File>();
+ Properties properties = load();
+ Enumeration<Object> enumeration = properties.keys();
+ while (enumeration.hasMoreElements())
+ {
+ Object k = enumeration.nextElement();
+ if (k instanceof String)
+ {
+ String key = (String) k;
+ File keystoreFile = new File(key);
+ mappedKeystores.add(keystoreFile);
+ }
+ }
+ return mappedKeystores;
+ }
+
+ /**
+ * Get a representation of the entry saved in the persistence.
+ * @param keystoreFile The file that will have its state retrieved.
+ * @return
+ * @throws IOException If there are problems loading the persistence file.
+ */
+ public ViewStateEntry getEntry(File keystoreFile) throws IOException
+ {
+ Properties properties = load();
+ Object v = properties.get(keystoreFile.getAbsolutePath());
+ ViewStateEntry entry = null;
+ if (v instanceof String)
+ {
+ String value = (String) v;
+ StringTokenizer stringTokenizer = new StringTokenizer(value, File.pathSeparator);
+ entry = new ViewStateEntry(keystoreFile);
+ while (stringTokenizer.hasMoreTokens())
+ {
+ String token = stringTokenizer.nextToken();
+ if (token.contains(KEYSTORE_TYPE))
+ {
+ token = token.substring(KEYSTORE_TYPE.length());
+ entry.setKeystoreType(token);
+ }
+ else if (token.contains(BACKUP_DATE))
+ {
+ token = token.substring(BACKUP_DATE.length());
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(Long.parseLong(token));
+ Date date = calendar.getTime();
+ entry.setBackupDate(date);
+ }
+ }
+ }
+ return entry;
+ }
+
+ /**
+ * Check if a keystore is mapped on the persistence mechanism.
+ * @param keystoreFile The keystore to be checked.
+ * @return true if keystore mapped, false otherwise
+ * @throws IOException If there are problems loading the persistence file.
+ */
+ public boolean isKeystoreMapped(File keystoreFile) throws IOException
+ {
+ Properties properties = load();
+ return properties.containsKey(keystoreFile.getAbsolutePath());
+ }
+
+ /**
+ * Adds (maps) a keystore.
+ * @param keystoreFile The keystore to be added to the persistence mechanism.
+ * @param keystoreType The type of the keystore.
+ * @throws IOException If there are problems loading the persistence file.
+ */
+ public void addEntry(File keystoreFile, String keystoreType) throws IOException
+ {
+ ViewStateEntry stateEntry = new ViewStateEntry(keystoreFile, keystoreType);
+ addEntry(keystoreFile, stateEntry);
+ }
+
+ private void addEntry(File keystoreFile, ViewStateEntry stateEntry) throws IOException
+ {
+ Properties prop = load();
+ prop.setProperty(keystoreFile.getAbsolutePath(), write(stateEntry));
+ store(prop);
+ }
+
+ /**
+ * Removes a keystore from the persistence mechanism.
+ * @param keystoreFile
+ * @throws IOException
+ */
+ public void removeEntry(File keystoreFile) throws IOException
+ {
+ Properties properties = load();
+ properties.remove(keystoreFile.getAbsolutePath());
+ store(properties);
+ }
+
+ /**
+ * Sets backup date from a keystore
+ * @param keystoreFile The keystore file.
+ * @param backupDate The date of the backup.
+ * @throws IOException If there are problems loading the persistence file.
+ */
+ public void setBackupDate(File keystoreFile, Date backupDate) throws IOException
+ {
+ ViewStateEntry entry = getEntry(keystoreFile);
+ entry.setBackupDate(backupDate);
+ addEntry(keystoreFile, entry);
+ }
+
+ private Properties load() throws IOException
+ {
+ FileInputStream in = null;
+ Properties props = new Properties();
+
+ try
+ {
+ in = new FileInputStream(persistenceFile);
+ props.loadFromXML(in);
+ }
+ finally
+ {
+ if (in != null)
+ {
+ in.close();
+ }
+ }
+ return props;
+ }
+
+ private void store(Properties prop) throws IOException
+ {
+ FileOutputStream out = null;
+
+ try
+ {
+ out = new FileOutputStream(persistenceFile);
+ prop.storeToXML(out, FILE_COMMENT);
+ }
+ finally
+ {
+ if (out != null)
+ {
+ try
+ {
+ out.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream while saving properties. "
+ + e.getMessage());
+ }
+ }
+ }
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManagerTest.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManagerTest.java
new file mode 100644
index 0000000..9376d47
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManagerTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.core;
+
+import java.io.File;
+import java.util.Calendar;
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+/**
+ * See {@link SaveStateManager}
+ */
+public class SaveStateManagerTest extends TestCase
+{
+ private static final String JKS = "JKS";
+
+ SaveStateManager manager;
+
+ File adtKeystoreFile = null;
+
+ File motodevKeystoreFile = null;
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception
+ {
+ manager = SaveStateManager.getInstance();
+ adtKeystoreFile = new File("C:\\Users\\gdpr78\\motodevstudio\\tools\\adt.keystore");
+ motodevKeystoreFile = new File("C:\\Users\\gdpr78\\motodevstudio\\tools\\motodev.keystore");
+
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ manager.removeEntry(adtKeystoreFile);
+ manager.removeEntry(motodevKeystoreFile);
+ }
+
+ @Test
+ public void testAddEntryWithoutBackupDate()
+ {
+ try
+ {
+ manager.addEntry(adtKeystoreFile, JKS);
+
+ SaveStateManager.ViewStateEntry entry = manager.getEntry(adtKeystoreFile);
+
+ assert ((entry != null) && (entry.getKeystoreFile() != null) && entry.getKeystoreFile()
+ .equals(adtKeystoreFile));
+ assert ((entry != null) && (entry.getKeystoreType() != null) && entry.getKeystoreType()
+ .equals(JKS));
+ }
+ catch (Exception e)
+ {
+ //error
+ assert (false);
+ }
+ }
+
+ @Test
+ public void testListKeystoresMapped()
+ {
+ try
+ {
+ manager.addEntry(adtKeystoreFile, JKS);
+ manager.addEntry(motodevKeystoreFile, "JKS");
+
+ assert ((manager.getMappedKeystores() != null)
+ && (manager.getMappedKeystores().size() == 2)
+ && manager.getMappedKeystores().contains(adtKeystoreFile) && manager
+ .getMappedKeystores().contains(motodevKeystoreFile));
+ }
+ catch (Exception e)
+ {
+ //error
+ assert (false);
+ }
+ }
+
+ @Test
+ public void testSetBackupDate()
+ {
+ try
+ {
+ Date date = Calendar.getInstance().getTime();
+ manager.addEntry(adtKeystoreFile, JKS);
+ manager.setBackupDate(adtKeystoreFile, date);
+
+ SaveStateManager.ViewStateEntry entry = manager.getEntry(adtKeystoreFile);
+
+ assert ((entry != null) && (entry.getBackupDate() != null) && entry.getBackupDate()
+ .equals(date));
+ }
+ catch (Exception e)
+ {
+ //error
+ assert (false);
+ }
+ }
+
+ @Test
+ public void testIsMappedKeystore()
+ {
+ try
+ {
+ manager.addEntry(adtKeystoreFile, JKS);
+ boolean result = manager.isKeystoreMapped(adtKeystoreFile);
+ assert (result == true);
+ }
+ catch (Exception e)
+ {
+ //error
+ assert (false);
+ }
+ }
+
+ @Test
+ public void testRemoveEntry()
+ {
+ try
+ {
+ manager.addEntry(motodevKeystoreFile, "JKS");
+ assert (manager.isKeystoreMapped(motodevKeystoreFile) == true);
+
+ manager.removeEntry(motodevKeystoreFile);
+ assert (manager.isKeystoreMapped(motodevKeystoreFile) == false);
+ }
+ catch (Exception e)
+ {
+ //error
+ assert (false);
+ }
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/IKeyStoreModelListener.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/IKeyStoreModelListener.java
new file mode 100644
index 0000000..19e24a4
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/IKeyStoreModelListener.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.event;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * This interface must be implemented by listeners to events occurred on the {@link ITreeNode}.
+ */
+public interface IKeyStoreModelListener
+{
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to add a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be added.
+ */
+ public void handleNodeAdditionEvent(KeyStoreModelEvent keyStoreModeEvent);
+
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to remove a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be added.
+ */
+ public void handleNodeRemovalEvent(KeyStoreModelEvent keyStoreModeEvent);
+
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to update a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be added.
+ */
+ public void handleNodeUpdateEvent(KeyStoreModelEvent keyStoreModeEvent);
+
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to collapse a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be collapsed.
+ */
+ public void handleNodeCollapseEvent(KeyStoreModelEvent keyStoreModelEvent);
+
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to refresh a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be refreshed.
+ */
+ public void handleNodeRefreshEvent(KeyStoreModelEvent keyStoreModelEvent);
+
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to clear a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be cleared.
+ */
+ public void handleNodeClearEvent(KeyStoreModelEvent keyStoreModelEvent);
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEvent.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEvent.java
new file mode 100644
index 0000000..9ff4dd0
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEvent.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.event;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * This class represents an event occurred on the {@link ITreeNode}.
+ */
+public class KeyStoreModelEvent
+{
+ private final EventType eventType;
+
+ private final ITreeNode treeNodeItem;
+
+ /**
+ * Represents the change in the model. The {@link KeyStoreModelEvent#treeNodeItem} in each event may vary as specified below:
+ * <ul>
+ * <li>{@link EVENT_TYPE#ADD} it is the item that needs to be added</li>
+ * <li>{@link EVENT_TYPE#REMOVE} it is the item that needs to be deleted</li>
+ * <li>{@link EVENT_TYPE#UPDATE} it is the item that needs to be updated</li>
+ * </ul>
+ */
+ public enum EventType
+ {
+ ADD, REMOVE, UPDATE, COLLAPSE, REFRESH, CLEAR
+ }
+
+ /**
+ * Returns the event type.
+ * */
+ public EventType getEventType()
+ {
+ return eventType;
+ }
+
+ /**
+ * Returns the tree node item related to the event.
+ * */
+ public ITreeNode getTreeNodeItem()
+ {
+ return treeNodeItem;
+ }
+
+ /**
+ * Constructs a new event given an {@link ITreeNode} and a {@link KeyStoreModelEvent#EventType}.
+ * */
+ public KeyStoreModelEvent(ITreeNode treeNodeItem, EventType eventType)
+ {
+ this.eventType = eventType;
+ this.treeNodeItem = treeNodeItem;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEventManager.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEventManager.java
new file mode 100644
index 0000000..5e2b49b
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEventManager.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * Manager which notifies {@link IKeyStoreModelListener} registered that a {@link KeyStoreModelEvent} occurred.
+ * It is a singleton that needs to be called by the hierarchy of {@link ITreeNode} items when they modify the {@link ITreeNode}.
+ */
+public class KeyStoreModelEventManager
+{
+ private static KeyStoreModelEventManager _instance;
+
+ private final List<IKeyStoreModelListener> listeners = new ArrayList<IKeyStoreModelListener>();
+
+ private KeyStoreModelEventManager()
+ {
+ // Singleton - private default constructor prevents instantiations by other classes.
+ }
+
+ /**
+ * Return the singleton instance of KeyStoreModelEventManager.
+ * */
+ public synchronized static KeyStoreModelEventManager getInstance()
+ {
+ if (_instance == null)
+ {
+ _instance = new KeyStoreModelEventManager();
+ }
+ return _instance;
+ }
+
+ /**
+ * Add the parameter {@code listener} to the list of KeyStore event listeners.
+ * @param listener The listener to be added.
+ * */
+ public void addListener(IKeyStoreModelListener listener)
+ {
+ synchronized (listener)
+ {
+ listeners.add(listener);
+ }
+ }
+
+ /**
+ * Remove the parameter {@code listener} to the list of KeyStore event listeners.
+ * @param listener The listener to be removed.
+ * */
+ public void removeListener(IKeyStoreModelListener listener)
+ {
+ synchronized (listener)
+ {
+ listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Fire/notify/deliver the event to registered listeners.
+ * @param node {@link ITreeNode} that needs to refresh the view based on the model
+ * @param eventType Event that occurred.
+ */
+ public void fireEvent(ITreeNode treeNodeItem, KeyStoreModelEvent.EventType eventType)
+ {
+ KeyStoreModelEvent keyStoreModelEvent = new KeyStoreModelEvent(treeNodeItem, eventType);
+ synchronized (listeners)
+ {
+ if (listeners != null)
+ {
+ for (IKeyStoreModelListener listener : listeners)
+ {
+ switch (eventType)
+ {
+ case ADD:
+ listener.handleNodeAdditionEvent(keyStoreModelEvent);
+ break;
+ case REMOVE:
+ listener.handleNodeRemovalEvent(keyStoreModelEvent);
+ break;
+ case UPDATE:
+ listener.handleNodeUpdateEvent(keyStoreModelEvent);
+ break;
+ case COLLAPSE:
+ listener.handleNodeCollapseEvent(keyStoreModelEvent);
+ break;
+ case REFRESH:
+ listener.handleNodeRefreshEvent(keyStoreModelEvent);
+ break;
+ case CLEAR:
+ listener.handleNodeClearEvent(keyStoreModelEvent);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/InvalidPasswordException.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/InvalidPasswordException.java
new file mode 100644
index 0000000..66e69bc
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/InvalidPasswordException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.exception;
+
+import com.motorola.studio.android.common.exception.AndroidException;
+
+/**
+ * Exception thrown when the password to access a keystore is invalid or wrong.
+ * */
+@SuppressWarnings("serial")
+public class InvalidPasswordException extends AndroidException
+{
+
+ /*
+ * Create a new empty exception.
+ * */
+ @SuppressWarnings("unused")
+ private InvalidPasswordException()
+ {
+ //prevent methods to throw this exception without further information
+ }
+
+ /**
+ * Create a new exception with a message indicating the problem.
+ * */
+ public InvalidPasswordException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create a new exception with a message indicating the problem,
+ * and append some other exception that is being replaced by this one.
+ * */
+ public InvalidPasswordException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/KeyStoreManagerException.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/KeyStoreManagerException.java
new file mode 100644
index 0000000..4252691
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/KeyStoreManagerException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.exception;
+
+import com.motorola.studio.android.common.exception.AndroidException;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+
+/**
+ * Exception thrown when trying to access the {@link KeyStoreManager}.
+ * */
+@SuppressWarnings("serial")
+public class KeyStoreManagerException extends AndroidException
+{
+ /*
+ * Create a new empty exception.
+ * */
+ @SuppressWarnings("unused")
+ private KeyStoreManagerException()
+ {
+ //prevent methods to throw this exception without further information
+ }
+
+ /**
+ * Create a new exception with a message indicating the problem.
+ * */
+ public KeyStoreManagerException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create a new exception with a message indicating the problem,
+ * and append some other exception that is being replaced by this one.
+ * */
+ public KeyStoreManagerException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/CertificateManagerNLS.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/CertificateManagerNLS.java
new file mode 100644
index 0000000..26fc44f
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/CertificateManagerNLS.java
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.i18n;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * This class is the NLS component for Certificate Manager plug-in
+ */
+public class CertificateManagerNLS extends NLS
+{
+
+ public static String AbstractTreeNode_SavedPassword_Tooltip;
+
+ public static String AbstractTreeNode_UnsavedPassword_Tooltip;
+
+ public static String BackupDialog_Archive_Exists_Message;
+
+ public static String BackupDialog_Archive_Exists_Title;
+
+ public static String BackupDialog_Backup_File;
+
+ public static String BackupDialog_Browse;
+
+ public static String BackupDialog_Default_Message;
+
+ public static String BackupDialog_Diag_Title;
+
+ public static String BackupDialog_DialogTitle;
+
+ public static String BackupDialog_Fail_Writing_Archive_Message;
+
+ public static String BackupDialog_Fail_Writing_Archive_Title;
+
+ public static String BackupDialog_Invalid_Destination_Message;
+
+ public static String BackupDialog_Invalid_Destination_Title;
+
+ public static String BackupDialog_KeyStores;
+
+ public static String BackupDialog_Non_Absolute_Path;
+
+ public static String BackupDialog_Path;
+
+ public static String BackupDialog_Select_All;
+
+ public static String BackupDialog_Select_KeyStore;
+
+ public static String BackupHandler_Error_BackUp_Title;
+
+ public static String BackupHandler_Error_Setting_Date;
+
+ public static String BackupHandler_Error_Writing_Archive;
+
+ public static String SelectExistentKeystorePage_CheckboxText_AlsoImportIntoSigningView;
+
+ public static String SelectExistentKeystorePage_KeystorePasswordLabel;
+
+ public static String SelectExistentKeystorePage_WizardPageMessage;
+
+ public static String SelectExistentKeystorePage_WizardPageTitle;
+
+ public static String SelectExistentKeystoreWizard_BrowseExistentKeystore_PageTitle;
+
+ public static String SelectExistentKeystoreWizard_Error_InvalidPassword;
+
+ public static String SelectExistentKeystoreWizard_Error_KeystoreType;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_LOAD;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_NO_CERTIFICATE_ERROR;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_OPERATION;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_ERROR;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_ERROR;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_ERROR_REASON;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_OPERATION;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_NO_PACKAGES_SELECTED;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_LABEL;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_INVALID;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_NOT_DIRECTORY;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_NO_AVAILABLE_PACKAGES;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_EMPTY;
+
+ public static String PACKAGE_EXPORT_WIZARD_AREA_SELECT_ALL_BUTTON;
+
+ public static String PACKAGE_EXPORT_WIZARD_AREA_DESELECT_ALL_BUTTON;
+
+ public static String PasswordProvider_DialogTitle;
+
+ public static String PasswordProvider_Error_WhileRemovingPassword;
+
+ public static String PasswordProvider_Error_WhileSaving;
+
+ public static String PasswordProvider_MessageLabel;
+
+ public static String PasswordProvider_PasswordLabel;
+
+ public static String PasswordProvider_SaveThisPassword;
+
+ public static String PasswordProvider_Key_MessageLabel;
+
+ public static String RemoveExternalPackageSignaturePage_Package_Tree_Label;
+
+ public static String RestoreBackupDialog_BackUp_File;
+
+ public static String RestoreBackupDialog_BackUpFile_Not_Exist;
+
+ public static String RestoreBackupDialog_Browse_Button;
+
+ public static String RestoreBackupDialog_Default_Message;
+
+ public static String RestoreBackupDialog_Destination;
+
+ public static String RestoreBackupDialog_Dialog_Title;
+
+ public static String RestoreBackupDialog_Error_Loading_Entries;
+
+ public static String RestoreBackupDialog_Invalid_Dest_Path;
+
+ public static String RestoreBackupDialog_KeyStores;
+
+ public static String RestoreBackupDialog_Path_Group;
+
+ public static String RestoreBackupDialog_Select_All;
+
+ public static String RestoreBackupDialog_Select_KeyStore;
+
+ public static String RestoreBackupDialog_TitleArea_Message;
+
+ public static String RestoreBackupHandler_Error_Mapping_Message;
+
+ public static String RestoreBackupHandler_Error_Mapping_Status;
+
+ public static String RestoreBackupHandler_Error_Mapping_Title;
+
+ public static String RestoreBackupHandler_Error_Restoring_Backup_Message;
+
+ public static String RestoreBackupHandler_Error_Restoring_Backup_Status;
+
+ public static String RestoreBackupHandler_Error_Restoring_Backup_Title;
+
+ public static String RestoreBackupHandler_RestoreIssue_MissingMetadataFile_WarningDescription;
+
+ public static String RestoreBackupHandler_RestoreIssue_WarningTitle;
+
+ public static String READ_ONLY_TEXT;
+
+ public static String SELECTOR_MESSAGE_LOCATION_ERROR_PATH_TOO_LONG;
+
+ public static String SELECTOR_MESSAGE_LOCATION_ERROR_INVALID_DEVICE;
+
+ public static String DeleteKeystoreHandler_ConfirmationQuestionDialog_Description;
+
+ public static String DeleteKeystoreHandler_ConfirmationQuestionDialog_Title;
+
+ public static String DeleteKeystoreHandler_ConfirmationQuestionDialog_Toggle;
+
+ public static String DeleteKeystoreHandler_Delete_Selected_Keystores;
+
+ public static String ImportKeyStoreDialog_Alias_Column;
+
+ public static String ImportKeyStoreDialog_Default_Message;
+
+ public static String ImportKeyStoreDialog_Dialog_Title;
+
+ public static String ImportKeyStoreDialog_Error_Loading_Entries;
+
+ public static String ImportKeyStoreDialog_Error_Loading_Keystores;
+
+ public static String ImportKeyStoreDialog_Invalid_Keystore_Passwd;
+
+ public static String ImportKeyStoreDialog_KeyStore_Label;
+
+ public static String ImportKeyStoreDialog_Load_Button;
+
+ public static String ImportKeyStoreDialog_No_Entries_To_Import;
+
+ public static String ImportKeyStoreDialog_Passwd_Column;
+
+ public static String ImportKeyStoreDialog_Password_Label;
+
+ public static String ImportKeyStoreDialog_Select_Source_Ks;
+
+ public static String ImportKeyStoreDialog_Select_Target_Kesytore;
+
+ public static String ImportKeyStoreDialog_Source_Group;
+
+ public static String ImportKeyStoreDialog_Target_Group;
+
+ public static String ImportKeyStoreDialog_Type_SourceKs_Passwd;
+
+ public static String ImportKeyStoreDialog_Verified_Column;
+
+ public static String ImportKeyStoreDialog_Verified_Pass_Wrong;
+
+ public static String ImportKeyStoreDialog_Verified_Pass_Yes;
+
+ public static String ImportKeyStoreDialog_Wrong_Entries_Passwd;
+
+ public static String ImportKeystorePage_CouldNotImportKeystore;
+
+ public static String ImportKeystorePage_Description;
+
+ public static String ImportKeystorePage_DirectoryNotAllowedErrorMsg;
+
+ public static String ImportKeystorePage_FileDoesNotExist;
+
+ public static String ImportKeystorePage_FilenameCannotBeEmpty;
+
+ public static String ImportKeystorePage_KeystoreAlreadyMapped;
+
+ public static String ImportKeystorePage_KeystoreTypeCannotBeEmpty;
+
+ public static String ImportKeystorePage_Title;
+
+ public static String ImportKeystoreWizard_ImportKeystore;
+
+ public static String ImportKeystorePage_FileEmpty;
+
+ public static String DeleteKeyHandler_ConfirmationQuestionDialog_Description;
+
+ public static String DeleteKeyHandler_ConfirmationQuestionDialog_Title;
+
+ public static String DeleteKeyHandler_Delete_Selected_Keys;
+
+ /**
+ * The bundle location.
+ * It refers to messages.properties file inside this package
+ */
+ static
+ {
+ NLS.initializeMessages(
+ "com.motorolamobility.studio.android.certmanager.i18n.certificateManagerNLS",
+ CertificateManagerNLS.class);
+ }
+
+ public static String CertificateManagerView_ExpiresIn_ColumnName;
+
+ public static String CertificateManagerView_LastBackupDate_ColumnName;
+
+ public static String CertificateManagerView_NameAlias_ColumnName;
+
+ public static String CertificateManagerView_Type_ColumnName;
+
+ public static String CertificateManagerView_Path_ColumnName;
+
+ public static String CreateKeystorePage_ConfirmFileOverwrite;
+
+ public static String CreateKeystorePage_ConfirmPasswordInfoMsg;
+
+ public static String CreateKeystorePage_ConfirmReplaceFile;
+
+ public static String CreateKeystorePage_CouldNotSavePassword;
+
+ public static String CreateKeystorePage_CreateKeystore;
+
+ public static String CreateKeystorePage_DefaultKeystoreFilename;
+
+ public static String CreateKeystorePage_DefaultKeystoreFilenameExtension;
+
+ public static String CreateKeystorePage_ErrorCreatingKeystore;
+
+ public static String CreateKeystorePage_ErrorOnKeyStoreFileCreation;
+
+ public static String CreateKeystorePage_FilenameSyntaxError;
+
+ public static String CreateKeystorePage_KeystoreConfirmPasswordLabel;
+
+ public static String CreateKeystorePage_KeystoreFilenameBrowse;
+
+ public static String CreateKeystorePage_KeystoreFilenameLabel;
+
+ public static String CreateKeystorePage_KeystorePasswordLabel;
+
+ public static String CreateKeystorePage_KeystoreType;
+
+ public static String CreateKeystorePage_PasswordDoesNotMatch;
+
+ public static String CreateKeystorePage_PasswordMinSizeMessage;
+
+ public static String CreateKeystorePage_SaveThisPassword;
+
+ public static String CreateKeystorePage_SetKeystoreType;
+
+ public static String CreateKeystorePage_SetPasswordInfoMsg;
+
+ public static String CreateKeystorePage_UseKeystoreTypeAsExtension;
+
+ public static String CreateKeystorePage_WizardDefaultMessage;
+
+ public static String CreateKeystoreWizard_CreateNewKeyStore;
+
+ /*
+ * CertificateBlock
+ */
+ public static String CertificateBlock_AliasName;
+
+ public static String CertificateBlock_BasicInfoGroupTitle;
+
+ public static String CertificateBlock_FirstAndLastName;
+
+ public static String CertificateBlock_Organization;
+
+ public static String CertificateBlock_OrganizationUnit;
+
+ public static String CertificateBlock_CityOrLocality;
+
+ public static String CertificateBlock_StateOrProvince;
+
+ public static String CertificateBlock_ConfirmKeyPassword_Label;
+
+ public static String CertificateBlock_EnterPassword_InfoMessage;
+
+ public static String CertificateBlock_CountryCode;
+
+ public static String CertificateBlock_FieldIsEmpty;
+
+ public static String CertificateBlock_Validity;
+
+ public static String CertificateBlock_Validity_Error;
+
+ public static String CertificateBlock_ExpirationDate;
+
+ public static String CertificateBlock_KeyPassword_Label;
+
+ public static String CertificateBlock_KeyTooltip;
+
+ public static String CertificateInfoDialog_NotAvailableProperty;
+
+ public static String CertificateInfoDialog_ShellTitle;
+
+ public static String CertificateInfoDialog_UnknownCertificateKeypairType;
+
+ /*
+ * Certificate properties handler
+ */
+ public static String CertificatePropertiesHandler_ErrorGettingCertificateOrKeypairProperties;
+
+ public static String CreateKeyWizard_ErrorCreatingKey_DialogTitle;
+
+ /*
+ * Create self signed wizard page
+ */
+ public static String CreateSelfSignedCertificateWizardPage_Description;
+
+ public static String CreateSelfSignedCertificateWizardPage_Title;
+
+ public static String KeystoreManagerView_ErrorImportingBackwardKeystore;
+
+ public static String KeystoreManagerView_ErrorLoadingMappedKeystoresFromPersistence;
+
+ public static String KeyStoreModel_Error_GettingAliasesFromKeystore;
+
+ public static String KeyStoreNode_CouldNotGetKeyStorePassword;
+
+ public static String KeyStoreNode_CouldNotLoadKeystore_Tooltip;
+
+ public static String KeyStoreNode_ErrorKeystoreNotFound;
+
+ public static String KeyStoreNode_IncorrectPasswordToDeleteEntries_Error;
+
+ public static String KeyStoreNode_InvalidPassword;
+
+ public static String KeyStoreNode_KeyPairNotMapped_Message;
+
+ public static String KeyStoreNode_KeyPairNotMapped_Title;
+
+ public static String KeyStoreNode_KeyPairNotMapped_LogMessage;
+
+ public static String KeyStoreNode_KeystoreFileNotFound;
+
+ public static String KeyStoreNode_KeystoreTypeWrong_NodeStatus;
+
+ public static String KeyStoreNode_NotFoundOrIncorrectPasswordToDeleteEntry;
+
+ public static String KeyStoreNode_Password_NotNull;
+
+ public static String KeyStoreNode_UseRefresh_StatusNode;
+
+ public static String KeyStoreNode_Wrong_KeystoreType_Message;
+
+ public static String KeyStoreNode_Wrong_KeystoreType_Title;
+
+ public static String KeyStoreRootNode_Error_AlreadyMappedKeystorePath;
+
+ public static String KeyStoreUtils_RSA_Keys_Expected;
+
+ public static String KeyStoreUtils_Error_AddEntryToKeyStore;
+
+ public static String KeyStoreUtils_Error_WriteKeyStore;
+
+ public static String SIGN_WIZARD_AREA_SIGN_KEYSTORE_LABEL;
+
+ public static String SIGN_WIZARD_AREA_SIGN_KEYS_LABEL;
+
+ public static String KeyStoreUtils_Error_DeleteKeyStore;
+
+ public static String KeyStoreUtils_Error_FileAlreadyExists;
+
+ public static String KeyStoreUtils_Error_LoadKeyStore;
+
+ public static String KeyStoreUtils_ErrorDeletingAlias;
+
+ public static String CertificatePeriodExpired_Issue;
+
+ public static String CertificatePeriodNotYeatValid_Issue;
+
+ public static String ChangePasswordKeyHandler_Error_WrongOldKeyPassword;
+
+ public static String ChangePasswordKeyHandler_Wrong_Key_Password;
+
+ public static String ChangePasswordKeystoreHandler_Error_ChangingKeystorePassword;
+
+ public static String ChangePasswordKeystoreHandler_Error_WrongOldKeystorePassword;
+
+ public static String ChangePasswordKeystoreHandler_InvalidOldPassword;
+
+ public static String EntryNode_ErrorGettingCertificateFromEntry;
+
+ public static String EntryNode_NotFoundOrTypeWrong;
+
+ public static String Passwordinput_EnterOldKeystorePasssword_Message;
+
+ public static String PasswordChanged_Info_Title;
+
+ public static String PasswordChanged_Info_Message;
+
+ public static String PasswordInput_EnterOldKeyPasssword_Message;
+
+ public static String PasswordChanged_KeyInfo_Message;
+
+ public static String PasswordChanged_InvalidKeystorePassword;
+
+ public static String CertificateBlock_CreationDate;
+
+ public static String CertificateBlock_DetailedInfoGroupTitle;
+
+ public static String CertificateBlock_DetailedInfoNonEmptyFieldsRestriction;
+
+ public static String ConvertKeyStoreTypeDialog_Alias_Column;
+
+ public static String ConvertKeyStoreTypeDialog_Choose_KeyStore_Msg;
+
+ public static String ConvertKeyStoreTypeDialog_Choose_New_Type_Msg;
+
+ public static String ConvertKeyStoreTypeDialog_CouldNotLoad_Keystores_Error;
+
+ public static String ConvertKeyStoreTypeDialog_DefaultMessage;
+
+ public static String ConvertKeyStoreTypeDialog_DialogTitle;
+
+ public static String ConvertKeyStoreTypeDialog_Entries_Group;
+
+ public static String ConvertKeyStoreTypeDialog_Error_Loading_Keystore;
+
+ public static String ConvertKeyStoreTypeDialog_Incorrect_Entry_Pass;
+
+ public static String ConvertKeyStoreTypeDialog_Invalid_Keystore_Pass;
+
+ public static String ConvertKeyStoreTypeDialog_KeyStoreLabel;
+
+ public static String ConvertKeyStoreTypeDialog_Load_Button;
+
+ public static String ConvertKeyStoreTypeDialog_NewType_Label;
+
+ public static String ConvertKeyStoreTypeDialog_Original_Type_Label;
+
+ public static String ConvertKeyStoreTypeDialog_Password_Column;
+
+ public static String ConvertKeyStoreTypeDialog_Password_Label;
+
+ public static String ConvertKeyStoreTypeDialog_Verified_Column;
+
+ public static String ConvertKeyStoreTypeDialog_Verified_Pass_Wrong;
+
+ public static String ConvertKeyStoreTypeDialog_Verified_Pass_Yes;
+
+ public static String NewKeyBlock_PasswordGroupTitle;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_FILESYSTEM;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_CHOOSE;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE_SIMPLE;
+
+ public static String SignExternalPackagePage_Package_Tree_Label;
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/certificateManagerNLS.properties b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/certificateManagerNLS.properties
new file mode 100644
index 0000000..4481dee
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/certificateManagerNLS.properties
@@ -0,0 +1,285 @@
+#
+# Copyright (C) 2012 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.
+#
+
+AbstractTreeNode_SavedPassword_Tooltip=[password saved]
+AbstractTreeNode_UnsavedPassword_Tooltip=[password not saved]
+BackupDialog_Archive_Exists_Message=The chosen destination file, {0}, already exists.\nDo you want to overwrite it?
+BackupDialog_Archive_Exists_Title=File already exists.
+BackupDialog_Backup_File=Backup File
+BackupDialog_Browse=Browse...
+BackupDialog_Default_Message=Specify an archive (zip) file and the keystores that should be backed up to that archive
+BackupDialog_Diag_Title=Back Up Keystores
+BackupDialog_DialogTitle=Back up keystores
+BackupDialog_Fail_Writing_Archive_Message=Can't write to file {0}.\nVerify that the path is valid, you have the right permissions and that the file has not been opened by another program.
+BackupDialog_Fail_Writing_Archive_Title=Unable to Write Archive
+BackupDialog_Invalid_Destination_Message=The archive file is invalid. It should be a zip file.
+BackupDialog_Invalid_Destination_Title=Invalid Archive File
+BackupDialog_KeyStores=Keystores
+BackupDialog_Non_Absolute_Path=Selected path is not absolute. Backup archive will be created at:\n{0}
+BackupDialog_Path=Path:
+BackupDialog_Select_All=Select all
+BackupDialog_Select_KeyStore=Select at least one keystore.
+BackupHandler_Error_BackUp_Title=Error while creating keystore backup
+BackupHandler_Error_Setting_Date=Could not set backup dates
+BackupHandler_Error_Writing_Archive=Unable to write archive file {0}
+
+ImportKeyStoreDialog_Alias_Column=Alias
+ImportKeyStoreDialog_Default_Message=Import selected keys (entries) from one keystore to another.
+ImportKeyStoreDialog_Dialog_Title=Import Entries
+ImportKeyStoreDialog_Error_Loading_Entries=An error has occurred while attempting to load source keystore entries.
+ImportKeyStoreDialog_Error_Loading_Keystores=Could not load mapped keystores
+ImportKeyStoreDialog_Invalid_Keystore_Passwd=Invalid source keystore password.
+ImportKeyStoreDialog_KeyStore_Label=Keystore:
+ImportKeyStoreDialog_Load_Button=Load
+ImportKeyStoreDialog_No_Entries_To_Import=Select at least one entry to import
+ImportKeyStoreDialog_Passwd_Column=Password
+ImportKeyStoreDialog_Password_Label=Password:
+ImportKeyStoreDialog_Select_Source_Ks=Select a source keystore
+ImportKeyStoreDialog_Select_Target_Kesytore=Select a target keystore
+ImportKeyStoreDialog_Source_Group=Source Keystore
+ImportKeyStoreDialog_Target_Group=Target Keystore
+ImportKeyStoreDialog_Type_SourceKs_Passwd=Enter the source keystore password.
+ImportKeyStoreDialog_Verified_Column=Verified
+ImportKeyStoreDialog_Verified_Pass_Wrong=Not verified
+ImportKeyStoreDialog_Verified_Pass_Yes=Yes
+ImportKeyStoreDialog_Wrong_Entries_Passwd=Supply the correct passwords for the entries being imported.
+ImportKeystorePage_CouldNotImportKeystore=Could not import keystore
+ImportKeystorePage_Description=Import an existing keystore into Signing and Keys view.
+ImportKeystorePage_DirectoryNotAllowedErrorMsg={0} is a directory
+ImportKeystorePage_FileDoesNotExist=The keystore file {0} does not exist.
+ImportKeystorePage_FileEmpty=The keystore file {0} is empty.
+ImportKeystorePage_FilenameCannotBeEmpty=Filename cannot be empty.
+ImportKeystorePage_KeystoreAlreadyMapped=The keystore file {0} is already present in the Signing and Keys view.
+ImportKeystorePage_KeystoreTypeCannotBeEmpty=Keystore type cannot be empty.
+ImportKeystorePage_Title=Import Keystore
+ImportKeystoreWizard_ImportKeystore=Import an existing keystore into the Signing and Keys view
+DeleteKeystoreHandler_ConfirmationQuestionDialog_Description=Delete keystore {0}?\nNOTE: consider making a backup before deleting this keystore.
+DeleteKeystoreHandler_ConfirmationQuestionDialog_Title=Delete Keystore
+DeleteKeystoreHandler_ConfirmationQuestionDialog_Toggle=Delete content on disk? (Cannot be undone).
+DeleteKeystoreHandler_Delete_Selected_Keystores=Delete selected keystores?\nNOTE: consider making a backup before deleting keystores.
+
+CertificateManagerView_ExpiresIn_ColumnName=Expires on
+CertificateManagerView_LastBackupDate_ColumnName=Last backup date
+CertificateManagerView_NameAlias_ColumnName=Name (Alias)
+CertificateManagerView_Type_ColumnName=Type
+CertificateManagerView_Path_ColumnName=Path
+
+DeleteKeyHandler_ConfirmationQuestionDialog_Description=Delete key {0}? (Cannot be undone).\nNOTE: consider making a backup before deleting this key.
+DeleteKeyHandler_ConfirmationQuestionDialog_Title=Delete Key
+DeleteKeyHandler_Delete_Selected_Keys=Delete selected keys? (Cannot be undone).\nNOTE: consider making a backup before deleting this key.
+
+#------------------------------------------------------------------------------
+# Create keystore Wizard
+#------------------------------------------------------------------------------
+CreateKeystorePage_ConfirmFileOverwrite=Confirm File Overwrite
+CreateKeystorePage_ConfirmPasswordInfoMsg=Confirm the password.
+CreateKeystorePage_ConfirmReplaceFile={0} already exists.\nDo you want to replace it?
+CreateKeystorePage_CouldNotSavePassword=Could not save password
+CreateKeystorePage_CreateKeystore=Create Keystore
+CreateKeystorePage_DefaultKeystoreFilename=keystore_{0}
+CreateKeystorePage_DefaultKeystoreFilenameExtension=keystore
+CreateKeystorePage_ErrorCreatingKeystore=Error creating keystore
+CreateKeystorePage_ErrorOnKeyStoreFileCreation=Error writing file \"{0}\" to disk. Check filename syntax and file system permissions.
+CreateKeystorePage_FilenameSyntaxError=The filename, directory name, or volume label syntax is incorrect.
+CreateKeystorePage_KeystoreConfirmPasswordLabel=Confirm Password:
+CreateKeystorePage_KeystoreFilenameBrowse=Browse...
+CreateKeystorePage_KeystoreFilenameLabel=Keystore Filename:
+CreateKeystorePage_KeystorePasswordLabel=Keystore Password:
+CreateKeystorePage_KeystoreType=Keystore Type:
+CreateKeystorePage_PasswordDoesNotMatch=Password does not match.
+CreateKeystorePage_PasswordMinSizeMessage=Password must have at least {0} characters.
+CreateKeystorePage_SaveThisPassword=Save this password
+CreateKeystorePage_SetKeystoreType=Set a keystore type.
+CreateKeystorePage_SetPasswordInfoMsg=Set a keystore password.
+CreateKeystorePage_UseKeystoreTypeAsExtension=Use keystore type as keystore filename extension
+CreateKeystorePage_WizardDefaultMessage=A keystore is an encrypted file protected by a password that groups key pairs - public/private keys.
+CreateKeystoreWizard_CreateNewKeyStore=Create Keystore
+
+#------------------------------------------------------------------------------
+# CertificateBlock
+#------------------------------------------------------------------------------
+CertificateBlock_AliasName=Alias name
+CertificateBlock_BasicInfoGroupTitle=Basic Info
+CertificateBlock_FirstAndLastName=First and Last Name
+CertificateBlock_Organization=Organization
+CertificateBlock_OrganizationUnit=Organization Unit
+CertificateBlock_CityOrLocality=City or Locality
+CertificateBlock_StateOrProvince=State or Province
+CertificateBlock_ConfirmKeyPassword_Label=Confirm Password
+CertificateBlock_EnterPassword_InfoMessage=Enter keystore password
+CertificateBlock_CountryCode=Country Code (XX)
+CertificateBlock_FieldIsEmpty={0} cannot be empty.
+CertificateBlock_Validity=Validity (years)
+CertificateBlock_Validity_Error=Validity should be a positive integer value.
+CertificateBlock_ExpirationDate=Expiration Date
+CertificateBlock_KeyPassword_Label=Key Password
+CertificateBlock_KeyTooltip=Organization: {0}\nFirst and Last Name: {1}
+CertificateInfoDialog_NotAvailableProperty=Not available
+CertificateInfoDialog_ShellTitle=Key Properties
+CertificateInfoDialog_UnknownCertificateKeypairType=Unknown key type
+CertificateBlock_CreationDate=Creation Date
+CertificateBlock_DetailedInfoGroupTitle=Detailed Info
+CertificateBlock_DetailedInfoNonEmptyFieldsRestriction=Validity and at least one other piece of detailed information must be supplied.
+
+#------------------------------------------------------------------------------
+# Certificate Properties Handler
+#------------------------------------------------------------------------------
+CertificatePropertiesHandler_ErrorGettingCertificateOrKeypairProperties=Error getting key properties
+
+#------------------------------------------------------------------------------
+# Create Self Signed wizard page
+#------------------------------------------------------------------------------
+CreateKeyWizard_ErrorCreatingKey_DialogTitle=Error creating key
+CreateSelfSignedCertificateWizardPage_Description=Provide the self-signed key information. Required fields are marked with '*'.
+CreateSelfSignedCertificateWizardPage_Title=Create Self-Signed Key
+KeystoreManagerView_ErrorImportingBackwardKeystore=Could not import the old MOTODEV keystore (for backward compatibility) from {0}
+KeystoreManagerView_ErrorLoadingMappedKeystoresFromPersistence=Error loading mapped keystores
+KeyStoreModel_Error_GettingAliasesFromKeystore=Cannot get aliases from keystore {0}.
+KeyStoreNode_CouldNotGetKeyStorePassword=Could not get keystore password:
+KeyStoreNode_CouldNotLoadKeystore_Tooltip=Could not load keystore file. Use Refresh to try again.
+KeyStoreNode_ErrorKeystoreNotFound=Keystore file not found
+KeyStoreNode_IncorrectPasswordToDeleteEntries_Error=Incorrect password
+KeyStoreNode_InvalidPassword=Invalid password. Try again.
+KeyStoreNode_KeyPairNotMapped_LogMessage=Entry with alias: {0} is a key pair, which is not supported for this view.
+KeyStoreNode_KeyPairNotMapped_Message=Keystore contains unsupported entries. Check log for details.
+KeyStoreNode_KeyPairNotMapped_Title=Entry not mapped
+KeyStoreNode_KeystoreFileNotFound=Keystore file not found
+KeyStoreNode_KeystoreTypeWrong_NodeStatus=Keystore type is wrong. Re-import keystore with the correct type.
+KeyStoreNode_NotFoundOrIncorrectPasswordToDeleteEntry=Password not found or incorrect when deleting entry with alias:
+KeyStoreNode_Password_NotNull=Password cannot be null
+KeyStoreNode_UseRefresh_StatusNode=Unable to read keystore. Refresh, and try again.
+KeyStoreNode_Wrong_KeystoreType_Message=The keystore {0} has been mapped with the incorrect type JCEKS. Keystore type has been changed to the correct type JKS.
+KeyStoreNode_Wrong_KeystoreType_Title=Wrong Keystore Type
+KeyStoreRootNode_Error_AlreadyMappedKeystorePath=Keystore in path: {0} is already mapped in the view.
+KeyStoreUtils_RSA_Keys_Expected=RSA keys are expected; use RSAPublicKey and RSAPrivateKey
+KeyStoreUtils_Error_AddEntryToKeyStore=An error has ocurred while attempting to add the entry {0}
+KeyStoreUtils_Error_DeleteKeyStore=Could not delete the keystore file {0}
+KeyStoreUtils_Error_FileAlreadyExists=Keystore file {0} already exists. Choose a new file path.
+KeyStoreUtils_Error_LoadKeyStore=An error has ocurred while attempting to load the keystore file {0}
+KeyStoreUtils_Error_WriteKeyStore=An error has ocurred while attempting to write the keystore file {0}
+KeyStoreUtils_ErrorDeletingAlias=Error deleting alias:
+
+
+UNSIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION = Remove package signatures
+UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE = Package Signature Removal
+UNSIGN_EXTERNAL_PKG_WIZARD_OPERATION = Removing Signature from Package:
+UNSIGN_EXTERNAL_PKG_WIZARD_ERROR = Signatures could not be removed from the following packages
+UNSIGN_EXTERNAL_PKG_WIZARD_ERROR_REASON = Unable to write files
+SelectExistentKeystorePage_CheckboxText_AlsoImportIntoSigningView=Add keystore to Signing and Keys view
+SelectExistentKeystorePage_KeystorePasswordLabel=Keystore Password:
+SelectExistentKeystorePage_WizardPageMessage=Select an existing keystore to use for exporting.
+SelectExistentKeystorePage_WizardPageTitle=Select existing keystore
+SelectExistentKeystoreWizard_BrowseExistentKeystore_PageTitle=Browse existing keystore
+SelectExistentKeystoreWizard_Error_InvalidPassword=Invalid password. Check password again
+SelectExistentKeystoreWizard_Error_KeystoreType=Verify that the keystore type is correct and that the keystore file exists.
+SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_LABEL = Packages folder:
+SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_INVALID = The chosen folder is invalid or does not exist
+SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_NOT_DIRECTORY = The chosen source directory is not a directory
+SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION = Sign packages with the chosen key
+SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_EMPTY = Select a folder containing Android packages.
+SIGN_EXTERNAL_PKG_WIZARD_NO_CERTIFICATE_ERROR = There are no keys available. Obtain a key to sign the selected packages.
+SIGN_EXTERNAL_PKG_WIZARD_NO_AVAILABLE_PACKAGES = This folder does not contain any packages
+UNSIGN_EXTERNAL_PKG_WIZARD_NO_PACKAGES_SELECTED = Select at least one package
+SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE = Package Signing
+SIGN_EXTERNAL_PKG_WIZARD_OPERATION = Signing Package:
+SIGN_EXTERNAL_PKG_WIZARD_ERROR = The following packages could not be signed
+SIGN_EXTERNAL_PKG_WIZARD_LOAD = Load
+SIGN_EXTERNAL_PKG_WIZARD_FILESYSTEM = Filesystem...
+SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE = Workspace...
+SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE_SIMPLE = Workspace
+PACKAGE_EXPORT_WIZARD_AREA_SELECT_ALL_BUTTON = Select All
+PACKAGE_EXPORT_WIZARD_AREA_DESELECT_ALL_BUTTON = Deselect All
+SIGN_WIZARD_AREA_SIGN_KEYSTORE_LABEL = Keystore:
+SIGN_WIZARD_AREA_SIGN_KEYS_LABEL = Key:
+SIGN_EXTERNAL_PKG_WIZARD_CHOOSE=Select the directory that contains the APK
+PasswordProvider_DialogTitle=Keystore password
+PasswordProvider_Error_WhileRemovingPassword=Could not open secure Preferences. Failed to remove saved password from keystore {0}.
+PasswordProvider_Error_WhileSaving=Could not open secure Preferences. It will not be possible to save or restore passwords.
+PasswordProvider_MessageLabel=Supply the password for the keystore file: {0}.\n
+PasswordProvider_Key_MessageLabel=When signing a package you must supply the key password.\nEnter the password for the key: {0}.\n
+PasswordProvider_PasswordLabel=Password:
+PasswordProvider_SaveThisPassword=Save password
+RemoveExternalPackageSignaturePage_Package_Tree_Label=Packages to be unsigned:
+RestoreBackupDialog_BackUp_File=Backup File:
+RestoreBackupDialog_BackUpFile_Not_Exist=Selected backup file does not exist.
+RestoreBackupDialog_Browse_Button=Browse...
+RestoreBackupDialog_Default_Message=Choose an archive file and select the keystore files that you want to restore
+RestoreBackupDialog_Destination=Destination:
+RestoreBackupDialog_Dialog_Title=Restore From Backup
+RestoreBackupDialog_Error_Loading_Entries=Unable to load entries from the zip file {0}
+RestoreBackupDialog_Invalid_Dest_Path=Invalid destination path
+RestoreBackupDialog_KeyStores=Keystores
+RestoreBackupDialog_Path_Group=Paths
+RestoreBackupDialog_Select_All=Select All
+RestoreBackupDialog_Select_KeyStore=Select at least one keystore to restore from backup
+RestoreBackupDialog_TitleArea_Message=Restore keystores from a backup
+RestoreBackupHandler_Error_Mapping_Message=Unable to map restored keystores
+RestoreBackupHandler_Error_Mapping_Status=Failed to import restored keystores
+RestoreBackupHandler_Error_Mapping_Title=Error Mapping Nodes
+RestoreBackupHandler_Error_Restoring_Backup_Message=Could not restore keystores from file {0}
+RestoreBackupHandler_Error_Restoring_Backup_Status=Could not extract zip file
+RestoreBackupHandler_Error_Restoring_Backup_Title=Error while restoring backup
+RestoreBackupHandler_RestoreIssue_MissingMetadataFile_WarningDescription=Missing backup metadata file.\nIt wasn't possible to determine the type of keystore(s): {0}.\nThe default type: {1} will be assumed for each.
+RestoreBackupHandler_RestoreIssue_WarningTitle=Restore Issue
+READ_ONLY_TEXT = Read Only
+
+SELECTOR_MESSAGE_LOCATION_ERROR_INVALID_DEVICE = The device you are trying to use is invalid
+SELECTOR_MESSAGE_LOCATION_ERROR_PATH_TOO_LONG = The path is too long
+SignExternalPackagePage_Package_Tree_Label=Packages to be signed:
+
+#------------------------------------------------------------------------------
+# Tree Decoration
+#------------------------------------------------------------------------------
+CertificatePeriodExpired_Issue=Warning for Android developers: the key will expire on {0}, but Google Play requires it to expire after October 22, 2033.
+CertificatePeriodNotYeatValid_Issue=Key is not yet valid. It is only valid after {0}.
+ChangePasswordKeyHandler_Error_WrongOldKeyPassword=Old password is invalid
+ChangePasswordKeyHandler_Wrong_Key_Password=Could not retrieve the key. Make sure that the old password is correct.
+ChangePasswordKeystoreHandler_Error_ChangingKeystorePassword=Failed to change keystore password
+ChangePasswordKeystoreHandler_Error_WrongOldKeystorePassword=Old password is invalid
+ChangePasswordKeystoreHandler_InvalidOldPassword=The old password is invalid. Could not access keystore {0} to change keystore password.
+ConvertKeyStoreTypeDialog_Alias_Column=Alias
+ConvertKeyStoreTypeDialog_Choose_KeyStore_Msg=Choose a new keystore.
+ConvertKeyStoreTypeDialog_Choose_New_Type_Msg=Choose a new type for the keystore.
+ConvertKeyStoreTypeDialog_CouldNotLoad_Keystores_Error=Could not load mapped keystores
+ConvertKeyStoreTypeDialog_DefaultMessage=Select a keystore along with its new type.
+ConvertKeyStoreTypeDialog_DialogTitle=Change Keystore Type
+ConvertKeyStoreTypeDialog_Entries_Group=Entries
+ConvertKeyStoreTypeDialog_Error_Loading_Keystore=An error has occurred while attempting to load keystore entries.
+ConvertKeyStoreTypeDialog_Incorrect_Entry_Pass=Enter the password for entries with non-verified passwords.
+ConvertKeyStoreTypeDialog_Invalid_Keystore_Pass=Invalid keystore password.
+ConvertKeyStoreTypeDialog_KeyStoreLabel=Keystore:
+ConvertKeyStoreTypeDialog_Load_Button=Load
+ConvertKeyStoreTypeDialog_NewType_Label=New Type:
+ConvertKeyStoreTypeDialog_Original_Type_Label=Original Type:
+ConvertKeyStoreTypeDialog_Password_Column=Password
+ConvertKeyStoreTypeDialog_Password_Label=Password:
+ConvertKeyStoreTypeDialog_Verified_Column=Verified
+ConvertKeyStoreTypeDialog_Verified_Pass_Wrong=Wrong password
+ConvertKeyStoreTypeDialog_Verified_Pass_Yes=Yes
+EntryNode_ErrorGettingCertificateFromEntry=Error getting key from entry: {0}
+EntryNode_NotFoundOrTypeWrong=Not found or type wrong for alias: {0}
+NewKeyBlock_PasswordGroupTitle=Password
+
+#------------------------------------------------------------------------------
+# Change password
+#------------------------------------------------------------------------------
+Passwordinput_EnterOldKeystorePasssword_Message=Change the password for keystore {0}.\nThe keystore password protects they keystore's keys.
+PasswordChanged_Info_Title=Password changed
+PasswordChanged_Info_Message=The password for keystore {0} was successfully changed.
+PasswordInput_EnterOldKeyPasssword_Message=The key password protects your key.
+PasswordChanged_KeyInfo_Message=Your key password was successfully changed.
+PasswordChanged_InvalidKeystorePassword=The password for this keystore is invalid.
+ToolsException_GenericError=An unexpected error occurred. \ No newline at end of file
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/job/CreateKeyJob.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/job/CreateKeyJob.java
new file mode 100644
index 0000000..c519235
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/job/CreateKeyJob.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.job;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.composite.NewKeyBlock;
+import com.motorolamobility.studio.android.certmanager.ui.model.CertificateDetailsInfo;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+import com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeyWizard;
+
+/**
+ * Creating a key is a time expensive task.
+ * In order to not block the UI while creating the key, a new
+ * job is creating and executed in the background.
+ */
+public class CreateKeyJob extends Job
+{
+ private static final String KEY_PASSWORD_SAVED = "Key password saved";
+
+ private static final String SAVING_KEY_PASSWORD = "Saving key password";
+
+ private static final String KEY_CREATED = "Key created";
+
+ private static final String CREATING_KEY = "Creating key";
+
+ private static final String GETTING_KEY_INFO = "Getting key info";
+
+ private static final int NUMBER_OF_TASKS = 5;
+
+ /*
+ * Key block, used to retrieve information from the create key wizard.
+ */
+ private NewKeyBlock newKeyBlock = null;
+
+ /*
+ * Information to create key
+ */
+ private CertificateDetailsInfo certificateDetailsInfo = null;
+
+ private IKeyStore keystore = null;
+
+ private String keyStorePass;
+
+ public CreateKeyJob(String jobName, NewKeyBlock newKeyBlock,
+ CertificateDetailsInfo certificateDetailsInfo, IKeyStore keystore, String keyStorePass)
+ {
+ super(jobName);
+ this.certificateDetailsInfo = certificateDetailsInfo;
+ this.newKeyBlock = newKeyBlock;
+ this.keystore = keystore;
+ this.keyStorePass = keyStorePass;
+ if (this.keyStorePass == null)
+ {
+ try
+ {
+ this.keyStorePass = keystore.getPasswordProvider().getKeyStorePassword(false);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e.getMessage());
+ }
+ }
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor)
+ {
+ SubMonitor subMonitor = SubMonitor.convert(monitor);
+ subMonitor.beginTask(CREATING_KEY, NUMBER_OF_TASKS);
+
+ StudioLogger.debug(GETTING_KEY_INFO);
+ subMonitor.worked(1);
+
+ IKeyStoreEntry entryNode = null;
+ try
+ {
+ StudioLogger.debug(CREATING_KEY);
+ subMonitor.worked(1);
+ String keystorePassword = getKeyStorePassword();
+
+ if (keystorePassword != null)
+ {
+ entryNode =
+ EntryNode.createSelfSignedNode(keystore, keystorePassword,
+ certificateDetailsInfo.getAlias(), certificateDetailsInfo);
+ StudioLogger.debug(KEY_CREATED);
+ subMonitor.worked(1);
+
+ if (newKeyBlock.needToSaveKeyPassword())
+ {
+ StudioLogger.debug(SAVING_KEY_PASSWORD);
+ subMonitor.worked(1);
+ PasswordProvider passwordProvider = new PasswordProvider(keystore.getFile());
+ passwordProvider.savePassword(entryNode.getAlias(),
+ newKeyBlock.getKeyPassword());
+ StudioLogger.debug(KEY_PASSWORD_SAVED);
+ subMonitor.worked(1);
+ }
+ }
+
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.CreateKeyWizard_ErrorCreatingKey_DialogTitle,
+ e.getMessage());
+ StudioLogger.error(CreateKeyWizard.class,
+ CertificateManagerNLS.CreateKeyWizard_ErrorCreatingKey_DialogTitle, e);
+ }
+
+ subMonitor.done();
+ return Status.OK_STATUS;
+ }
+
+ private String getKeyStorePassword() throws KeyStoreManagerException
+ {
+ boolean invalidPass = true;
+ String keystorePassword = this.keyStorePass;
+
+ try
+ {
+ if (keystorePassword != null)
+ {
+ this.keystore.isPasswordValid(keystorePassword);
+ invalidPass = false;
+ }
+ }
+ catch (InvalidPasswordException e1)
+ {
+ invalidPass = true;
+ }
+ while (invalidPass)
+ {
+ try
+ {
+ this.keystore.isPasswordValid(keystorePassword);
+ invalidPass = false;
+ }
+ catch (InvalidPasswordException e)
+ {
+ invalidPass = true;
+ PasswordProvider passwordProvider = new PasswordProvider(this.keystore.getFile());
+ keystorePassword = passwordProvider.getKeyStorePassword(true, false);
+
+ if (keystorePassword == null)
+ {
+ invalidPass = false;
+ }
+ }
+ }
+
+ return keystorePassword;
+ }
+
+ public String getCreatedKeyAlias()
+ {
+ return this.certificateDetailsInfo.getAlias();
+ }
+
+ public IKeyStore getKeyStore()
+ {
+ return this.keystore;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/PackageFile.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/PackageFile.java
new file mode 100644
index 0000000..27a565d
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/PackageFile.java
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.packaging;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.CRC32;
+
+import org.eclipse.core.runtime.IBundleGroup;
+import org.eclipse.core.runtime.IBundleGroupProvider;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+
+import com.motorola.studio.android.common.IAndroidConstants;
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.AndroidUtils;
+import com.motorola.studio.android.common.utilities.FileUtil;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+
+/**
+ * This class is an in-memory package file representation.
+ */
+public class PackageFile
+{
+ private static final String COM_MOTOROLA_STUDIO_ANDROID_FEATURE =
+ "com.motorola.studio.android.feature";
+
+ /*
+ * Map of entries contained in this package file
+ */
+ private final Map<String, File> entryMap = new HashMap<String, File>();
+
+ /*
+ * Map of temporary entries contained in this package file (it duplicates
+ * the entries on entryMap)
+ */
+ private final Map<String, File> tempEntryMap = new HashMap<String, File>();
+
+ /*
+ * Package manifest
+ */
+ private Manifest manifest;
+
+ private int apiVersion;
+
+ private String targetName;
+
+ private Set<String> rawFiles = new HashSet<String>();
+
+ /**
+ * Creates an empty PackageFile.
+ *
+ * @param createdBy
+ * Created-By manifest attribute
+ */
+ public PackageFile(String createdBy)
+ {
+ targetName = "";
+ apiVersion = -1;
+ manifest = createManifest(createdBy);
+ }
+
+ /**
+ * Creates an empty PackageFile
+ *
+ * @param createdBy
+ * Created-By manifest attribute
+ */
+ public PackageFile(String createdBy, String targetName, int apiVersion)
+ {
+ this.targetName = targetName;
+ this.apiVersion = apiVersion;
+ manifest = createManifest(createdBy);
+ }
+
+ /**
+ * Creates a PackageFile from an existing JarFile
+ *
+ * @param jarFile
+ * the base jar file
+ * @param apiVersion
+ * @param targetName
+ * @throws IOException
+ * if an I/O error occurs when reading the contents of the base
+ * jar file
+ */
+ public PackageFile(JarFile jarFile) throws IOException
+ {
+ this(jarFile, "", -1);
+ }
+
+ /**
+ * Creates a PackageFile from an existing JarFile
+ *
+ * @param jarFile
+ * the base jar file
+ * @param apiVersion
+ * @param targetName
+ * @throws IOException
+ * if an I/O error occurs when reading the contents of the base
+ * jar file
+ */
+ public PackageFile(JarFile jarFile, String targetName, int apiVersion) throws IOException
+ {
+ manifest = jarFile.getManifest();
+ this.targetName = targetName;
+ this.apiVersion = apiVersion;
+ String createdBy = generateStudioFingerprint();
+ if (manifest == null)
+ {
+ manifest = createManifest(createdBy);
+ }
+
+ // go through all the entries in the base jar file
+ Enumeration<JarEntry> entryEnum = jarFile.entries();
+
+ while (entryEnum.hasMoreElements())
+ {
+ JarEntry entry = entryEnum.nextElement();
+ if (!entry.getName().equalsIgnoreCase(
+ CertificateManagerActivator.METAFILES_DIR
+ + CertificateManagerActivator.JAR_SEPARATOR
+ + CertificateManagerActivator.MANIFEST_FILE_NAME))
+ {
+ // create a temporary file for this entry
+ InputStream is = jarFile.getInputStream(entry);
+ File tempFile =
+ File.createTempFile(CertificateManagerActivator.TEMP_FILE_PREFIX, null);
+ tempFile.deleteOnExit();
+
+ // copy contents from the original file to the temporary file
+ BufferedInputStream bis = null;
+ BufferedOutputStream bos = null;
+
+ try
+ {
+ bis = new BufferedInputStream(is);
+ bos = new BufferedOutputStream(new FileOutputStream(tempFile));
+
+ int c;
+ while ((c = bis.read()) >= 0)
+ {
+ bos.write(c);
+ }
+ }
+ finally
+ {
+ if (bis != null)
+ {
+ bis.close();
+ }
+
+ if (bos != null)
+ {
+ bos.close();
+ }
+ }
+
+ // add the temporary file to the package file
+ setTempEntryFile(entry.getName(), tempFile);
+
+ //check if the entry is not compressed to keep it this way
+ if (entry.getMethod() == JarEntry.STORED)
+ {
+ rawFiles.add(entry.getName());
+ }
+ }
+ }
+ }
+
+ private String generateStudioFingerprint()
+ {
+ IBundleGroupProvider[] providers = Platform.getBundleGroupProviders();
+ List<IBundleGroup> groups = new ArrayList<IBundleGroup>();
+ if (providers != null)
+ {
+ for (int i = 0; i < providers.length; ++i)
+ {
+ IBundleGroup[] bundleGroups = providers[i].getBundleGroups();
+ groups.addAll(Arrays.asList(bundleGroups));
+ }
+ }
+ String version = "";
+ for (IBundleGroup group : groups)
+ {
+ if (group.getIdentifier().equals(COM_MOTOROLA_STUDIO_ANDROID_FEATURE))
+ {
+ version = group.getVersion();
+ break;
+ }
+ }
+
+ StringBuilder stringBuilder =
+ new StringBuilder(CertificateManagerActivator.CREATED_BY_FIELD_VALUE);
+ stringBuilder.append(" v");
+ stringBuilder.append(version);
+ stringBuilder.append(" - ");
+ stringBuilder.append(Platform.getOS());
+ stringBuilder.append(", ");
+ stringBuilder.append(Platform.getOSArch());
+ stringBuilder.append(". ");
+ if (targetName.trim().length() > 0)
+ {
+ stringBuilder.append("Android target - ");
+ stringBuilder.append(targetName);
+ stringBuilder.append(", ");
+ }
+ if (apiVersion >= 0)
+ {
+ stringBuilder.append("API version - ");
+ stringBuilder.append(apiVersion);
+ stringBuilder.append(".");
+ }
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Gets the names for all the entries in this package file
+ *
+ * @return Set containing the names for all the entries in this package file
+ */
+ public Set<String> getEntryNames()
+ {
+ return Collections.unmodifiableSet(entryMap.keySet());
+ }
+
+ /**
+ * Gets the File object for a given entry
+ *
+ * @param entryName
+ * the entry name
+ * @return the File object corresponding to entryName
+ */
+ public File getEntryFile(String entryName)
+ {
+ return entryMap.get(entryName);
+ }
+
+ /**
+ * Puts a File object as a named entry in this package file
+ *
+ * @param entryName
+ * the entry name
+ * @param file
+ * the File object corresponding to entryName
+ */
+ public void setEntryFile(String entryName, File file)
+ {
+ entryMap.put(entryName, file);
+ }
+
+ /**
+ * Puts a Temporary File object as a named entry in this package file
+ *
+ * @param entryName
+ * the entry name
+ * @param tempFile
+ * the temporary file object corresponding to entryName
+ */
+ public void setTempEntryFile(String entryName, File tempFile)
+ {
+ entryMap.put(entryName, tempFile);
+ tempEntryMap.put(entryName, tempFile);
+ }
+
+ /**
+ * Remove the named entry of files map of this package
+ *
+ * @param entryName
+ * the name of entry to be removed
+ * @throws IOException
+ */
+ public void removeEntryFile(String entryName) throws IOException
+ {
+ File entryFile = entryMap.get(entryName);
+ if (entryFile != null)
+ {
+ entryMap.remove(entryName);
+ if (tempEntryMap.containsKey(entryName))
+ {
+ tempEntryMap.remove(entryName);
+ deleteFile(entryFile);
+ }
+ }
+ }
+
+ /**
+ * Remove the meta entry files (files under META-INF folder)
+ *
+ * @throws IOException
+ */
+ public void removeMetaEntryFiles() throws IOException
+ {
+ String createdBy =
+ manifest.getMainAttributes().getValue(CertificateManagerActivator.CREATED_BY_FIELD);
+ Set<String> entries = new HashSet<String>(getEntryNames());
+ for (String entry : entries)
+ {
+ if (entry.startsWith(CertificateManagerActivator.METAFILES_DIR))
+ {
+ removeEntryFile(entry);
+ }
+ }
+ Manifest cleanManifest = new Manifest();
+ cleanManifest.getMainAttributes().putAll(manifest.getMainAttributes());
+ if ("".equals(targetName) && (apiVersion <= 0)) //Just removing signatures.
+ {
+ cleanManifest.getMainAttributes().putValue(
+ CertificateManagerActivator.CREATED_BY_FIELD, createdBy);
+ }
+ else
+ {
+ cleanManifest.getMainAttributes().putValue(
+ CertificateManagerActivator.CREATED_BY_FIELD, generateStudioFingerprint());
+ }
+ manifest = cleanManifest;
+ }
+
+ private void writeCompressed(JarOutputStream jarOut, String entryName) throws IOException
+ {
+ File file = entryMap.get(entryName);
+ if ((file.exists()) && (file.isFile()))
+ {
+ JarEntry entry = new JarEntry(entryName);
+ jarOut.putNextEntry(entry);
+ WritableByteChannel outputChannel = null;
+ FileChannel readFromFileChannel = null;
+ FileInputStream inputStream = null;
+ try
+ {
+ outputChannel = Channels.newChannel(jarOut);
+ inputStream = new FileInputStream(file);
+ readFromFileChannel = inputStream.getChannel();
+ readFromFileChannel.transferTo(0, file.length(), outputChannel);
+ }
+ finally
+ {
+ try
+ {
+ if (jarOut != null)
+ {
+ jarOut.closeEntry();
+ }
+ if (readFromFileChannel != null)
+ {
+ readFromFileChannel.close();
+ }
+ if (inputStream != null)
+ {
+ inputStream.close();
+ }
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream: ", e.getMessage()); //$NON-NLS-1$
+ }
+ }
+ }
+
+ }
+
+ private void writeRaw(JarOutputStream jarOut, String entryName) throws IOException
+ {
+ FileInputStream inputStream = null;
+ File file = entryMap.get(entryName);
+ if ((file.exists()) && (file.isFile()))
+ {
+ CRC32 crc = new CRC32();
+ JarEntry entry = new JarEntry(entryName);
+ entry.setMethod(JarEntry.STORED);
+ entry.setSize(file.length());
+ WritableByteChannel outputChannel = null;
+ FileChannel readFromFileChannel = null;
+ try
+ {
+ outputChannel = Channels.newChannel(jarOut);
+ inputStream = new FileInputStream(file);
+ readFromFileChannel = inputStream.getChannel();
+
+ ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
+ crc.reset();
+ while (readFromFileChannel.read(buffer) > 0)
+ {
+ buffer.flip();
+ byte[] byteArray = new byte[buffer.limit()];
+ buffer.get(byteArray, 0, buffer.limit());
+ crc.update(byteArray);
+ buffer.clear();
+ }
+ entry.setCrc(crc.getValue());
+ jarOut.putNextEntry(entry);
+ readFromFileChannel.transferTo(0, file.length(), outputChannel);
+ }
+ finally
+ {
+ if (inputStream != null)
+ {
+ inputStream.close();
+ }
+ if (readFromFileChannel != null)
+ {
+ readFromFileChannel.close();
+ }
+ jarOut.closeEntry();
+ }
+ }
+ }
+
+ /**
+ * Writes this package file to an output stream
+ *
+ * @param outputStream
+ * the stream to write the package to
+ * @throws IOException
+ * if an I/O error occurs when writing the package contents to
+ * the output stream
+ */
+ public void write(OutputStream outputStream) throws IOException
+ {
+ // create a jar output stream
+ JarOutputStream jarOut = null;
+
+ try
+ {
+ jarOut = new JarOutputStream(outputStream, manifest);
+
+ // for each entry in the package file
+ for (String jarEntryName : entryMap.keySet())
+ {
+ if (jarEntryName.contains("raw/") || rawFiles.contains(jarEntryName))
+ {
+ writeRaw(jarOut, jarEntryName);
+ }
+ else
+ {
+ writeCompressed(jarOut, jarEntryName);
+ }
+ }
+ }
+ finally
+ {
+ if (jarOut != null)
+ {
+ try
+ {
+ jarOut.finish();
+ jarOut.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream while writing jar file. "
+ + e.getMessage());
+ }
+ }
+ }
+ }
+
+ /**
+ * Calculate the package total size returns long
+ */
+ public long getTotalSize()
+ {
+ long totalSize = 0;
+
+ for (String jarEntryName : entryMap.keySet())
+ {
+ File file = entryMap.get(jarEntryName);
+ if ((file.exists()) && (file.isFile()))
+ {
+ totalSize += file.length();
+ }
+ }
+
+ return totalSize;
+ }
+
+ /**
+ * Gets the package manifest
+ *
+ * @return the package manifest
+ */
+ public Manifest getManifest()
+ {
+ return manifest;
+ }
+
+ /**
+ * Remove the temporary entry files
+ *
+ * @throws IOException
+ */
+ public void removeTemporaryEntryFiles() throws IOException
+ {
+ Set<String> tempEntries =
+ new HashSet<String>(Collections.unmodifiableSet(tempEntryMap.keySet()));
+ for (String tempEntry : tempEntries)
+ {
+ removeEntryFile(tempEntry);
+ }
+ }
+
+ /*
+ * Delete a single file from the filesystem.
+ *
+ * @param fileToDelete
+ * A <code>File</code> object representing the file to be
+ * deleted.
+ * @throws IOException
+ * if any problem occurs deleting the file.
+ */
+ private void deleteFile(File fileToDelete) throws IOException
+ {
+ if ((fileToDelete != null) && fileToDelete.exists() && fileToDelete.isFile()
+ && fileToDelete.canWrite())
+ {
+ fileToDelete.delete();
+ }
+ else
+ {
+ String errorMessage = "";
+ if (fileToDelete == null)
+ {
+ errorMessage = "Null pointer for file to delete.";
+ }
+ else
+ {
+ if (!fileToDelete.exists())
+ {
+ errorMessage = "The file " + fileToDelete.getName() + " does not exist.";
+ }
+ else
+ {
+ if (!fileToDelete.isFile())
+ {
+ errorMessage = fileToDelete.getName() + " is not a file.";
+ }
+ else
+ {
+ if (!fileToDelete.canWrite())
+ {
+ errorMessage = "Cannot write to " + fileToDelete.getName();
+ }
+ }
+ }
+
+ }
+ throw new IOException("Cannot delete file: " + errorMessage);
+ }
+ }
+
+ /**
+ * Create a new Manifest with the basic values and the created by string
+ * @param createdBy who is creating this manifest
+ * @return a new Manifest with basic values and desired created by string
+ */
+ public Manifest createManifest(String createdBy)
+ {
+ Manifest newManifest = new Manifest();
+ Attributes mainAttributes = newManifest.getMainAttributes();
+ mainAttributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(),
+ CertificateManagerActivator.MANIFEST_VERSION);
+ mainAttributes.putValue(CertificateManagerActivator.CREATED_BY_FIELD, createdBy);
+ return newManifest;
+ }
+
+ /**
+ * Execute the zipalign for a certain apk
+ * @param apk
+ */
+ public static void zipAlign(File apk)
+ {
+ // String zipAlign = SdkUtils.getSdkToolsPath();
+ String zipAlign =
+ AndroidUtils.getSDKPathByPreference() + Path.SEPARATOR + IAndroidConstants.FD_TOOLS;
+ try
+ {
+ File tempFile = File.createTempFile("_tozipalign", ".apk");
+ FileUtil.copyFile(apk, tempFile);
+
+ if (!zipAlign.endsWith(File.separator))
+ {
+ zipAlign += File.separator;
+ }
+ zipAlign += Platform.getOS().equals(Platform.OS_WIN32) ? "zipalign.exe" : "zipalign";
+
+ String[] command = new String[]
+ {
+ zipAlign, "-f", "-v", "4", tempFile.getAbsolutePath(), apk.getAbsolutePath()
+ };
+ StringBuilder commandLine = new StringBuilder();
+ for (String commandPart : command)
+ {
+ commandLine.append(commandPart);
+ commandLine.append(" ");
+ }
+
+ StudioLogger.info(PackageFile.class, "Zipaligning package: " + commandLine.toString());
+ Runtime.getRuntime().exec(command);
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(PackageFile.class, "Error while zipaligning package", e);
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(PackageFile.class,
+ "Zipalign application cannot be executed - insuficient permissions", e);
+ }
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ISignConstants.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ISignConstants.java
new file mode 100644
index 0000000..cb8e4df
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ISignConstants.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.packaging.sign;
+
+public interface ISignConstants
+{
+ /**
+ * md5 algorithm
+ */
+ public final String MD5 = "MD5";
+
+ /**
+ * rsa algorithm
+ */
+ public final String RSA = "RSA";
+
+ /**
+ * dsa algorithm
+ */
+ public final String DSA = "DSA";
+
+ /**
+ * sha1 algorithm
+ */
+ public final String SHA1 = "SHA1";
+
+ /**
+ * algorithm connector
+ */
+ public final String ALGORITHM_CONNECTOR = "with";
+
+ /**
+ * Signature file name extension
+ */
+ public final String SIGNATURE_FILE_NAME_EXTENSION = ".SF";
+
+ /**
+ * Signature Version
+ */
+ public final String SIGNATURE_VERSION_KEY = "Signature-Version";
+
+ public final String SIGNATURE_VERSION_VALUE = "1.0";
+
+ /**
+ * Digest algorithm entry in manifest
+ */
+ public final String SHA1_DIGEST = "SHA1-Digest";
+
+ /**
+ * sha1-digest-manifest signature entry
+ */
+ public final String SHA1_DIGEST_MANIFEST = "SHA1-Digest-Manifest";
+
+ /**
+ * manifest main attributes signature entry
+ */
+ public final String SHA1_DIGEST_MANIFEST_MAIN = "SHA1-Digest-Manifest-Main-Attributes";
+
+ /**
+ * Name of the signature files (.SF and .RSA)
+ */
+ public final String SIGNATURE_FILE_NAME = "CERT";
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestDigester.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestDigester.java
new file mode 100644
index 0000000..9ebcee6
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestDigester.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.packaging.sign;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+
+/**
+ * This class is a Manifest digester.
+ * It generates digested hashes for each entry in the manifest file.
+ */
+public class ManifestDigester
+{
+ private final Manifest manifest;
+
+ private HashMap<String, ManifestEntry> entries = null;
+
+ /**
+ * Create a new manifest digester with the given manifest
+ * @param manifest
+ */
+ public ManifestDigester(final Manifest manifest)
+ {
+ this.manifest = manifest;
+ initialize();
+ }
+
+ /**
+ * Initialize the digester creating internal entries for each manifest entry
+ */
+ private void initialize()
+ {
+ Map<String, Attributes> manifestEntries = manifest.getEntries();
+
+ // initialize internal entries list
+ entries = new HashMap<String, ManifestEntry>(manifestEntries.size());
+ for (String entryName : manifestEntries.keySet())
+ {
+ entries.put(entryName, new ManifestEntry(entryName, manifestEntries.get(entryName)));
+ }
+ }
+
+ /**
+ * Get this Manifest file digested
+ * @throws IOException if some error occurs during entries encoding
+ */
+ public String getDigestedString() throws IOException
+ {
+ StringBuilder builder = new StringBuilder();
+ for (ManifestEntry entry : entries.values())
+ {
+ builder.append(entry.toDigestedManifestEntry());
+ builder.append(ManifestEntry.MANIFEST_NEW_LINE);
+ }
+ return builder.toString();
+ }
+
+ public HashMap<String, ManifestEntry> getEntries()
+ {
+ return entries;
+ }
+
+ /**
+ * Computes the digest for the main manifest attributes
+ *
+ * @return the digest of the main manifest attributes or null otherwise
+ * @throws SignException
+ * if a processing error occurs when computing the digest
+ */
+ public byte[] getDigestedManifestMainAttributes() throws SignException
+ {
+ // create an auxiliary manifest that contain only the main attributes
+ // of the original manifest
+ Manifest auxManifest = new Manifest();
+ byte[] result;
+ Attributes auxMainAttributes = auxManifest.getMainAttributes();
+ Attributes mainAttributes = manifest.getMainAttributes();
+ for (Object attributeKey : mainAttributes.keySet())
+ {
+ String name = attributeKey.toString();
+ String value = mainAttributes.getValue(name);
+ auxMainAttributes.putValue(name, value);
+ }
+
+ result = getDigestedManifest(auxManifest);
+
+ StudioLogger.info(SignatureFile.class, "Created digest for main manifest attributes");
+
+ return result;
+ }
+
+ /**
+ * Get this Manifest digested
+ * @return
+ * @throws SignException
+ */
+ public byte[] getDigestedManifest() throws SignException
+ {
+ return getDigestedManifest(manifest);
+ }
+
+ /**
+ * Computes the digest for the manifest
+ *
+ * @param manifest
+ * the manifest to be digested
+ * @return the digest of the entire manifest or null otherwise
+ * @throws SignException
+ * if a processing error occurs when computing the digest
+ */
+ public static byte[] getDigestedManifest(Manifest manifest) throws SignException
+ {
+ byte[] digestedManifestBytes = null;
+ ByteArrayOutputStream baos = null;
+ try
+ {
+ MessageDigest messageDigest = MessageDigest.getInstance(ISignConstants.SHA1);
+ baos = new ByteArrayOutputStream();
+ manifest.write(baos);
+
+ messageDigest.reset();
+ digestedManifestBytes = messageDigest.digest(baos.toByteArray());
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(SignatureFile.class,
+ "I/O error encoding manifest digest: " + e.getMessage());
+
+ throw new SignException("I/O error encoding manifest digest", e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ StudioLogger.error(SignatureFile.class, "Error getting message digester");
+
+ throw new SignException("Could digest the manifest");
+ }
+ finally
+ {
+ try
+ {
+ if (baos != null)
+ {
+ baos.close();
+ }
+ }
+ catch (IOException e)
+ {
+ //do nothing
+ }
+ }
+
+ if (digestedManifestBytes == null)
+ {
+ StudioLogger.error(SignatureFile.class, "Error encoding manifest digest");
+
+ throw new SignException("Could not encode manifest digest");
+ }
+
+ StudioLogger.info(SignatureFile.class, "Created manifest digest");
+
+ return digestedManifestBytes;
+ }
+} \ No newline at end of file
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestEntry.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestEntry.java
new file mode 100644
index 0000000..b7223ec
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestEntry.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.packaging.sign;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Iterator;
+import java.util.jar.Attributes;
+
+import org.bouncycastle.util.encoders.Base64Encoder;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+
+/**
+ * A Class representing a Manifest Entry.
+ */
+public class ManifestEntry
+{
+ /**
+ * New line string according Jar specification
+ */
+ public static final String MANIFEST_NEW_LINE = "\r\n";
+
+ public static final String ENTRY_NAME_ATTRIBUTE = "Name: ";
+
+ public static final String UTF8_CHARSET = "UTF-8";
+
+ /**
+ * Safe line size limit according Jar Specification
+ */
+ public static final int SAFE_LIMIT = 72;
+
+ private final String name;
+
+ private final Attributes attributes;
+
+ /**
+ * Create a new ManifestEntry with the desired name and attributes
+ * @param name
+ * @param attr
+ */
+ public ManifestEntry(String name, Attributes attr)
+ {
+ this.name = name;
+ this.attributes = attr;
+ }
+
+ /**
+ * Get the manifest as it will be written in the Manifest file
+ * @return a byte array representing the manifest entry
+ */
+ public byte[] toManifestEntryBytes()
+ {
+ byte[] result = null;
+ DataOutputStream dataOut = null;
+ ByteArrayOutputStream stream = null;
+ try
+ {
+ stream = new ByteArrayOutputStream();
+ dataOut = new DataOutputStream(stream);
+ String nameField = wrap72bytes(ENTRY_NAME_ATTRIBUTE + name);
+ dataOut.writeBytes(nameField);
+ dataOut.writeBytes(MANIFEST_NEW_LINE);
+ dataOut.writeBytes(getAttributesString());
+ dataOut.writeBytes(MANIFEST_NEW_LINE);
+ dataOut.writeBytes(MANIFEST_NEW_LINE);
+ result = stream.toString().getBytes(UTF8_CHARSET);
+
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(ManifestEntry.class, "Error getting manifest like bytes");
+ }
+ finally
+ {
+ try
+ {
+ if (dataOut != null)
+ {
+ dataOut.close();
+ }
+ if (stream != null)
+ {
+ stream.close();
+ }
+ }
+ catch (IOException e)
+ {
+ StudioLogger
+ .error("Could not close stream while writing manifest" + e.getMessage());
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Digest the entire entry
+ * @return a byte array with the SHA-1 sum of this entry
+ */
+ public byte[] digest()
+ {
+ byte[] digested = null;
+ try
+ {
+ MessageDigest digester = MessageDigest.getInstance("SHA-1");
+ digester.reset();
+ digester.update(toManifestEntryBytes());
+ digested = digester.digest();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ StudioLogger.error(ManifestEntry.class, "Error digesting manifest bytes");
+ }
+ return digested;
+ }
+
+ /**
+ * Get this Entry attributes as it will be written in the Manifest file
+ * @return
+ */
+ private String getAttributesString()
+ {
+ StringBuilder builder = new StringBuilder();
+ Iterator<Object> it = attributes.keySet().iterator();
+ while (it.hasNext())
+ {
+ Object next = it.next();
+ String line = wrap72bytes(next + ": " + attributes.get(next));
+ if (it.hasNext())
+ {
+ line += MANIFEST_NEW_LINE;
+ }
+ builder.append(line);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Wrap a string into another string with at most 72 bytes per line
+ * According Jar spec, each line must have at most 72 bytes
+ * @param line
+ * @return the wrapped string
+ */
+ public static String wrap72bytes(String line)
+ {
+ String returnString = line;
+
+ if (line.length() > SAFE_LIMIT)
+ {
+ int maximumLength = SAFE_LIMIT - MANIFEST_NEW_LINE.length();
+ StringBuilder wrapped = new StringBuilder();
+ int index = maximumLength;
+ String first = line.substring(0, index); //get first SAFE_LIMIT - MANIFEST_NEW_LINE.length() bytes
+ first += MANIFEST_NEW_LINE;
+ wrapped.append(first);
+ while (index < line.length())
+ {
+ String medium = " ";
+ if ((index + maximumLength) < line.length())
+ {
+ medium += line.substring(index, index + maximumLength); //get the maximum length minus the blank space size
+ }
+ else
+ {
+ medium += line.substring(index);
+ }
+ wrapped.append(medium);
+ index += maximumLength;
+ }
+ returnString = wrapped.toString();
+ }
+
+ return returnString;
+ }
+
+ /**
+ * Get this entry name
+ * @return this entry name
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Get this entry ready to be written in the Signature File
+ * @return this entry ready to be written in the Signature File
+ * @throws IOException if some error occurs during encoding
+ */
+ public String toDigestedManifestEntry() throws IOException
+ {
+ Base64Encoder encoder = new Base64Encoder();
+ StringBuilder builder = new StringBuilder();
+ ByteArrayOutputStream output = null;
+
+ try
+ {
+ output = new ByteArrayOutputStream();
+
+ builder.append(wrap72bytes(ENTRY_NAME_ATTRIBUTE + name));
+ builder.append(MANIFEST_NEW_LINE);
+ builder.append(ISignConstants.SHA1_DIGEST + ": ");
+
+ byte[] digest = digest();
+ encoder.encode(digest, 0, digest.length, output);
+
+ builder.append(output.toString());
+ builder.append(MANIFEST_NEW_LINE);
+ }
+ finally
+ {
+ if (output != null)
+ {
+ try
+ {
+ output.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream: " + e.getMessage());
+ }
+ }
+ }
+ return builder.toString();
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/PackageFileSigner.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/PackageFileSigner.java
new file mode 100644
index 0000000..32a5b3f
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/PackageFileSigner.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.packaging.sign;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.security.KeyStoreException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.util.jar.Attributes;
+
+import org.bouncycastle.util.encoders.Base64Encoder;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.packaging.PackageFile;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+
+/**
+ * Utility class used to sign package files.
+ */
+public class PackageFileSigner
+{
+ public static final String MOTODEV_STUDIO = "MOTODEV Studio";
+
+ /**
+ * Signs a package file
+ *
+ * @param packageFile
+ * the package file to sign
+ * @param certificateAlias
+ * the signing certificate alias
+ * @param createdBy
+ * Created-By manifest attribute
+ * @throws SignException
+ * if a processing error occurs during the signing process
+ * @throws UnrecoverableKeyException
+ */
+ public static void signPackage(PackageFile packageFile, IKeyStoreEntry keystoreEntry,
+ String keyEntryPassword, String createdBy) throws SignException,
+ UnrecoverableKeyException
+ {
+
+ try
+ {
+ Base64Encoder encoder = new Base64Encoder();
+ MessageDigest messageDigest = MessageDigest.getInstance(ISignConstants.SHA1);
+
+ addFilesDigestsToManifest(packageFile, encoder, messageDigest);
+
+ addSignatureFiles(packageFile, keystoreEntry, keyEntryPassword, encoder, createdBy);
+ }
+ catch (UnrecoverableKeyException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(PackageFileSigner.class, "Error signing package", e);
+ throw new SignException(e.getMessage(), e);
+ }
+
+ }
+
+ /**
+ * Remove package signature files
+ *
+ * @param packageFile
+ * @throws IOException
+ */
+ public static void removePackageSignature(PackageFile packageFile) throws IOException
+ {
+ packageFile.removeMetaEntryFiles();
+ }
+
+ /**
+ * Generates the digests for all the files in the package and puts them in
+ * the manifest
+ *
+ * @param packageFile
+ * the package file being signed
+ * @param encoder
+ * the BASE64 encoder
+ * @param messageDigest
+ * the message digest
+ * @throws IOException
+ * if an I/O error occurs when reading the files contained in
+ * the package
+ */
+ private static void addFilesDigestsToManifest(PackageFile packageFile, Base64Encoder encoder,
+ MessageDigest messageDigest) throws IOException
+ {
+ InputStream fileInputStream = null;
+ ReadableByteChannel rc = null;
+ ByteArrayOutputStream encodedStream = null;
+
+ // for each entry in the package file
+ for (String entryName : packageFile.getEntryNames())
+ {
+ File file = packageFile.getEntryFile(entryName);
+ if (file.isFile())
+ {
+ try
+ {
+ // read the file contents
+ fileInputStream = new FileInputStream(file);
+ rc = Channels.newChannel(fileInputStream);
+ ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());
+ rc.read(byteBuffer);
+
+ // compute the digest
+ messageDigest.reset();
+ byte[] digestedArray = messageDigest.digest(byteBuffer.array());
+
+ encodedStream = new ByteArrayOutputStream();
+ encoder.encode(digestedArray, 0, digestedArray.length, encodedStream);
+ String digestedMessage = encodedStream.toString();
+
+ // put the digest in the manifest file
+ Attributes jarEntryAttributes = new Attributes();
+ jarEntryAttributes.putValue(ISignConstants.SHA1_DIGEST, digestedMessage);
+ packageFile.getManifest().getEntries().put(entryName, jarEntryAttributes);
+ }
+ finally
+ {
+ try
+ {
+ if (encodedStream != null)
+ {
+ encodedStream.close();
+ }
+ if (rc != null)
+ {
+ rc.close();
+ }
+ if (fileInputStream != null)
+ {
+ fileInputStream.close();
+ }
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream while signing package. "
+ + e.getMessage());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds the signature file and the signature block file to the package
+ *
+ * @param packageFile
+ * the package file being signed
+ * @param certificateAlias
+ * the signing certificate alias
+ * @param encoder
+ * the BASE64 encoder
+ * @param messageDigest
+ * the message digest
+ * @param createdBy
+ * Created-By manifest attribute
+ * @throws SignException
+ * if a processing error occurs during the signing process
+ * @throws IOException
+ * if an I/O error occurs during the signing process
+ * @throws NoSuchAlgorithmException
+ * @throws KeyStoreManagerException
+ * @throws KeyStoreException
+ * @throws UnrecoverableKeyException
+ */
+ private static void addSignatureFiles(PackageFile packageFile, IKeyStoreEntry keystoreEntry,
+ String keyEntryPassword, Base64Encoder encoder, String createdBy) throws IOException,
+ SignException, UnrecoverableKeyException, KeyStoreException, KeyStoreManagerException,
+ NoSuchAlgorithmException
+ {
+ // signature file
+ SignatureFile signatureFile =
+ new SignatureFile(packageFile, keystoreEntry.getAlias(), encoder, createdBy);
+
+ File sigFile = File.createTempFile(CertificateManagerActivator.TEMP_FILE_PREFIX, null);
+ FileOutputStream sigFileOutStream = null;
+
+ try
+ {
+ sigFileOutStream = new FileOutputStream(sigFile);
+ signatureFile.write(sigFileOutStream);
+ }
+ finally
+ {
+ if (sigFileOutStream != null)
+ {
+ try
+ {
+ sigFileOutStream.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger
+ .error("Could not close stream while adding signature files to package. "
+ + e.getMessage());
+ }
+ }
+ }
+
+ packageFile.setTempEntryFile(signatureFile.toString(), sigFile);
+
+ // signature block file
+ SignatureBlockFile signatureBlockFile =
+ new SignatureBlockFile(signatureFile, keystoreEntry, keyEntryPassword);
+
+ File sigBlockFile = File.createTempFile(CertificateManagerActivator.TEMP_FILE_PREFIX, null);
+ FileOutputStream sigBlockFileOutStream = null;
+
+ try
+ {
+ sigBlockFileOutStream = new FileOutputStream(sigBlockFile);
+ signatureBlockFile.write(sigBlockFileOutStream);
+ }
+ finally
+ {
+ if (sigBlockFileOutStream != null)
+ {
+ try
+ {
+ sigBlockFileOutStream.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger
+ .error("Could not close stream while adding signature files to package. "
+ + e.getMessage());
+ }
+ }
+ }
+
+ packageFile.setTempEntryFile(signatureBlockFile.toString(), sigBlockFile);
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignException.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignException.java
new file mode 100644
index 0000000..901a420
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.packaging.sign;
+
+/**
+ * Signing exception
+ */
+@SuppressWarnings("serial")
+public class SignException extends Exception
+{
+ /**
+ * Creates a SignException with a detail message
+ *
+ * @param message the detail message
+ */
+ public SignException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Creates a SignException with a detail message and a cause
+ *
+ * @param message the detail message
+ * @param cause the cause
+ */
+ public SignException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureBlockFile.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureBlockFile.java
new file mode 100644
index 0000000..f8fdcad
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureBlockFile.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.packaging.sign;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.X509Certificate;
+
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.pkcs.ContentInfo;
+import sun.security.pkcs.PKCS7;
+import sun.security.pkcs.SignerInfo;
+import sun.security.x509.AlgorithmId;
+import sun.security.x509.X500Name;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+
+/**
+ * This class implements the signature block file from jar mechanism used in packaging
+ */
+public class SignatureBlockFile
+{
+
+ /**
+ * the signature file
+ */
+ private SignatureFile signatureFile;
+
+ /**
+ * A certificate from keystore
+ */
+ private IKeyStoreEntry keystoreEntry;
+
+ /**
+ * The password of the certificate.
+ */
+ private String keyEntryPassword;
+
+ /**
+ * Default Constructor
+ *
+ * @param signatureFile the signature file
+ * @param alias the certificate alias
+ */
+ public SignatureBlockFile(SignatureFile signatureFile, IKeyStoreEntry keystoreEntry,
+ String keyEntryPassword)
+ {
+ this.keyEntryPassword = keyEntryPassword;
+ this.keystoreEntry = keystoreEntry;
+ this.signatureFile = signatureFile;
+ }
+
+ /**
+ * To string method override
+ *
+ * @return the signature block file name with relative path from root. Frequently META-INF/alias.RSA or .DSA
+ */
+ @Override
+ public String toString()
+ {
+ String result = new String();
+ try
+ {
+ result =
+ new StringBuilder(CertificateManagerActivator.METAFILES_DIR)
+ .append(CertificateManagerActivator.JAR_SEPARATOR)
+ .append(ISignConstants.SIGNATURE_FILE_NAME).append(".")
+ .append(getBlockAlgorithm()).toString();
+ }
+ catch (UnrecoverableKeyException e)
+ {
+ StudioLogger.error("Could not generate signature block file name.");
+ }
+ catch (KeyStoreException e)
+ {
+ StudioLogger.error("Could not generate signature block file name.");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ StudioLogger.error("Could not generate signature block file name.");
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Could not generate signature block file name.");
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets the block file algorithm
+ *
+ * @return the signature block file algorithm to be used
+ * @throws KeyStoreManagerException
+ * @throws NoSuchAlgorithmException
+ * @throws KeyStoreException
+ * @throws UnrecoverableKeyException
+ * @throws
+ */
+ private String getBlockAlgorithm() throws UnrecoverableKeyException, KeyStoreException,
+ NoSuchAlgorithmException, KeyStoreManagerException
+ {
+ return keystoreEntry.getKey(this.keyEntryPassword).getAlgorithm();
+ }
+
+ /**
+ * Writes this file to an output stream
+ *
+ * @param outputStream the output stream to write the file
+ * @throws IOException if an I/O error occurs during the signing process
+ * @throws SignException if a processing error occurs during the signing process
+ * @throws KeyStoreManagerException
+ * @throws KeyStoreException
+ * @throws UnrecoverableKeyException
+ * @throws NoSuchAlgorithmException
+ */
+ public void write(OutputStream outputStream) throws IOException, SignException,
+ UnrecoverableKeyException, KeyStoreException, KeyStoreManagerException,
+ NoSuchAlgorithmException
+ {
+ // get certificate from entry
+ X509Certificate[] certChain =
+ {
+ keystoreEntry.getX509Certificate()
+ };
+ if (certChain.length > 0)
+ {
+ //get some info from certificate as issuer, serial and algorithm
+ X500Principal issuer = certChain[0].getIssuerX500Principal();
+ String serial = certChain[0].getSerialNumber().toString();
+ String blockalgorithm = getBlockAlgorithm();
+
+ String digestAlgotithm = null;
+ // determine the algorithm to be used to cipher the block file
+ if (blockalgorithm.equalsIgnoreCase(ISignConstants.DSA))
+ {
+ digestAlgotithm = ISignConstants.SHA1;
+ }
+ else if (blockalgorithm.equalsIgnoreCase(ISignConstants.RSA))
+ {
+ digestAlgotithm = ISignConstants.MD5;
+ }
+ else
+ {
+ StudioLogger.error(SignatureBlockFile.class,
+ "Signing block algorithm not supported. Key algorithm must be DSA or RSA");
+
+ throw new SignException("Signing block algorithm not supported");
+ }
+
+ String signatureAlgorithm =
+ digestAlgotithm + ISignConstants.ALGORITHM_CONNECTOR + blockalgorithm;
+
+ AlgorithmId digestAlg;
+ try
+ {
+ digestAlg = AlgorithmId.get(digestAlgotithm);
+ AlgorithmId privateKeyAlg = AlgorithmId.get(blockalgorithm);
+ // write the certificate with signature file and cipher it
+ Signature sig = Signature.getInstance(signatureAlgorithm);
+ sig.initSign(keystoreEntry.getPrivateKey(this.keyEntryPassword));
+
+ PKCS7 block = null;
+ ByteArrayOutputStream baos = null;
+ ByteArrayOutputStream signature = null;
+
+ try
+ {
+ baos = new ByteArrayOutputStream();
+ signatureFile.write(baos);
+
+ ContentInfo contentInfo = new ContentInfo(ContentInfo.DATA_OID, null);
+ sig.update(baos.toByteArray());
+
+ signature = new ByteArrayOutputStream();
+ signature.write(sig.sign());
+
+ SignerInfo si =
+ new SignerInfo(new X500Name(issuer.getName()), new BigInteger(serial),
+ digestAlg, privateKeyAlg, signature.toByteArray());
+
+ AlgorithmId[] algs =
+ {
+ digestAlg
+ };
+ SignerInfo[] infos =
+ {
+ si
+ };
+
+ block = new PKCS7(algs, contentInfo, certChain, infos);
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(SignatureBlockFile.class,
+ "I/O error creating signature block file: " + e.getMessage());
+
+ throw new SignException("I/O error creating signature block file", e);
+ }
+ finally
+ {
+ if (baos != null)
+ {
+ baos.close();
+ }
+ if (signature != null)
+ {
+ signature.close();
+ }
+ }
+
+ // I/O exceptions below are thrown unmodified
+ block.encodeSignedData(outputStream);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ StudioLogger.error(SignatureBlockFile.class, "Signing algorithm not supported: "
+ + nsae.getMessage());
+
+ throw new SignException("Signing algorithm not supported", nsae);
+ }
+ catch (InvalidKeyException ike)
+ {
+ StudioLogger.error(SignatureBlockFile.class,
+ "Invalid key when creating signature block file: " + ike.getMessage());
+
+ throw new SignException("Invalid key when creating signature block file", ike);
+ }
+ catch (SignatureException se)
+ {
+ StudioLogger.error(SignatureBlockFile.class,
+ "Signature error when creating signature block file: " + se.getMessage());
+
+ throw new SignException("Signature error creating signature block file", se);
+ }
+ }
+ StudioLogger.info(SignatureBlockFile.class, "Created signature block file");
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java
new file mode 100644
index 0000000..669cf70
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.packaging.sign;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.bouncycastle.util.encoders.Base64Encoder;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.packaging.PackageFile;
+
+/**
+ * This class implements the package signature file, that follows the jar
+ * signing process.
+ */
+public class SignatureFile
+{
+ /**
+ * The package file
+ */
+ private final PackageFile packageFile;
+
+ /**
+ * The base encoder
+ */
+ private Base64Encoder encoder = new Base64Encoder();
+
+ /**
+ * Manifest Created-By attribute
+ */
+ private final String createdBy;
+
+ /**
+ * Default Constructor
+ *
+ * @param packageFile
+ * the signed package file to be signed
+ * @param alias
+ * the certificate alias
+ * @param encoder
+ * the BASE64 encoder
+ * @param createdBy
+ * Created-By manifest attribute
+ */
+ public SignatureFile(PackageFile packageFile, String alias, Base64Encoder encoder,
+ String createdBy)
+ {
+ this.packageFile = packageFile;
+ this.encoder = encoder;
+ this.createdBy = createdBy;
+ }
+
+ /**
+ * Return the filename with relative path from root (normally
+ * META-INF/alias.SF).
+ */
+ @Override
+ public String toString()
+ {
+ return CertificateManagerActivator.METAFILES_DIR
+ + CertificateManagerActivator.JAR_SEPARATOR + ISignConstants.SIGNATURE_FILE_NAME
+ + ISignConstants.SIGNATURE_FILE_NAME_EXTENSION;
+
+ }
+
+ /**
+ * Writes this file to an output stream.
+ *
+ * @param outputStream
+ * the stream to write this file
+ * @throws IOException
+ * if an I/O error occurs during the signing process
+ * @throws SignException
+ * if a processing error occurs during the signing process
+ */
+ public void write(OutputStream outputStream) throws IOException, SignException
+ {
+ // the manifest file
+ Manifest manifestFile = this.packageFile.getManifest();
+
+ // the manifest digester
+ ManifestDigester manifestDigester = new ManifestDigester(manifestFile);
+
+ // the signature file to be constructed
+ Manifest signatureFile = new Manifest();
+
+ // the manifest digested main attributes
+ byte[] digestedMainAttributes = manifestDigester.getDigestedManifestMainAttributes();
+
+ // the digest of entire manifest
+ byte[] digestedManifest = manifestDigester.getDigestedManifest();
+
+ // put the required main attributes to a valid signature file
+ // (Version, CreatedBy, Main Attrib digest, Manifest digest)
+ Attributes signatureFileMainAtt = signatureFile.getMainAttributes();
+ signatureFileMainAtt.putValue(ISignConstants.SIGNATURE_VERSION_KEY,
+ ISignConstants.SIGNATURE_VERSION_VALUE);
+ signatureFileMainAtt.putValue(CertificateManagerActivator.CREATED_BY_FIELD, this.createdBy);
+
+ ByteArrayOutputStream stream = null;
+
+ try
+ {
+ stream = new ByteArrayOutputStream();
+ encoder.encode(digestedMainAttributes, 0, digestedMainAttributes.length, stream);
+ String encodedMainAttributesDigest = stream.toString();
+
+ stream.reset();
+ encoder.encode(digestedManifest, 0, digestedManifest.length, stream);
+ String encodedManifestDigest = stream.toString();
+
+ signatureFileMainAtt.putValue(ISignConstants.SHA1_DIGEST_MANIFEST_MAIN,
+ encodedMainAttributesDigest);
+ signatureFileMainAtt.putValue(ISignConstants.SHA1_DIGEST_MANIFEST,
+ encodedManifestDigest);
+ }
+ finally
+ {
+ if (stream != null)
+ {
+ try
+ {
+ stream.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream writing signature file. "
+ + e.getMessage());
+ }
+ }
+ }
+
+ // calculate the digest from each entry of manifest
+ ByteArrayOutputStream baos = null;
+ try
+ {
+ baos = new ByteArrayOutputStream();
+ manifestFile.write(baos);
+
+ Map<String, Attributes> manifestEntries = manifestFile.getEntries();
+ Map<String, Attributes> signatureFileEntries = signatureFile.getEntries();
+ HashMap<String, ManifestEntry> entries = manifestDigester.getEntries();
+
+ for (String manifestEntryKey : manifestEntries.keySet())
+ {
+ ManifestEntry signatureFileEntry = entries.get(manifestEntryKey);
+
+ byte[] digestedArray = signatureFileEntry.digest();
+
+ ByteArrayOutputStream encodedStream = null;
+
+ try
+ {
+ encodedStream = new ByteArrayOutputStream();
+ this.encoder.encode(digestedArray, 0, digestedArray.length, encodedStream);
+
+ String digestedValue = encodedStream.toString();
+
+ Attributes signatureFileAtt = new Attributes();
+ signatureFileAtt.putValue(ISignConstants.SHA1_DIGEST, digestedValue);
+ signatureFileEntries.put(manifestEntryKey, signatureFileAtt);
+ }
+ finally
+ {
+ try
+ {
+ if (encodedStream != null)
+ {
+ encodedStream.close();
+ }
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream: " + e.getMessage());
+ }
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(SignatureFile.class,
+ "I/O error digesting manifest entries: " + e.getMessage());
+
+ throw new SignException("I/O error digesting manifest entries", e);
+ }
+ finally
+ {
+ try
+ {
+ if (baos != null)
+ {
+ baos.close();
+ }
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream: " + e.getMessage());
+ }
+ }
+
+ // I/O exceptions below are thrown unmodified
+ signatureFile.write(outputStream);
+
+ StudioLogger.info(SignatureFile.class, "Signature file was written");
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/property/tester/TreeNodeTester.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/property/tester/TreeNodeTester.java
new file mode 100644
index 0000000..033dc01
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/property/tester/TreeNodeTester.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.property.tester;
+
+import org.eclipse.core.expressions.PropertyTester;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * Property testers are used via extension point to test object's state properties.
+ * This tester checks {@link ITreeNode} properties.
+ * */
+public class TreeNodeTester extends PropertyTester
+{
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.expressions.IPropertyTester#test(Object,String,Object[],Object)
+ */
+ @Override
+ public boolean test(Object receiver, String property, Object[] args, Object expectedValue)
+ {
+ boolean result = false;
+
+ if (receiver instanceof ITreeNode)
+ {
+ ITreeNode treeNode = (ITreeNode) receiver;
+ result =
+ treeNode.testAttribute(receiver,
+ ITreeNode.PROP_NAMESPACE.concat("." + property),
+ expectedValue.toString());
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/PopupMenuActionDelegate.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/PopupMenuActionDelegate.java
new file mode 100644
index 0000000..ad2c4d2
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/PopupMenuActionDelegate.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.action;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.command.BackupHandler;
+import com.motorolamobility.studio.android.certmanager.command.CertificatePropertiesHandler;
+import com.motorolamobility.studio.android.certmanager.command.ChangeKeyStoreTypeHandler;
+import com.motorolamobility.studio.android.certmanager.command.ChangePasswordKeyHandler;
+import com.motorolamobility.studio.android.certmanager.command.ChangePasswordKeystoreHandler;
+import com.motorolamobility.studio.android.certmanager.command.CreateKeyHandler;
+import com.motorolamobility.studio.android.certmanager.command.DeleteKeyHandler;
+import com.motorolamobility.studio.android.certmanager.command.DeleteKeystoreHandler;
+import com.motorolamobility.studio.android.certmanager.command.ImportKeyStoreEntriesHandler;
+import com.motorolamobility.studio.android.certmanager.command.RefreshHandler;
+import com.motorolamobility.studio.android.certmanager.command.SignExternalPackagesHandler;
+
+public class PopupMenuActionDelegate implements IObjectActionDelegate
+{
+
+ /**
+ * Enum type for ActionHandlers. If you need to add a new ActionHandler, just include
+ * a new type to this enum with the action id that you defined on your action extension point
+ */
+ enum ActionHandlers
+ {
+ SIGN_PACKAGE("com.motorolamobility.studio.android.certmanager.core.ui.action.addSignature") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new SignExternalPackagesHandler();
+ }
+ },
+ BACKUP_KEYSTORE(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.backupKeystore") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ //this handler will delegate the operation to another action that, in turn,
+ //will retrieve the current selection
+ //therefore, the parameter treeNode is not used here.
+ return new BackupHandler();
+ }
+
+ },
+ DELETE_KEYSTORE(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.deleteKeystore") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new DeleteKeystoreHandler();
+ }
+
+ },
+ PROPERTIES_KEYSTORE(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.certificateProperties") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new CertificatePropertiesHandler();
+ }
+
+ },
+ CHANGE_KEYSTORE_PASSWORD(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.changeKeystorePassword") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new ChangePasswordKeystoreHandler();
+ }
+
+ },
+ CHANGE_KEY_PASSWORD(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.changeKeyPassword") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new ChangePasswordKeyHandler();
+ }
+
+ },
+ CREATE_KEY("com.motorolamobility.studio.android.certmanager.core.ui.action.createKey") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new CreateKeyHandler();
+ }
+
+ },
+ DELETE_KEY("com.motorolamobility.studio.android.certmanager.core.ui.action.deleteEntry") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new DeleteKeyHandler();
+ }
+
+ },
+ REFRESH("com.motorolamobility.studio.android.certmanager.core.ui.action.refresh") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new RefreshHandler();
+ }
+
+ },
+ CHANGE_KEYSTORE_TYPE(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.changeKeystoreType")
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new ChangeKeyStoreTypeHandler();
+ }
+ },
+ IMPORT_KEYSTORE_ENTRIES(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.importKeystoreEntries")
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new ImportKeyStoreEntriesHandler();
+ }
+ };
+
+ private final String actionId;
+
+ private ActionHandlers(String actionId)
+ {
+ this.actionId = actionId;
+ }
+
+ public abstract IHandler getHandler();
+
+ public static ActionHandlers getActionHandlerbyId(String id)
+ {
+
+ Object ret = null;
+ for (ActionHandlers h : ActionHandlers.values())
+ {
+ if (h.actionId.equals(id))
+ {
+ ret = h;
+ break;
+ }
+ }
+
+ return (ActionHandlers) ret;
+ }
+ }
+
+ @Override
+ public void run(IAction action)
+ {
+
+ ActionHandlers type = ActionHandlers.getActionHandlerbyId(action.getId());
+
+ IHandler handler = null;
+
+ if (type != null)
+ {
+ handler = type.getHandler();
+ }
+
+ if (handler != null)
+ {
+ ExecutionEvent event = new ExecutionEvent();
+ try
+ {
+ handler.execute(event);
+ }
+ catch (ExecutionException e)
+ {
+ StudioLogger.error(PopupMenuActionDelegate.class, e.getMessage(), e);
+ EclipseUtils.showErrorDialog("Execution error", e.getMessage());
+ }
+ }
+
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection)
+ {
+ //selection is retrieved by the handlers
+ }
+
+ @Override
+ public void setActivePart(IAction action, IWorkbenchPart targetPart)
+ {
+ //do nothing
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/RemoveSignatureAction.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/RemoveSignatureAction.java
new file mode 100644
index 0000000..dc029cd
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/RemoveSignatureAction.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.action;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.wizards.RemoveExternalPackageSignatureWizard;
+
+/**
+ * This class gets the current workspace selection and calls the wizard to remove a package signature
+ */
+public class RemoveSignatureAction extends Action
+{
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.jface.action.Action#run()
+ */
+ @Override
+ public void run()
+ {
+ IWorkbench workbench = PlatformUI.getWorkbench();
+
+ if ((workbench != null) && !workbench.isClosing())
+ {
+
+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+
+ if (window != null)
+ {
+ ISelection selection = window.getSelectionService().getSelection();
+ IStructuredSelection structureSelection = null;
+
+ if (selection instanceof IStructuredSelection)
+ {
+ structureSelection = (IStructuredSelection) selection;
+ }
+ else
+ {
+ structureSelection = new StructuredSelection();
+ }
+ WizardDialog dialog =
+ new WizardDialog(window.getShell(),
+ new RemoveExternalPackageSignatureWizard(structureSelection));
+ dialog.open();
+ }
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/SignCreatedPackageAction.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/SignCreatedPackageAction.java
new file mode 100644
index 0000000..c02b20a
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/SignCreatedPackageAction.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.action;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+import com.motorolamobility.studio.android.certmanager.ui.wizards.SignExternalPackageWizard;
+
+/**
+ * This class gets the current workspace selection and calls the wizard to Sign an existent package
+ */
+public class SignCreatedPackageAction extends Action
+{
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.jface.action.Action#run()
+ */
+ @Override
+ public void run()
+ {
+ IWorkbench workbench = PlatformUI.getWorkbench();
+
+ if ((workbench != null) && !workbench.isClosing())
+ {
+
+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+
+ if (window != null)
+ {
+ ISelection selection = window.getSelectionService().getSelection();
+ IStructuredSelection structureSelection = null;
+ IKeyStore selectedIKeyStore = null;
+ IKeyStoreEntry selectedEntry = null;
+ if (selection instanceof IStructuredSelection)
+ {
+ structureSelection = (IStructuredSelection) selection;
+ Object selectedItem = structureSelection.getFirstElement();
+ if (selectedItem instanceof IKeyStore)
+ {
+ selectedIKeyStore = (IKeyStore) selectedItem;
+ }
+ else if (selectedItem instanceof IKeyStoreEntry)
+ {
+ selectedEntry = (IKeyStoreEntry) selectedItem;
+ selectedIKeyStore = selectedEntry.getKeyStoreNode();
+ }
+ }
+ else
+ {
+ structureSelection = new StructuredSelection();
+ }
+ WizardDialog dialog =
+ new WizardDialog(window.getShell(), new SignExternalPackageWizard(
+ structureSelection, selectedIKeyStore, selectedEntry));
+ dialog.open();
+
+ }
+ }
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/CertificateBlock.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/CertificateBlock.java
new file mode 100644
index 0000000..2e1f70e
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/CertificateBlock.java
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.composite;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import com.motorola.studio.android.common.utilities.ui.Country;
+import com.motorola.studio.android.common.utilities.ui.ToolsCountries;
+import com.motorola.studio.android.common.utilities.ui.WidgetsFactory;
+import com.motorola.studio.android.common.utilities.ui.WidgetsUtil;
+import com.motorola.studio.android.wizards.elements.IBaseBlock;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+/**
+ * This class shows the properties to for certificate.
+ */
+public class CertificateBlock implements IBaseBlock
+{
+ private static final String LABEL_DECORATOR = "*"; //$NON-NLS-1$
+
+ private static final int LONG_TEXT_SIZE = 256;
+
+ private static final int MEDIUM_TEXT_SIZE = 128;
+
+ private static final int SMALL_TEXT_SIZE = 64;
+
+ /**
+ * The attribute representing the window with which the user interacts.
+ */
+ private Shell shell;
+
+ /**
+ * Store the composite.
+ */
+ protected Composite parent;
+
+ /**
+ * The key pair alias text field.
+ */
+ private Text textAlias;
+
+ /**
+ * The common name text field.
+ */
+ private Text commonNameText;
+
+ /**
+ * The organization text field.
+ */
+ private Text textOrganization;
+
+ /**
+ * The organization unit text field.
+ */
+ private Text textOrganizationUnit;
+
+ /**
+ * The locality text field.
+ */
+ private Text textLocality;
+
+ /**
+ * The state text field.
+ */
+ private Text textState;
+
+ /**
+ * The country combo.
+ */
+ private Combo comboCountry;
+
+ private Label labelAlias;
+
+ private Control controlToFocus = null;
+
+ /**
+ * This listener is used to save the field that has the focus.
+ * */
+ protected FocusListener focusListener = new FocusListener()
+ {
+
+ @Override
+ public void focusLost(FocusEvent e)
+ {
+ //do nothing...
+ }
+
+ @Override
+ public void focusGained(FocusEvent e)
+ {
+ if (e.widget instanceof Control)
+ {
+ controlToFocus = (Control) e.widget;
+ }
+ }
+ };
+
+ /*
+ * (non-Javadoc)
+ * @seecom.motorola.studio.android.wizards.BaseWizard#
+ * createContentPlugin(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Composite createContent(Composite parent)
+ {
+ Composite toReturn = WidgetsFactory.createComposite(parent, 1);
+
+ this.parent = parent;
+
+ createBasicInfoArea(toReturn);
+ createDetailedInfoArea(toReturn);
+ createCustomArea(toReturn);
+ setDefaultFocus();
+
+ return toReturn;
+ }
+
+ protected void createCustomArea(Composite parent)
+ {
+ //by default, do nothing
+ }
+
+ /**
+ * Creates Custom Fields to be appended in the properties block
+ * @param dnFieldsArea
+ */
+ protected void createCustomDetailedInfoArea(Composite dnFieldsArea)
+ {
+ //by default, do nothing
+ }
+
+ /**
+ * Create all fields of the distinguished name.
+ *
+ * @param parent The parent composite to add the created fields.
+ */
+ private void createDetailedInfoArea(Composite parent)
+ {
+ //Composite bottomComposite = WidgetsFactory.createComposite(parent);
+
+ Group detailsGroup =
+ WidgetsFactory.createTitledGroup(parent,
+ CertificateManagerNLS.CertificateBlock_DetailedInfoGroupTitle, 2);
+
+ // Creating the common name field
+ WidgetsFactory.createLabel(detailsGroup,
+ CertificateManagerNLS.CertificateBlock_FirstAndLastName + ":"); //$NON-NLS-1$
+ commonNameText = WidgetsFactory.createText(detailsGroup);
+ commonNameText.setTextLimit(MEDIUM_TEXT_SIZE);
+ commonNameText.addListener(SWT.Modify, this);
+ commonNameText.addFocusListener(focusListener);
+
+ // Creating the organization field
+ WidgetsFactory.createLabel(detailsGroup,
+ CertificateManagerNLS.CertificateBlock_Organization + ":"); //$NON-NLS-1$
+ textOrganization = WidgetsFactory.createText(detailsGroup);
+ textOrganization.setTextLimit(MEDIUM_TEXT_SIZE);
+ textOrganization.addListener(SWT.Modify, this);
+ textOrganization.addFocusListener(focusListener);
+
+ // Creating the organization unit field
+ WidgetsFactory.createLabel(detailsGroup,
+ CertificateManagerNLS.CertificateBlock_OrganizationUnit + ":"); //$NON-NLS-1$
+ textOrganizationUnit = WidgetsFactory.createText(detailsGroup);
+ textOrganizationUnit.setTextLimit(MEDIUM_TEXT_SIZE);
+ textOrganizationUnit.addListener(SWT.Modify, this);
+ textOrganizationUnit.addFocusListener(focusListener);
+
+ // Creating the locality field
+ WidgetsFactory.createLabel(detailsGroup,
+ CertificateManagerNLS.CertificateBlock_CityOrLocality + ":"); //$NON-NLS-1$
+ textLocality = WidgetsFactory.createText(detailsGroup);
+ textLocality.setTextLimit(LONG_TEXT_SIZE);
+ textLocality.addListener(SWT.Modify, this);
+ textLocality.addFocusListener(focusListener);
+
+ // Creating the state field
+ WidgetsFactory.createLabel(detailsGroup,
+ CertificateManagerNLS.CertificateBlock_StateOrProvince + ":"); //$NON-NLS-1$
+ textState = WidgetsFactory.createText(detailsGroup);
+ textState.setTextLimit(LONG_TEXT_SIZE);
+ textState.addListener(SWT.Modify, this);
+ textState.addFocusListener(focusListener);
+
+ // Creating the country field
+ WidgetsFactory.createLabel(detailsGroup, CertificateManagerNLS.CertificateBlock_CountryCode
+ + ":"); //$NON-NLS-1$
+ comboCountry = WidgetsFactory.createCombo(detailsGroup);
+ comboCountry.addListener(SWT.Selection, this);
+ comboCountry.addFocusListener(focusListener);
+ for (Country country : ToolsCountries.getInstance().getCountries())
+ {
+ this.comboCountry.add(country.getCountryName());
+ this.comboCountry.setData(country.getCountryName(), country.getCountryCode());
+ }
+ comboCountry.setVisibleItemCount(SMALL_TEXT_SIZE);
+
+ createCustomDetailedInfoArea(detailsGroup);
+ }
+
+ /**
+ * Create the key pair alias field.
+ *
+ * @param parent The parent composite to add the key pair alias field.
+ */
+ private void createBasicInfoArea(Composite parent)
+ {
+ Group groupBasicInfo =
+ WidgetsFactory.createTitledGroup(parent,
+ CertificateManagerNLS.CertificateBlock_BasicInfoGroupTitle, 2);
+
+ labelAlias =
+ WidgetsFactory.createLabel(groupBasicInfo,
+ CertificateManagerNLS.CertificateBlock_AliasName + ":"); //$NON-NLS-1$
+ textAlias = WidgetsFactory.createText(groupBasicInfo);
+ textAlias.setTextLimit(SMALL_TEXT_SIZE);
+ textAlias.addListener(SWT.Modify, this);
+ textAlias.addFocusListener(focusListener);
+
+ createCustomBasicInfoArea(groupBasicInfo);
+ }
+
+ /**
+ * Allow subclasses to add custom required fields to the certificate block.
+ * @param parent The parent composite for the custom required fields.
+ */
+ protected void createCustomBasicInfoArea(Composite parent)
+ {
+ //default implementation does nothing.
+ }
+
+ /**
+ * Decorate required fields using {@link CertificateBlock#decorateText(String)}. Always call the {@code super} implementation when overriding this method.
+ * <br/>
+ * Default required fields are:
+ * <ul>
+ * <li>Alias</li>
+ * </ul>
+ * */
+ protected void decorateRequiredFields()
+ {
+ labelAlias.setText(decorateText(labelAlias.getText()));
+ }
+
+ /**
+ * Decorate required fields by prefixing it with {@link CertificateBlock#LABEL_DECORATOR}.
+ *
+ * @return The decorated text.
+ * */
+ protected String decorateText(String strToDecorate)
+ {
+ return LABEL_DECORATOR.concat(strToDecorate);
+ }
+
+ /**
+ * Obtains the key pair alias defined by user.
+ *
+ * @return The key pair alias.
+ */
+ public String getAlias()
+ {
+ return textAlias.getText().toLowerCase();
+ }
+
+ /**
+ * Obtains the common name defined by user.
+ *
+ * @return The common name.
+ */
+ public String getCommonName()
+ {
+ return commonNameText.getText();
+ }
+
+ /**
+ * Obtains the organization defined by user.
+ *
+ * @return The organization.
+ */
+ public String getOrganization()
+ {
+ return textOrganization.getText();
+ }
+
+ /**
+ * Obtains the organization unit defined by user.
+ *
+ * @return The organization unit.
+ */
+ public String getOrganizationUnit()
+ {
+ return textOrganizationUnit.getText();
+ }
+
+ /**
+ * Obtains the locality defined by user.
+ *
+ * @return The locality.
+ */
+ public String getLocality()
+ {
+ return textLocality.getText();
+ }
+
+ /**
+ * Obtains the state defined by user.
+ *
+ * @return The state.
+ */
+ public String getState()
+ {
+ return textState.getText();
+ }
+
+ /**
+ * Obtains the country defined by user.
+ *
+ * @return The country.
+ */
+ public String getCountry()
+ {
+ String result = new String(); //empty string
+
+ //ensure that there is something selected in the combo before indexing its item list
+ if (comboCountry.getSelectionIndex() >= 0)
+ {
+ result =
+ (String) comboCountry.getData(comboCountry.getItem(comboCountry
+ .getSelectionIndex()));
+ }
+ return result;
+ }
+
+ /**
+ * Returns true if there is no error message set, the alias is not empty and there is at least one detail field non empty.
+ * @see com.motorola.studio.platform.tools.common.ui.composite.BaseBlock#isPageComplete()
+ */
+ @Override
+ public boolean isPageComplete()
+ {
+ return (getErrorMessage() == null)
+ && !WidgetsUtil.isNullOrEmpty(this.textAlias)
+ && (!WidgetsUtil.isNullOrEmpty(this.commonNameText)
+ || !WidgetsUtil.isNullOrEmpty(this.textOrganization)
+ || !WidgetsUtil.isNullOrEmpty(this.textOrganizationUnit)
+ || !WidgetsUtil.isNullOrEmpty(this.textLocality)
+ || !WidgetsUtil.isNullOrEmpty(this.textState) || !WidgetsUtil
+ .isNullOrDeselected(this.comboCountry));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @seecom.motorola.studio.platform.tools.common.ui.composite.BaseBlock#
+ * canFlipToNextPage()
+ */
+ @Override
+ public boolean canFlipToNextPage()
+ {
+ return (getErrorMessage() == null) && isPageComplete();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @seecom.motorola.studio.platform.tools.common.ui.composite.BaseBlock#
+ * getErrorMessage()
+ */
+ @Override
+ public String getErrorMessage()
+ {
+ String toReturn = null;
+
+ if (WidgetsUtil.isNullOrEmpty(textAlias))
+ {
+ toReturn =
+ CertificateManagerNLS.bind(CertificateManagerNLS.CertificateBlock_FieldIsEmpty,
+ CertificateManagerNLS.CertificateBlock_AliasName);
+ }
+ else if (WidgetsUtil.isNullOrEmpty(commonNameText)
+ && (WidgetsUtil.isNullOrEmpty(textOrganization))
+ && (WidgetsUtil.isNullOrEmpty(textOrganizationUnit))
+ && (WidgetsUtil.isNullOrEmpty(textLocality))
+ && (WidgetsUtil.isNullOrEmpty(textState))
+ && (WidgetsUtil.isNullOrDeselected(comboCountry)))
+ {
+ toReturn = CertificateManagerNLS.CertificateBlock_DetailedInfoNonEmptyFieldsRestriction;
+ }
+
+ return toReturn;
+ }
+
+ public Composite createInfoBlock(Composite parent, String alias, String name,
+ String organization, String organizationUnit, String country, String state,
+ String locality)
+ {
+ Composite toReturn = createContent(parent);
+ textAlias.setText(alias);
+ commonNameText.setText(name);
+ textOrganization.setText(organization);
+ textOrganizationUnit.setText(organizationUnit);
+ textLocality.setText(locality);
+ textState.setText(state);
+ int i = 0;
+ boolean found = false;
+ while ((i < comboCountry.getItemCount()) && !found)
+ {
+ String id = (String) comboCountry.getData(comboCountry.getItem(i));
+ if (id.equalsIgnoreCase(country))
+ {
+ comboCountry.select(i);
+ found = true;
+ }
+ i++;
+ }
+
+ textAlias.setEditable(false);
+ commonNameText.setEditable(false);
+ textOrganization.setEditable(false);
+ textOrganizationUnit.setEditable(false);
+ textLocality.setEditable(false);
+ textState.setEditable(false);
+ if (!found)
+ {
+ comboCountry.add(CertificateManagerNLS.CertificateInfoDialog_NotAvailableProperty, 0);
+ comboCountry.select(0);
+ }
+ comboCountry.setEnabled(false);
+
+ return toReturn;
+ }
+
+ @Override
+ public void handleEvent(Event event)
+ {
+ if (this.parent != null)
+ {
+ this.parent.notifyListeners(event.type, event);
+ }
+ }
+
+ @Override
+ public void refresh()
+ {
+ // Empty
+ }
+
+ @Override
+ public void setShell(Shell shell)
+ {
+ this.shell = shell;
+ }
+
+ @Override
+ public Shell getShell()
+ {
+ return shell;
+ }
+
+ @Override
+ public void setDefaultFocus()
+ {
+ controlToFocus = textAlias;
+ }
+
+ @Override
+ public void setFocus()
+ {
+ if (controlToFocus != null)
+ {
+ controlToFocus.setFocus();
+ }
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/KeyPropertiesBlock.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/KeyPropertiesBlock.java
new file mode 100644
index 0000000..f0b97f6
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/KeyPropertiesBlock.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.composite;
+
+import java.util.Date;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+import com.motorola.studio.android.common.utilities.ui.WidgetsFactory;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+/**
+ * This class shows the properties to for Android certificates / keys.
+ */
+public class KeyPropertiesBlock extends CertificateBlock
+{
+ private Label labelExpirationDate = null;
+
+ private Text textExpirationDate = null;
+
+ private Label labelCreationDate = null;
+
+ private Text textCreationDate = null;
+
+ @Override
+ protected void createCustomDetailedInfoArea(Composite parent)
+ {
+ labelCreationDate =
+ WidgetsFactory.createLabel(parent,
+ CertificateManagerNLS.CertificateBlock_CreationDate + ":"); //$NON-NLS-1$
+ textCreationDate = WidgetsFactory.createText(parent);
+
+ labelExpirationDate =
+ WidgetsFactory.createLabel(parent,
+ CertificateManagerNLS.CertificateBlock_ExpirationDate + ":"); //$NON-NLS-1$
+ textExpirationDate = WidgetsFactory.createText(parent);
+ }
+
+ public Composite createInfoBlock(Composite parent, String alias, String name,
+ String organization, String organizationUnit, String country, String state,
+ String locality, Date validity, Date creationDate)
+ {
+ Composite toReturn =
+ super.createInfoBlock(parent, alias, name, organization, organizationUnit, country,
+ state, locality);
+ labelCreationDate.setText(CertificateManagerNLS.CertificateBlock_CreationDate + ":"); //$NON-NLS-1$
+ labelCreationDate.setVisible(true);
+ textCreationDate.setTextLimit(Text.LIMIT);
+ textCreationDate.setText(creationDate.toString());
+ textCreationDate.setEditable(false);
+
+ labelExpirationDate.setText(CertificateManagerNLS.CertificateBlock_ExpirationDate + ":"); //$NON-NLS-1$
+ textExpirationDate.setTextLimit(Text.LIMIT);
+ textExpirationDate.setText(validity.toString());
+ textExpirationDate.setEditable(false);
+
+ return toReturn;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/NewKeyBlock.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/NewKeyBlock.java
new file mode 100644
index 0000000..dfeea6f
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/NewKeyBlock.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.composite;
+
+import java.util.Date;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+
+import com.motorola.studio.android.common.utilities.ui.WidgetsFactory;
+import com.motorola.studio.android.common.utilities.ui.WidgetsUtil;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeyWizardPage;
+
+/**
+ * This class shows the field to create a new Android certificates / keys.
+ */
+public class NewKeyBlock extends CertificateBlock
+{
+ private static final int VALIDITY_SIZE = 3;
+
+ private static final int SMALL_TEXT_SIZE = 64;
+
+ private CreateKeyWizardPage baseWizardPage;
+
+ private Label keyPasswordLabel;
+
+ private Label keyConfirmPasswordLabel;
+
+ private Text keyPassword;
+
+ private Text keyConfirmPassword;
+
+ private Button savePasswordCheckBox;
+
+ private Text textValidity = null;
+
+ private Label labelValidity = null;
+
+ private boolean canSavePassword = false;
+
+ private String keyPasswordText = new String();
+
+ private static final String DEFAULT_VALIDITY_IN_YEARS = "30"; //default //$NON-NLS-1$
+
+ @Override
+ public Composite createContent(Composite parent)
+ {
+ Composite composite = super.createContent(parent);
+
+ decorateRequiredFields();
+
+ return composite;
+ };
+
+ @Override
+ protected void createCustomDetailedInfoArea(Composite parent)
+ {
+ labelValidity =
+ WidgetsFactory.createLabel(parent, CertificateManagerNLS.CertificateBlock_Validity
+ + ":"); //$NON-NLS-1$
+ textValidity = WidgetsFactory.createText(parent);
+ textValidity.addListener(SWT.Modify, this);
+ textValidity.addFocusListener(focusListener);
+ textValidity.setTextLimit(VALIDITY_SIZE);
+ textValidity.setText(DEFAULT_VALIDITY_IN_YEARS);
+ }
+
+ /* (non-Javadoc)
+ * @see com.motorolamobility.studio.android.certmanager.ui.composite.CertificateBlock#createCustomArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected void createCustomArea(Composite parent)
+ {
+ Group passwordGroup =
+ WidgetsFactory.createTitledGroup(parent,
+ CertificateManagerNLS.NewKeyBlock_PasswordGroupTitle, 2);
+
+ //KEYSTORE PASSWORD SECTION
+ keyPasswordLabel = new Label(passwordGroup, SWT.NONE);
+ keyPasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keyPasswordLabel.setText(CertificateManagerNLS.CertificateBlock_KeyPassword_Label + ":"); //$NON-NLS-2$ //$NON-NLS-1$
+
+ keyPassword = new Text(passwordGroup, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
+ keyPassword.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ keyPassword.setTextLimit(SMALL_TEXT_SIZE);
+ keyPassword.addListener(SWT.Modify, new Listener()
+ {
+ @Override
+ public void handleEvent(Event event)
+ {
+ keyPasswordText = keyPassword.getText();
+ NewKeyBlock.super.handleEvent(event);
+ }
+ });
+
+ keyPassword.addFocusListener(focusListener);
+
+ //CONFIRM PASSWORD SECTION
+ keyConfirmPasswordLabel = new Label(passwordGroup, SWT.NONE);
+ keyConfirmPasswordLabel
+ .setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keyConfirmPasswordLabel
+ .setText(CertificateManagerNLS.CertificateBlock_ConfirmKeyPassword_Label + ":"); //$NON-NLS-2$ //$NON-NLS-1$
+
+ keyConfirmPassword = new Text(passwordGroup, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
+ keyConfirmPassword.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ keyConfirmPassword.addListener(SWT.Modify, this);
+ keyConfirmPassword.addFocusListener(focusListener);
+ keyConfirmPassword.setTextLimit(SMALL_TEXT_SIZE);
+
+ //Creates the save password checkbox
+ savePasswordCheckBox = new Button(passwordGroup, SWT.CHECK);
+ savePasswordCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+ savePasswordCheckBox.setText(CertificateManagerNLS.PasswordProvider_SaveThisPassword);
+ savePasswordCheckBox.setSelection(false);
+ savePasswordCheckBox.addFocusListener(focusListener);
+
+ if ((baseWizardPage != null) && (baseWizardPage.getKeystore() != null))
+ {
+ //we can not save password if keystore is not mapped in the view
+ savePasswordCheckBox.setVisible(KeyStoreManager.getInstance().isKeystoreMapped(
+ baseWizardPage.getKeystore().getFile()));
+ }
+ savePasswordCheckBox.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ //update according to check status
+ canSavePassword = savePasswordCheckBox.getSelection();
+ }
+
+ });
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.motorolamobility.studio.android.certmanager.ui.composite.CertificateBlock#decorateRequiredFields()
+ */
+ @Override
+ protected void decorateRequiredFields()
+ {
+ super.decorateRequiredFields();
+
+ labelValidity.setText(decorateText(labelValidity.getText()));
+ keyPasswordLabel.setText(decorateText(keyPasswordLabel.getText()));
+ keyConfirmPasswordLabel.setText(decorateText(keyConfirmPasswordLabel.getText()));
+ }
+
+ @Override
+ public boolean isPageComplete()
+ {
+ return (super.isPageComplete()) && !WidgetsUtil.isNullOrEmpty(this.textValidity)
+ && !WidgetsUtil.isNullOrEmpty(this.keyPassword)
+ && !WidgetsUtil.isNullOrEmpty(this.keyConfirmPassword);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @seecom.motorola.studio.platform.tools.common.ui.composite.BaseBlock#
+ * canFlipToNextPage()
+ */
+ @Override
+ public boolean canFlipToNextPage()
+ {
+ return super.canFlipToNextPage() && !WidgetsUtil.isNullOrEmpty(this.textValidity)
+ && !WidgetsUtil.isNullOrEmpty(this.keyPassword)
+ && !WidgetsUtil.isNullOrEmpty(this.keyConfirmPassword);
+ }
+
+ public Composite createInfoBlock(Composite parent, String alias, String name,
+ String organization, String organizationUnit, String country, String state,
+ String locality, Date validity, Date creationDate)
+ {
+ Composite toReturn =
+ super.createInfoBlock(parent, alias, name, organization, organizationUnit, country,
+ state, locality);
+ labelValidity.setText(CertificateManagerNLS.CertificateBlock_ExpirationDate + ":"); //$NON-NLS-1$
+ textValidity.setTextLimit(Text.LIMIT);
+ textValidity.setText(validity.toString());
+ textValidity.setEditable(false);
+
+ keyPasswordLabel.setVisible(false);
+ keyPassword.setVisible(false);
+ keyConfirmPasswordLabel.setVisible(false);
+ keyConfirmPassword.setVisible(false);
+ savePasswordCheckBox.setVisible(false);
+
+ return toReturn;
+ }
+
+ public String getKeyPassword()
+ {
+ return keyPasswordText;
+ }
+
+ public String getKeyConfirmPassword()
+ {
+ return keyConfirmPassword.getText();
+ }
+
+ public boolean needToSaveKeyPassword()
+ {
+ return canSavePassword;
+ }
+
+ @Override
+ public String getErrorMessage()
+ {
+ String message = super.getErrorMessage();
+
+ //if there is no error message on other items => check text validity field
+ if (message == null)
+ {
+ try
+ {
+ int validity = Integer.parseInt(textValidity.getText());
+ if (validity <= 0)
+ {
+ throw new NumberFormatException();
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ message = CertificateManagerNLS.CertificateBlock_Validity_Error; //$NON-NLS-1$
+ }
+ }
+
+ //if there is no error message on other items => check password fields
+ if (message == null)
+ {
+ //password text and confirmation password text must match
+ if (!keyPassword.getText().equals(keyConfirmPassword.getText()))
+ {
+ message = CertificateManagerNLS.CreateKeystorePage_PasswordDoesNotMatch;
+ }
+ //check password size according to keytool specification
+ if (keyPassword.getText().length() < EntryNode.KEY_PASSWORD_MIN_SIZE)
+ {
+ message =
+ CertificateManagerNLS.bind(
+ CertificateManagerNLS.CreateKeystorePage_PasswordMinSizeMessage,
+ IKeyStore.KEYSTORE_PASSWORD_MIN_SIZE); //$NON-NLS-1$
+ }
+
+ }
+
+ return message;
+ }
+
+ /**
+ * Set messages (used to set information messages)
+ * @param message
+ * @param messageType IMessageProvider.INFORMATION
+ */
+ protected void setMessage(String message, int messageType)
+ {
+ if (baseWizardPage != null)
+ {
+ baseWizardPage.setMessage(message, messageType);
+ }
+ }
+
+ public String getValidity()
+ {
+ return textValidity.getText();
+ }
+
+ /**
+ * @param baseWizardPage the baseWizardPage to set
+ */
+ public void setBaseWizardPage(CreateKeyWizardPage baseWizardPage)
+ {
+ this.baseWizardPage = baseWizardPage;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupContentProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupContentProvider.java
new file mode 100644
index 0000000..ec916ea
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupContentProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.dialogs;
+
+import java.util.List;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+public class BackupContentProvider implements IStructuredContentProvider
+{
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ //do nothing
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement)
+ {
+ Object[] elements = null;
+ if (inputElement instanceof List)
+ {
+ elements = ((List<?>) inputElement).toArray();
+ }
+ else if (inputElement instanceof String[])
+ {
+ elements = (String[]) inputElement;
+ }
+ return elements;
+ }
+
+} \ No newline at end of file
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupDialog.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupDialog.java
new file mode 100644
index 0000000..65cd6ed
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupDialog.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.dialogs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.FileUtil;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+public class BackupDialog extends TitleAreaDialog
+{
+
+ private static final String ZIP_EXT = ".zip"; //$NON-NLS-1$
+
+ private static final String WIZARD_BANNER = "icons/wizban/backup_keystore_wiz.png"; //$NON-NLS-1$
+
+ private static final String BACKUP_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".backup_keystore"; //$NON-NLS-1$;
+
+ private final IContentProvider contentProvider;
+
+ private final IBaseLabelProvider labelProvider;
+
+ private CheckboxTableViewer tableViewer;
+
+ private Object input;
+
+ private final String title;
+
+ private File archiveFile;
+
+ private List<String> selectedKeyStores;
+
+ private String archivePath;
+
+ private boolean verifyOverwrite;
+
+ private Button selectAllButton;
+
+ public BackupDialog(Shell parentShell)
+ {
+ super(parentShell);
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ this.contentProvider = new BackupContentProvider();
+ this.labelProvider = new BackupLabelProvider();
+ this.title = CertificateManagerNLS.BackupDialog_Diag_Title;
+ this.archivePath = ""; //$NON-NLS-1$
+ selectedKeyStores = new ArrayList<String>();
+ setTitleImage(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER).createImage());
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ getShell().setText(title);
+ setTitle(CertificateManagerNLS.BackupDialog_DialogTitle);
+ //the shell has the same help as its page
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(getShell(), BackupDialog.BACKUP_KEYSTORE_HELP_ID);
+
+ Composite dialogArea = new Composite(parent, SWT.FILL);
+ dialogArea.setLayout(new GridLayout());
+ dialogArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Group pathGroup = new Group(dialogArea, SWT.SHADOW_NONE);
+ pathGroup.setText(CertificateManagerNLS.BackupDialog_Backup_File);
+ pathGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ pathGroup.setLayout(new GridLayout(3, false));
+
+ Label pathLabel = new Label(pathGroup, SWT.NONE);
+ pathLabel.setText(CertificateManagerNLS.BackupDialog_Path);
+ pathLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+ final Text pathText = new Text(pathGroup, SWT.BORDER);
+ pathText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ pathText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ archivePath = pathText.getText();
+ archiveFile = new File(archivePath);
+ verifyOverwrite = true;
+ validate();
+ }
+ });
+
+ Button browseButton = new Button(pathGroup, SWT.PUSH);
+ browseButton.setText(CertificateManagerNLS.BackupDialog_Browse);
+ browseButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ browseButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ FileDialog fileDialog = new FileDialog(getShell(), SWT.SAVE);
+ fileDialog.setFilterExtensions(new String[]
+ {
+ "*" + ZIP_EXT //$NON-NLS-1$
+ });
+ fileDialog.setOverwrite(true);
+ String choosenPath = fileDialog.open();
+ pathText.setText(choosenPath);
+ verifyOverwrite = false;
+ super.widgetSelected(e);
+ }
+ });
+
+ Group keystoresGroup = new Group(dialogArea, SWT.SHADOW_NONE);
+ keystoresGroup.setText(CertificateManagerNLS.BackupDialog_KeyStores);
+ keystoresGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ keystoresGroup.setLayout(new GridLayout(1, false));
+
+ tableViewer =
+ CheckboxTableViewer.newCheckList(keystoresGroup, SWT.H_SCROLL | SWT.V_SCROLL
+ | SWT.CHECK | SWT.BORDER);
+ tableViewer.setContentProvider(contentProvider);
+ tableViewer.setLabelProvider(labelProvider);
+ tableViewer.setInput(input);
+ selectKeystores();
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ layoutData.widthHint = 400;
+ layoutData.heightHint = 200;
+ tableViewer.getControl().setLayoutData(layoutData);
+ tableViewer.addCheckStateListener(new ICheckStateListener()
+ {
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event)
+ {
+ String keyStore = null;
+ Object element = event.getElement();
+ if (element instanceof String)
+ {
+ keyStore = (String) element;
+ }
+
+ if (keyStore != null)
+ {
+ if (event.getChecked())
+ {
+ selectedKeyStores.add(keyStore);
+ }
+ else
+ {
+ selectedKeyStores.remove(keyStore);
+ }
+ }
+
+ updateSelectAllState();
+
+ validate();
+ }
+ });
+ Composite selectButtonArea = new Composite(keystoresGroup, SWT.NONE);
+ selectButtonArea.setLayout(new GridLayout(1, true));
+ selectButtonArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ selectAllButton = new Button(selectButtonArea, SWT.CHECK);
+ selectAllButton.setText(CertificateManagerNLS.BackupDialog_Select_All);
+ selectAllButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+ selectAllButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableViewer.setAllChecked(selectAllButton.getSelection());
+ selectedKeyStores.clear();
+
+ for (Object element : tableViewer.getCheckedElements())
+ {
+ String keyStoreEl = (String) element;
+ selectedKeyStores.add(keyStoreEl);
+ }
+ validate();
+ super.widgetSelected(e);
+ }
+ });
+
+ updateSelectAllState();
+
+ setMessage(CertificateManagerNLS.BackupDialog_Default_Message);
+ return dialogArea;
+ }
+
+ private void updateSelectAllState()
+ {
+ if (tableViewer.getCheckedElements().length == tableViewer.getTable().getItems().length)
+ {
+ selectAllButton.setSelection(true);
+ }
+ else
+ {
+ selectAllButton.setSelection(false);
+ }
+ }
+
+ @Override
+ protected Control createButtonBar(Composite parent)
+ {
+ Control buttonBar = super.createButtonBar(parent);
+ getButton(OK).setEnabled(false);
+ return buttonBar;
+ }
+
+ @Override
+ protected void okPressed()
+ {
+ boolean canContinue = true;
+ if (verifyOverwrite && archiveFile.exists())
+ {
+ boolean canOvewrite =
+ EclipseUtils.showQuestionDialog(
+ CertificateManagerNLS.BackupDialog_Archive_Exists_Title, NLS.bind(
+ CertificateManagerNLS.BackupDialog_Archive_Exists_Message,
+ archiveFile));
+
+ if (!canOvewrite)
+ {
+ canContinue = false;
+ }
+ else
+ {
+ archiveFile.delete();
+ }
+ }
+
+ if (canContinue)
+ {
+ if (!FileUtil.canWrite(archiveFile))
+ {
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.BackupDialog_Fail_Writing_Archive_Title, NLS.bind(
+ CertificateManagerNLS.BackupDialog_Fail_Writing_Archive_Message,
+ archiveFile));
+
+ }
+ else
+ {
+ setErrorMessage(null);
+ super.okPressed();
+ }
+ }
+ }
+
+ private void validate()
+ {
+
+ boolean isValid = true;
+ boolean hasWarn = false;
+ Path path = new Path(archivePath);
+ try
+ {
+ if (archivePath.isEmpty() || !path.isValidPath(archiveFile.getCanonicalPath()))
+ {
+ setErrorMessage(CertificateManagerNLS.BackupDialog_Invalid_Destination_Title);
+ isValid = false;
+ }
+ }
+ catch (IOException e)
+ {
+ setErrorMessage(CertificateManagerNLS.BackupDialog_Invalid_Destination_Title);
+ isValid = false;
+ }
+
+ if (isValid)
+ {
+ if (archiveFile.exists() && (archiveFile.isDirectory()))
+ {
+ setErrorMessage(CertificateManagerNLS.BackupDialog_Invalid_Destination_Message);
+ isValid = false;
+ }
+ }
+
+ if (isValid)
+ {
+ if (!archiveFile.isAbsolute())
+ {
+ setMessage(
+ NLS.bind(CertificateManagerNLS.BackupDialog_Non_Absolute_Path,
+ archiveFile.getAbsolutePath()), IMessageProvider.WARNING);
+ hasWarn = true;
+ }
+ }
+
+ if (isValid)
+ {
+ if (selectedKeyStores.isEmpty())
+ {
+ setErrorMessage(CertificateManagerNLS.BackupDialog_Select_KeyStore);
+ isValid = false;
+ }
+ else
+ {
+ setErrorMessage(null);
+ if (!hasWarn)
+ {
+ setMessage(CertificateManagerNLS.BackupDialog_Default_Message);
+ }
+ isValid = true;
+ }
+ }
+
+ getButton(OK).setEnabled(isValid);
+ }
+
+ public void setInput(Object input)
+ {
+ if (tableViewer != null)
+ {
+ tableViewer.setInput(input);
+ }
+ this.input = input;
+ }
+
+ /**
+ * @return the Archive file to be created
+ */
+ public File getArchiveFile()
+ {
+ return archiveFile.getName().toLowerCase().endsWith(ZIP_EXT) ? archiveFile : new File(
+ archivePath + ZIP_EXT);
+ }
+
+ /**
+ * @return the Keystores file paths to be archived
+ */
+ public List<String> getSelectedKeyStores()
+ {
+ return selectedKeyStores;
+ }
+
+ public void selectKeyStores(List<ITreeNode> keystores)
+ {
+ for (ITreeNode treeNode : keystores)
+ {
+ if (treeNode instanceof IKeyStore)
+ {
+ IKeyStore keystore = (IKeyStore) treeNode;
+ selectedKeyStores.add(keystore.getFile().getAbsolutePath());
+ }
+ }
+ }
+
+ private void selectKeystores()
+ {
+ for (TableItem item : tableViewer.getTable().getItems())
+ {
+ item.setChecked(selectedKeyStores.contains(item.getText()));
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupLabelProvider.java
new file mode 100644
index 0000000..6e4fa90
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupLabelProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.dialogs;
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.swt.graphics.Image;
+
+public class BackupLabelProvider implements ILabelProvider
+{
+
+ @Override
+ public void addListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property)
+ {
+ return false;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public Image getImage(Object element)
+ {
+ return null;
+ }
+
+ @Override
+ public String getText(Object element)
+ {
+ String text = null;
+ if (element instanceof String)
+ {
+ text = (String) element;
+ }
+ return text;
+ }
+
+} \ No newline at end of file
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/CertificateInfoDialog.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/CertificateInfoDialog.java
new file mode 100644
index 0000000..53fbbf3
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/CertificateInfoDialog.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.dialogs;
+
+import java.security.cert.X509Certificate;
+
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.composite.KeyPropertiesBlock;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+
+/**
+ * Dialog to show certificate info.
+ */
+public class CertificateInfoDialog extends Dialog
+{
+ private static final String HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".certificate_info_dialog"; //$NON-NLS-1$
+
+ final private KeyPropertiesBlock block;
+
+ final private EntryNode entry;
+
+ public CertificateInfoDialog(Shell parentShell, KeyPropertiesBlock blk, EntryNode entry)
+ {
+ super(parentShell);
+ this.block = blk;
+ this.entry = entry;
+ }
+
+ @Override
+ protected Control createContents(Composite parent)
+ {
+ if (parent instanceof Shell)
+ {
+ ((Shell) parent).setText(CertificateManagerNLS.CertificateInfoDialog_ShellTitle);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, HELP_ID);
+ }
+ return super.createContents(parent);
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent)
+ {
+ createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ Composite newComposite = (Composite) super.createDialogArea(parent);
+ X509Certificate cert = null;
+
+ try
+ {
+ cert = entry.getX509Certificate();
+
+ if (cert != null)
+ {
+ X500Name x500name = new JcaX509CertificateHolder(cert).getSubject();
+ RDN commonName =
+ x500name.getRDNs(BCStyle.CN).length >= 1 ? x500name.getRDNs(BCStyle.CN)[0]
+ : null;
+ RDN organization =
+ x500name.getRDNs(BCStyle.O).length >= 1 ? x500name.getRDNs(BCStyle.O)[0]
+ : null;
+ RDN organizationUnit =
+ x500name.getRDNs(BCStyle.OU).length >= 1 ? x500name.getRDNs(BCStyle.OU)[0]
+ : null;
+ RDN country =
+ x500name.getRDNs(BCStyle.C).length >= 1 ? x500name.getRDNs(BCStyle.C)[0]
+ : null;
+ RDN state =
+ x500name.getRDNs(BCStyle.ST).length >= 1 ? x500name.getRDNs(BCStyle.ST)[0]
+ : null;
+ RDN locality =
+ x500name.getRDNs(BCStyle.L).length >= 1 ? x500name.getRDNs(BCStyle.L)[0]
+ : null;
+
+ block.createInfoBlock(newComposite, entry.getAlias(), printCertInfo(commonName),
+ printCertInfo(organization), printCertInfo(organizationUnit),
+ printCertInfo(country), printCertInfo(state), printCertInfo(locality),
+ cert.getNotAfter(), cert.getNotBefore());
+ }
+ else
+ {
+ //not found Android certificate expected (X509Certificate)
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.CertificateInfoDialog_UnknownCertificateKeypairType,
+ CertificateManagerNLS.CertificatePropertiesHandler_ErrorGettingCertificateOrKeypairProperties);
+ }
+ }
+ catch (Exception e)
+ {
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.CertificatePropertiesHandler_ErrorGettingCertificateOrKeypairProperties,
+ e.getMessage());
+ StudioLogger
+ .error(CertificateInfoDialog.class,
+ CertificateManagerNLS.CertificatePropertiesHandler_ErrorGettingCertificateOrKeypairProperties,
+ e);
+ }
+ return newComposite;
+ }
+
+ private String printCertInfo(RDN certItem)
+ {
+ return certItem != null ? certItem.getFirst().getValue().toString()
+ : CertificateManagerNLS.CertificateInfoDialog_NotAvailableProperty;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/RestoreBackupDialog.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/RestoreBackupDialog.java
new file mode 100644
index 0000000..64f364c
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/RestoreBackupDialog.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.dialogs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.command.BackupHandler;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+public class RestoreBackupDialog extends TitleAreaDialog
+{
+
+ private static final String ZIP_EXT = "*.zip"; //$NON-NLS-1$
+
+ private static final String WIZARD_BANNER = "icons/wizban/restore_keystore_wiz.png"; //$NON-NLS-1$
+
+ public static final String RESTORE_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".restore_keystore"; //$NON-NLS-1$
+
+ private final IContentProvider contentProvider;
+
+ private final IBaseLabelProvider labelProvider;
+
+ private CheckboxTableViewer tableViewer;
+
+ private final String title;
+
+ private File archiveFile;
+
+ private List<String> selectedKeyStores;
+
+ private File destinationFile;
+
+ private Button selectAllButton;
+
+ private String destinationPath = ""; //$NON-NLS-1$
+
+ public RestoreBackupDialog(Shell parentShell)
+ {
+ super(parentShell);
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ this.contentProvider = new BackupContentProvider();
+ this.labelProvider = new BackupLabelProvider();
+ this.title = CertificateManagerNLS.RestoreBackupDialog_Dialog_Title;
+ selectedKeyStores = new ArrayList<String>();
+ setTitleImage(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER).createImage());
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ getShell().setText(title);
+ setTitle(CertificateManagerNLS.RestoreBackupDialog_TitleArea_Message);
+
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(getShell(), RestoreBackupDialog.RESTORE_KEYSTORE_HELP_ID);
+
+ Composite dialogArea = new Composite(parent, SWT.FILL);
+ dialogArea.setLayout(new GridLayout());
+ dialogArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Group pathGroup = new Group(dialogArea, SWT.SHADOW_NONE);
+ pathGroup.setText(CertificateManagerNLS.RestoreBackupDialog_Path_Group);
+ pathGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ pathGroup.setLayout(new GridLayout(3, false));
+
+ Label pathLabel = new Label(pathGroup, SWT.NONE);
+ pathLabel.setText(CertificateManagerNLS.RestoreBackupDialog_BackUp_File);
+ pathLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+ final Text pathText = new Text(pathGroup, SWT.BORDER);
+ pathText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ pathText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ archiveFile = new File(pathText.getText());
+ selectAllButton.setSelection(false);
+ validate();
+ loadArchiveEntries();
+ }
+ });
+
+ Button browseButton = new Button(pathGroup, SWT.PUSH);
+ browseButton.setText(CertificateManagerNLS.RestoreBackupDialog_Browse_Button);
+ browseButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ browseButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ FileDialog fileDialog = new FileDialog(getShell());
+ fileDialog.setFilterExtensions(new String[]
+ {
+ ZIP_EXT
+ });
+ fileDialog.setOverwrite(false);
+ String choosenPath = fileDialog.open();
+ pathText.setText(choosenPath);
+ super.widgetSelected(e);
+ }
+ });
+
+ Label destinPath = new Label(pathGroup, SWT.NONE);
+ destinPath.setText(CertificateManagerNLS.RestoreBackupDialog_Destination);
+ destinPath.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+ final Text destinText = new Text(pathGroup, SWT.BORDER);
+ destinText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ destinText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ destinationPath = destinText.getText();
+ destinationFile = new File(destinationPath);
+ validate();
+ }
+ });
+
+ Button destinBrowseButton = new Button(pathGroup, SWT.PUSH);
+ destinBrowseButton.setText(CertificateManagerNLS.RestoreBackupDialog_Browse_Button);
+ destinBrowseButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ destinBrowseButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ DirectoryDialog directoryDialog = new DirectoryDialog(getShell());
+ String choosenPath = directoryDialog.open();
+ destinText.setText(choosenPath);
+ super.widgetSelected(e);
+ }
+ });
+
+ Group keystoresGroup = new Group(dialogArea, SWT.SHADOW_NONE);
+ keystoresGroup.setText(CertificateManagerNLS.RestoreBackupDialog_KeyStores);
+ keystoresGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ keystoresGroup.setLayout(new GridLayout(1, false));
+
+ tableViewer =
+ CheckboxTableViewer.newCheckList(keystoresGroup, SWT.H_SCROLL | SWT.V_SCROLL
+ | SWT.CHECK | SWT.BORDER);
+ tableViewer.setContentProvider(contentProvider);
+ tableViewer.setLabelProvider(labelProvider);
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ layoutData.widthHint = 400;
+ layoutData.heightHint = 200;
+ tableViewer.getControl().setLayoutData(layoutData);
+ tableViewer.addCheckStateListener(new ICheckStateListener()
+ {
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event)
+ {
+ String keyStore = null;
+ Object element = event.getElement();
+ if (element instanceof String)
+ {
+ keyStore = (String) element;
+ }
+
+ if (keyStore != null)
+ {
+ if (event.getChecked())
+ {
+ selectedKeyStores.add(keyStore);
+ }
+ else
+ {
+ selectedKeyStores.remove(keyStore);
+ }
+ }
+
+ if (tableViewer.getCheckedElements().length == tableViewer.getTable().getItems().length)
+ {
+ selectAllButton.setSelection(true);
+ }
+ else
+ {
+ selectAllButton.setSelection(false);
+ }
+
+ validate();
+ }
+ });
+
+ Composite selectButtonArea = new Composite(keystoresGroup, SWT.NONE);
+ selectButtonArea.setLayout(new GridLayout(1, true));
+ selectButtonArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ selectAllButton = new Button(selectButtonArea, SWT.CHECK);
+ selectAllButton.setText(CertificateManagerNLS.RestoreBackupDialog_Select_All);
+ selectAllButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+ selectAllButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableViewer.setAllChecked(selectAllButton.getSelection());
+ selectedKeyStores.clear();
+ for (Object element : tableViewer.getCheckedElements())
+ {
+ String keyStoreEl = (String) element;
+ selectedKeyStores.add(keyStoreEl);
+ }
+ validate();
+ super.widgetSelected(e);
+ }
+ });
+
+ setMessage(CertificateManagerNLS.RestoreBackupDialog_Default_Message);
+ return dialogArea;
+ }
+
+ protected void loadArchiveEntries()
+ {
+ Runnable loadRunnable = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ if (archiveFile.exists())
+ {
+ @SuppressWarnings("rawtypes")
+ final List[] holderArray = new List[1];
+
+ ZipFile zipFile = null;
+ try
+ {
+ zipFile = new ZipFile(archiveFile, ZipFile.OPEN_READ);
+ ArrayList<String> keyStores = new ArrayList<String>(zipFile.size());
+ holderArray[0] = keyStores;
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements())
+ {
+ ZipEntry zipEntry = entries.nextElement();
+ if (!zipEntry.getName().equalsIgnoreCase(
+ BackupHandler.KS_TYPES_FILENAME))
+ {
+ keyStores.add(zipEntry.getName());
+ }
+ }
+ Display.getDefault().syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ tableViewer.setInput(holderArray[0]);
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ Display.getDefault().asyncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ clearKeystoresTableViewer();
+ setErrorMessage(NLS
+ .bind(CertificateManagerNLS.RestoreBackupDialog_Error_Loading_Entries,
+ archiveFile));
+ getButton(OK).setEnabled(false);
+ }
+ });
+ }
+ finally
+ {
+ if (zipFile != null)
+ {
+ try
+ {
+ zipFile.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger
+ .error("Could not close stream while restoring backup. "
+ + e.getMessage());
+ }
+ }
+ }
+ }
+ }
+ };
+
+ Thread thread = new Thread(loadRunnable);
+ thread.start();
+ }
+
+ @Override
+ protected Control createButtonBar(Composite parent)
+ {
+ Control buttonBar = super.createButtonBar(parent);
+ getButton(OK).setEnabled(false);
+ return buttonBar;
+ }
+
+ private void validate()
+ {
+
+ boolean isValid = true;
+
+ if (!archiveFile.exists())
+ {
+ clearKeystoresTableViewer();
+ setErrorMessage(CertificateManagerNLS.RestoreBackupDialog_BackUpFile_Not_Exist);
+ isValid = false;
+ }
+ else
+ {
+ setErrorMessage(null);
+ isValid = true;
+ }
+
+ if (isValid)
+ {
+ if (destinationPath.isEmpty())
+ {
+ setErrorMessage(CertificateManagerNLS.RestoreBackupDialog_Invalid_Dest_Path);
+ isValid = false;
+ }
+ else
+ {
+ if ((destinationFile != null) && destinationFile.isFile())
+ {
+ setErrorMessage(CertificateManagerNLS.RestoreBackupDialog_Invalid_Dest_Path);
+ isValid = false;
+ }
+ else
+ {
+ setErrorMessage(null);
+ isValid = true;
+ }
+ }
+ }
+
+ if (isValid)
+ {
+ if (selectedKeyStores.isEmpty())
+ {
+ setErrorMessage(CertificateManagerNLS.RestoreBackupDialog_Select_KeyStore);
+ isValid = false;
+ }
+ else
+ {
+ setErrorMessage(null);
+ isValid = true;
+ }
+ }
+
+ getButton(OK).setEnabled(isValid);
+ }
+
+ /**
+ * Remove all entries from keystores table viewer.
+ * */
+ private void clearKeystoresTableViewer()
+ {
+ tableViewer.setInput(null);
+ }
+
+ /**
+ * @return The back archive file
+ */
+ public File getArchiveFile()
+ {
+ return archiveFile;
+ }
+
+ /**
+ * @return The keystores to be restored
+ */
+ public List<String> getSelectedKeyStores()
+ {
+ return selectedKeyStores;
+ }
+
+ /**
+ * @return The destination directory
+ */
+ public File getDestinationDir()
+ {
+ return destinationFile;
+ }
+
+} \ No newline at end of file
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ConvertKeyStoreTypeDialog.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ConvertKeyStoreTypeDialog.java
new file mode 100644
index 0000000..aa697b4
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ConvertKeyStoreTypeDialog.java
@@ -0,0 +1,633 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.dialogs.importks;
+
+import java.io.File;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.PasswordProtection;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+public class ConvertKeyStoreTypeDialog extends TitleAreaDialog
+{
+ public class EntryModel
+ {
+
+ private final String alias;
+
+ private String passwd;
+
+ private boolean verified;
+
+ public EntryModel(String alias)
+ {
+ this.alias = alias;
+ try
+ {
+ String savedPass = keyStore.getPasswordProvider().getPassword(alias, false);
+ setPasswd(savedPass != null ? savedPass : ""); //$NON-NLS-1$
+ }
+ catch (KeyStoreManagerException e)
+ {
+ setPasswd(""); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return alias;
+ }
+
+ public String getPasswd()
+ {
+ return passwd;
+ }
+
+ public void setPasswd(String passwd)
+ {
+ this.passwd = passwd;
+ try
+ {
+ Entry entry =
+ keyStore.getKeyStore().getEntry(alias,
+ new PasswordProtection(passwd.toCharArray()));
+ setVerified(entry != null);
+ }
+ catch (Exception e)
+ {
+ setVerified(false);
+ }
+ aliaseMap.put(alias, passwd);
+ }
+
+ public String getAlias()
+ {
+ return alias;
+ }
+
+ public boolean isVerified()
+ {
+ return verified;
+ }
+
+ private void setVerified(boolean verified)
+ {
+ this.verified = verified;
+ validateUi();
+ }
+ }
+
+ public class EntriesContentProvider implements IStructuredContentProvider
+ {
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ //do nothing
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement)
+ {
+ List<EntryModel> modelList = null;
+ if (inputElement instanceof List<?>)
+ {
+ List<?> inputList = (List<?>) inputElement;
+ modelList = new ArrayList<EntryModel>(inputList.size());
+ Iterator<?> it = inputList.iterator();
+ while (it.hasNext())
+ {
+ Object element = it.next();
+ if (element instanceof String) //received an alias
+ {
+ String alias = (String) element;
+ EntryModel entryModel = new EntryModel(alias);
+ modelList.add(entryModel);
+ }
+ }
+
+ }
+ return modelList.toArray();
+ }
+
+ }
+
+ private final class PasswordEditingSupport extends EditingSupport
+ {
+ private PasswordEditingSupport(ColumnViewer viewer)
+ {
+ super(viewer);
+ }
+
+ @Override
+ protected boolean canEdit(Object element)
+ {
+ return true;
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element)
+ {
+ return new TextCellEditor(entriesTable, SWT.PASSWORD);
+ }
+
+ @Override
+ protected Object getValue(Object element)
+ {
+ return ((EntryModel) element).getPasswd();
+ }
+
+ @Override
+ protected void setValue(Object element, Object value)
+ {
+ EntryModel model = (EntryModel) element;
+ model.setPasswd((String) value);
+ getViewer().update(element, null);
+ }
+ }
+
+ private static final String HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".convert_keystore_type"; //$NON-NLS-1$
+
+ private static final String WIZARD_BANNER = "icons/wizban/change_keystore_type_wiz.png"; //$NON-NLS-1$
+
+ private IKeyStore keyStore;
+
+ private String newType = ""; //$NON-NLS-1$
+
+ private Text passwdText;
+
+ private String password = ""; //$NON-NLS-1$
+
+ private Table entriesTable;
+
+ private TableViewer entriesTableViewer;
+
+ private final Map<String, String> aliaseMap = new HashMap<String, String>();
+
+ /**
+ * Create the dialog.
+ * @param parentShell
+ */
+ public ConvertKeyStoreTypeDialog(Shell parentShell, IKeyStore keyStore)
+ {
+ super(parentShell);
+ setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
+
+ this.keyStore = keyStore;
+ setTitleImage(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER).createImage());
+ }
+
+ /**
+ * Create contents of the dialog.
+ * @param parent
+ */
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ parent.getShell().setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_DialogTitle);
+ setMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_DefaultMessage);
+ setTitle(CertificateManagerNLS.ConvertKeyStoreTypeDialog_DialogTitle);
+ Composite area = (Composite) super.createDialogArea(parent);
+ Composite container = new Composite(area, SWT.NONE);
+ container.setLayout(new GridLayout(1, false));
+ container.setLayoutData(new GridData(GridData.FILL_BOTH));
+ Composite convertTopComposite = new Composite(container, SWT.NONE);
+ convertTopComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1));
+ convertTopComposite.setLayout(new GridLayout(1, false));
+
+ Composite keyStoreComposite = new Composite(convertTopComposite, SWT.NONE);
+ keyStoreComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ keyStoreComposite.setLayout(new GridLayout(3, false));
+
+ Label keyStoreLabel = new Label(keyStoreComposite, SWT.NONE);
+ keyStoreLabel.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_KeyStoreLabel);
+
+ final Combo keyStoreCombo = new Combo(keyStoreComposite, SWT.READ_ONLY);
+ keyStoreCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ final KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();
+ try
+ {
+ List<IKeyStore> keyStores = keyStoreManager.getKeyStores();
+ for (IKeyStore keyStore : keyStores)
+ {
+ File ksFile = keyStore.getFile();
+ String comboItem = ksFile.getName() + " - " + ksFile.getAbsolutePath(); //$NON-NLS-1$
+ keyStoreCombo.add(comboItem);
+ keyStoreCombo.setData(comboItem, keyStore);
+ if (keyStore.equals(this.keyStore))
+ {
+ keyStoreCombo.select(keyStoreCombo.indexOf(comboItem));
+ }
+ }
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_CouldNotLoad_Keystores_Error);
+ }
+
+ Label passwdLabel = new Label(keyStoreComposite, SWT.NONE);
+ passwdLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ passwdLabel.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Password_Label);
+
+ passwdText = new Text(keyStoreComposite, SWT.BORDER | SWT.PASSWORD);
+ passwdText.addModifyListener(new ModifyListener()
+ {
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ password = passwdText.getText();
+ }
+ });
+ passwdText.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e)
+ {
+ super.widgetDefaultSelected(e);
+ loadEntries();
+ }
+ });
+ passwdText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ Button loadButton = new Button(keyStoreComposite, SWT.NONE);
+ GridData gd_loadButton = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ gd_loadButton.widthHint = 80;
+ loadButton.setLayoutData(gd_loadButton);
+ loadButton.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Load_Button);
+ loadButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ loadEntries();
+ }
+ });
+
+ Composite composite_1 = new Composite(convertTopComposite, SWT.NONE);
+ GridData gd_composite_1 = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1);
+ gd_composite_1.heightHint = 39;
+ composite_1.setLayoutData(gd_composite_1);
+ composite_1.setLayout(new GridLayout(4, false));
+
+ Label typeLabel = new Label(composite_1, SWT.NONE);
+ typeLabel.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Original_Type_Label);
+
+ final Label currentTypeLabel = new Label(composite_1, SWT.NONE);
+ GridData gd_currentTypeLabel = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
+ gd_currentTypeLabel.widthHint = 90;
+ gd_currentTypeLabel.minimumWidth = 90;
+ currentTypeLabel.setLayoutData(gd_currentTypeLabel);
+ currentTypeLabel.setText(keyStore.getType());
+
+ Label newTypeLabel = new Label(composite_1, SWT.NONE);
+ newTypeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ newTypeLabel.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_NewType_Label);
+
+ final Combo typeCombo = new Combo(composite_1, SWT.READ_ONLY);
+ typeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ loadTypeCombo(keyStoreManager, typeCombo);
+ new Label(composite_1, SWT.NONE);
+ new Label(composite_1, SWT.NONE);
+ new Label(composite_1, SWT.NONE);
+ new Label(composite_1, SWT.NONE);
+
+ typeCombo.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ super.widgetSelected(e);
+ newType = typeCombo.getText();
+ validateUi();
+ }
+ });
+
+ keyStoreCombo.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ super.widgetSelected(e);
+ updateUi(keyStoreCombo, keyStoreManager, currentTypeLabel, typeCombo);
+ validateUi();
+ }
+ });
+
+ Group entriesGroup = new Group(container, SWT.NONE);
+ entriesGroup.setLayout(new GridLayout(1, true));
+ GridData gd_entriesGroup = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
+ gd_entriesGroup.heightHint = 230;
+ gd_entriesGroup.widthHint = 433;
+ entriesGroup.setLayoutData(gd_entriesGroup);
+ entriesGroup.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Entries_Group);
+
+ entriesTableViewer =
+ new TableViewer(entriesGroup, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION);
+ entriesTableViewer.setContentProvider(new EntriesContentProvider());
+ entriesTable = entriesTableViewer.getTable();
+ entriesTable.setHeaderVisible(true);
+ entriesTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+
+ TableViewerColumn aliasViewerColumn = new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ TableColumn tblclmnAlias = aliasViewerColumn.getColumn();
+ tblclmnAlias.setWidth(100);
+ tblclmnAlias.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Alias_Column);
+ aliasViewerColumn.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).getAlias();
+ }
+ });
+
+ TableViewerColumn passwordViewerColumn_1 =
+ new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ passwordViewerColumn_1.setEditingSupport(new PasswordEditingSupport(entriesTableViewer));
+ TableColumn tblclmnPassword = passwordViewerColumn_1.getColumn();
+ tblclmnPassword.setWidth(100);
+ tblclmnPassword.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Password_Column);
+ passwordViewerColumn_1.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).getPasswd().replaceAll(".", "*"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ });
+
+ TableViewerColumn verifiedViewerColumn_2 =
+ new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ TableColumn tblclmnVerified = verifiedViewerColumn_2.getColumn();
+ tblclmnVerified.setWidth(130);
+ tblclmnVerified.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Verified_Column);
+ verifiedViewerColumn_2.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).isVerified()
+ ? CertificateManagerNLS.ConvertKeyStoreTypeDialog_Verified_Pass_Yes
+ : CertificateManagerNLS.ConvertKeyStoreTypeDialog_Verified_Pass_Wrong;
+ }
+ });
+
+ updateUi(keyStoreCombo, keyStoreManager, currentTypeLabel, typeCombo);
+
+ return area;
+ }
+
+ @Override
+ protected Control createHelpControl(Composite parent)
+ {
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent.getShell(), HELP_ID);
+ return super.createHelpControl(parent);
+ }
+
+ private void updateUi(final Combo keyStoreCombo, final KeyStoreManager keyStoreManager,
+ final Label currentTypeLabel, final Combo typeCombo)
+ {
+ keyStore = (IKeyStore) keyStoreCombo.getData(keyStoreCombo.getText());
+ try
+ {
+ password = keyStore.getPasswordProvider().getKeyStorePassword(false);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e.getMessage());
+ }
+
+ if (password == null)
+ {
+ password = ""; //$NON-NLS-1$
+ }
+ passwdText.setText(password);
+ if (!password.isEmpty())
+ {
+ IKeyStore keyStore = (IKeyStore) keyStoreCombo.getData(keyStoreCombo.getText());
+ currentTypeLabel.setText(keyStore.getType());
+ loadTypeCombo(keyStoreManager, typeCombo);
+ aliaseMap.clear();
+ try
+ {
+ if (keyStore.isPasswordValid(password))
+ {
+ List<String> aliases;
+ aliases = keyStore.getAliases(password);
+ entriesTableViewer.setInput(aliases);
+ }
+ else
+ {
+ validateUi();
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e.getMessage());
+ }
+ catch (InvalidPasswordException e)
+ {
+ validateUi();
+ }
+ }
+ }
+
+ private void loadEntries()
+ {
+ try
+ {
+ aliaseMap.clear();
+ List<String> aliases = keyStore.getAliases(password);
+ entriesTableViewer.setInput(aliases);
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Error_Loading_Keystore);
+ entriesTableViewer.setInput(new ArrayList<String>());
+ }
+ catch (InvalidPasswordException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Invalid_Keystore_Pass);
+ entriesTableViewer.setInput(new ArrayList<String>());
+ }
+ validateUi();
+ }
+
+ private void loadTypeCombo(KeyStoreManager keyStoreManager, final Combo typeCombo)
+ {
+ typeCombo.setItems(new String[0]);
+ List<String> availableTypes = keyStoreManager.getAvailableTypes();
+ for (String type : availableTypes)
+ {
+ if (!type.equals(keyStore.getType()))
+ {
+ typeCombo.add(type);
+ }
+ }
+ typeCombo.clearSelection();
+ }
+
+ @Override
+ protected Control createButtonBar(Composite parent)
+ {
+ Control bar = super.createButtonBar(parent);
+ getButton(OK).setEnabled(false);
+ return bar;
+ }
+
+ public void validateUi()
+ {
+ boolean isValid = true;
+ setErrorMessage(null);
+ if (isValid && (keyStore == null))
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Choose_KeyStore_Msg);
+ }
+ if (isValid)
+ {
+ boolean passwordValid;
+ try
+ {
+ passwordValid = keyStore.isPasswordValid(password);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ passwordValid = false;
+ }
+ catch (InvalidPasswordException e)
+ {
+ passwordValid = false;
+ }
+ if (!passwordValid)
+ {
+ isValid = false;
+ setErrorMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Invalid_Keystore_Pass);
+ }
+ }
+ if (isValid && newType.isEmpty())
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Choose_New_Type_Msg);
+ }
+ if (isValid)
+ {
+ Object input = entriesTableViewer.getInput();
+ if (input != null)
+ {
+ int itemCount = ((List<?>) input).size();
+ for (int i = 0; i < itemCount; i++)
+ {
+ EntryModel entryModel = (EntryModel) entriesTableViewer.getElementAt(i);
+ if ((entryModel != null) && !entryModel.isVerified())
+ {
+ isValid = false;
+ setMessage(
+ CertificateManagerNLS.ConvertKeyStoreTypeDialog_Incorrect_Entry_Pass,
+ IMessageProvider.WARNING);
+ break;
+ }
+ }
+ }
+ }
+
+ Button okButton = getButton(OK);
+ if (okButton != null)
+ {
+ if (!isValid)
+ {
+ okButton.setEnabled(false);
+ }
+ else
+ {
+ getButton(OK).setEnabled(true);
+ setErrorMessage(null);
+ setMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_DefaultMessage);
+ }
+ }
+ }
+
+ public IKeyStore getKeyStore()
+ {
+ return keyStore;
+ }
+
+ public String getNewType()
+ {
+ return newType;
+ }
+
+ public Map<String, String> getAliases()
+ {
+ return aliaseMap;
+ }
+
+ public String getKeystorePassword()
+ {
+ return this.password;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ImportEntriesDialog.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ImportEntriesDialog.java
new file mode 100644
index 0000000..0a1cf31
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ImportEntriesDialog.java
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.dialogs.importks;
+
+import java.io.File;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.PasswordProtection;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+public class ImportEntriesDialog extends TitleAreaDialog
+{
+ public class EntryModel
+ {
+ private final String alias;
+
+ private String passwd;
+
+ private boolean verified;
+
+ public EntryModel(String alias)
+ {
+ this.alias = alias;
+ try
+ {
+ String savedPass = sourceKeyStore.getPasswordProvider().getPassword(alias, false);
+ setPasswd(savedPass != null ? savedPass : ""); //$NON-NLS-1$
+ }
+ catch (KeyStoreManagerException e)
+ {
+ setPasswd(""); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return alias;
+ }
+
+ public String getPasswd()
+ {
+ return passwd;
+ }
+
+ public void setPasswd(String passwd)
+ {
+ this.passwd = passwd;
+ try
+ {
+ Entry entry =
+ sourceKeyStore.getKeyStore().getEntry(alias,
+ new PasswordProtection(passwd.toCharArray()));
+ setVerified(entry != null);
+ }
+ catch (Exception e)
+ {
+ setVerified(false);
+ }
+ aliasMap.put(alias, passwd);
+ }
+
+ public String getAlias()
+ {
+ return alias;
+ }
+
+ public boolean isVerified()
+ {
+ return verified;
+ }
+
+ private void setVerified(boolean verified)
+ {
+ this.verified = verified;
+ // entriesTableViewer.update(this, null);
+ validateUi();
+ }
+ }
+
+ public class EntriesContentProvider implements IStructuredContentProvider
+ {
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ validateUi();
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement)
+ {
+ List<EntryModel> modelList = null;
+ if (inputElement instanceof List<?>)
+ {
+ List<?> inputList = (List<?>) inputElement;
+ modelList = new ArrayList<EntryModel>(inputList.size());
+ Iterator<?> it = inputList.iterator();
+ while (it.hasNext())
+ {
+ Object element = it.next();
+ if (element instanceof String) //received an alias
+ {
+ String alias = (String) element;
+ EntryModel entryModel = new EntryModel(alias);
+ modelList.add(entryModel);
+ }
+ }
+
+ }
+ return modelList.toArray();
+ }
+
+ }
+
+ private final class PasswordEditingSupport extends EditingSupport
+ {
+ private PasswordEditingSupport(ColumnViewer viewer)
+ {
+ super(viewer);
+ }
+
+ @Override
+ protected boolean canEdit(Object element)
+ {
+ return true;
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element)
+ {
+ return new TextCellEditor(entriesTable, SWT.PASSWORD);
+ }
+
+ @Override
+ protected Object getValue(Object element)
+ {
+ return ((EntryModel) element).getPasswd();
+ }
+
+ @Override
+ protected void setValue(Object element, Object value)
+ {
+ EntryModel model = (EntryModel) element;
+ model.setPasswd((String) value);
+ getViewer().update(element, null);
+ }
+ }
+
+ private static final String WIZARD_BANNER = "icons/wizban/import_entries_wiz.png"; //$NON-NLS-1$
+
+ private static final String HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".import_entries_dialog"; //$NON-NLS-1$
+
+ private IKeyStore sourceKeyStore;
+
+ private IKeyStore targetKeyStore;
+
+ private Text passwdText;
+
+ protected String sourcePassword = ""; //$NON-NLS-1$
+
+ private Table entriesTable;
+
+ private CheckboxTableViewer entriesTableViewer;
+
+ private final Map<String, String> aliasMap = new HashMap<String, String>();
+
+ private Combo keyStoreCombo;
+
+ private Combo targetKsCombo;
+
+ protected List<String> selectedAlias = new ArrayList<String>();
+
+ /**
+ * Create the dialog.
+ * @param parentShell
+ */
+ public ImportEntriesDialog(Shell parentShell, IKeyStore keyStore)
+ {
+ super(parentShell);
+ setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
+
+ this.targetKeyStore = keyStore;
+ setTitleImage(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER).createImage());
+ }
+
+ /**
+ * Create contents of the dialog.
+ * @param parent
+ */
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ parent.getShell().setText(CertificateManagerNLS.ImportKeyStoreDialog_Dialog_Title);
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_Default_Message);
+ setTitle(CertificateManagerNLS.ImportKeyStoreDialog_Dialog_Title);
+ Composite area = (Composite) super.createDialogArea(parent);
+ Composite container = new Composite(area, SWT.NONE);
+ container.setLayout(new GridLayout(1, false));
+ container.setLayoutData(new GridData(GridData.FILL_BOTH));
+ Group SourceGroup = new Group(container, SWT.NONE);
+ SourceGroup.setText(CertificateManagerNLS.ImportKeyStoreDialog_Source_Group);
+ SourceGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ SourceGroup.setLayout(new GridLayout(1, false));
+
+ Composite keyStoreComposite = new Composite(SourceGroup, SWT.NONE);
+ keyStoreComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
+ keyStoreComposite.setLayout(new GridLayout(3, false));
+
+ Label keyStoreLabel = new Label(keyStoreComposite, SWT.NONE);
+ keyStoreLabel.setText(CertificateManagerNLS.ImportKeyStoreDialog_KeyStore_Label);
+
+ keyStoreCombo = new Combo(keyStoreComposite, SWT.READ_ONLY);
+ keyStoreCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ Label passwdLabel = new Label(keyStoreComposite, SWT.NONE);
+ passwdLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ passwdLabel.setText(CertificateManagerNLS.ImportKeyStoreDialog_Password_Label);
+
+ passwdText = new Text(keyStoreComposite, SWT.BORDER | SWT.PASSWORD);
+ passwdText.addModifyListener(new ModifyListener()
+ {
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ sourcePassword = passwdText.getText();
+ }
+ });
+ passwdText.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e)
+ {
+ super.widgetDefaultSelected(e);
+ loadEntries();
+ }
+ });
+ passwdText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ Button loadButton = new Button(keyStoreComposite, SWT.NONE);
+ GridData gd_loadButton = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ gd_loadButton.widthHint = 80;
+ loadButton.setLayoutData(gd_loadButton);
+ loadButton.setText(CertificateManagerNLS.ImportKeyStoreDialog_Load_Button);
+
+ Composite entriesComposite = new Composite(SourceGroup, SWT.NONE);
+ GridData gd_entriesComposite = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
+ gd_entriesComposite.heightHint = 200;
+ entriesComposite.setLayoutData(gd_entriesComposite);
+ entriesComposite.setLayout(new GridLayout(1, true));
+
+ entriesTableViewer =
+ CheckboxTableViewer.newCheckList(entriesComposite, SWT.BORDER | SWT.CHECK
+ | SWT.FULL_SELECTION);
+ entriesTableViewer.setContentProvider(new EntriesContentProvider());
+ entriesTable = entriesTableViewer.getTable();
+ entriesTable.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (e.detail == SWT.CHECK)
+ {
+ validateUi();
+ TableItem item = (TableItem) e.item;
+ if (item.getChecked())
+ {
+ selectedAlias.add(item.getText(0));
+ }
+ else
+ {
+ selectedAlias.remove(item.getText(0));
+ }
+ }
+ }
+ });
+ entriesTable.setHeaderVisible(true);
+ GridData gd_entriesTable = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
+ gd_entriesTable.heightHint = 250;
+ entriesTable.setLayoutData(gd_entriesTable);
+ TableViewerColumn aliasViewerColumn = new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ TableColumn tblclmnAlias = aliasViewerColumn.getColumn();
+ tblclmnAlias.setWidth(100);
+ tblclmnAlias.setText(CertificateManagerNLS.ImportKeyStoreDialog_Alias_Column);
+ aliasViewerColumn.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).getAlias();
+ }
+ });
+
+ TableViewerColumn passwordViewerColumn_1 =
+ new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ passwordViewerColumn_1.setEditingSupport(new PasswordEditingSupport(entriesTableViewer));
+ TableColumn tblclmnPassword = passwordViewerColumn_1.getColumn();
+ tblclmnPassword.setWidth(100);
+ tblclmnPassword.setText(CertificateManagerNLS.ImportKeyStoreDialog_Passwd_Column);
+ passwordViewerColumn_1.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).getPasswd().replaceAll(".", "*"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ });
+
+ TableViewerColumn verifiedViewerColumn_2 =
+ new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ TableColumn tblclmnVerified = verifiedViewerColumn_2.getColumn();
+ tblclmnVerified.setWidth(130);
+ tblclmnVerified.setText(CertificateManagerNLS.ImportKeyStoreDialog_Verified_Column);
+ verifiedViewerColumn_2.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).isVerified()
+ ? CertificateManagerNLS.ImportKeyStoreDialog_Verified_Pass_Yes
+ : CertificateManagerNLS.ImportKeyStoreDialog_Verified_Pass_Wrong;
+ }
+ });
+ loadButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ loadEntries();
+ }
+ });
+
+ keyStoreCombo.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ super.widgetSelected(e);
+ sourceKeyStore = (IKeyStore) keyStoreCombo.getData(keyStoreCombo.getText());
+ IKeyStore keyStore = (IKeyStore) keyStoreCombo.getData(keyStoreCombo.getText());
+ try
+ {
+ sourcePassword = keyStore.getPasswordProvider().getKeyStorePassword(false);
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e1.getMessage());
+ }
+
+ if (sourcePassword == null)
+ {
+ sourcePassword = ""; //$NON-NLS-1$
+ }
+ passwdText.setText(sourcePassword);
+ loadEntries();
+ updateTargetCombo();
+ validateUi();
+ }
+ });
+
+ Group targetGroup = new Group(container, SWT.NONE);
+ targetGroup.setLayout(new GridLayout(2, false));
+ targetGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ targetGroup.setText(CertificateManagerNLS.ImportKeyStoreDialog_Target_Group);
+
+ Label targetKsLabel = new Label(targetGroup, SWT.NONE);
+ targetKsLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ targetKsLabel.setText(CertificateManagerNLS.ImportKeyStoreDialog_KeyStore_Label);
+
+ targetKsCombo = new Combo(targetGroup, SWT.READ_ONLY);
+ targetKsCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ targetKsCombo.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ super.widgetSelected(e);
+ String selectedItem = targetKsCombo.getText();
+ targetKeyStore = (IKeyStore) targetKsCombo.getData(selectedItem);
+ validateUi();
+ }
+ });
+
+ final KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();
+ try
+ {
+ List<IKeyStore> keyStores = keyStoreManager.getKeyStores();
+ for (IKeyStore keyStore : keyStores)
+ {
+ File ksFile = keyStore.getFile();
+ String comboItem = ksFile.getName() + " - " + ksFile.getAbsolutePath(); //$NON-NLS-1$
+ keyStoreCombo.add(comboItem);
+ keyStoreCombo.setData(comboItem, keyStore);
+ if (keyStore.equals(this.sourceKeyStore))
+ {
+ keyStoreCombo.select(keyStoreCombo.indexOf(comboItem));
+ }
+ else
+ {
+ targetKsCombo.add(comboItem);
+ targetKsCombo.setData(comboItem, keyStore);
+ if (keyStore.equals(this.targetKeyStore))
+ {
+ targetKsCombo.select(targetKsCombo.indexOf(comboItem));
+ }
+ }
+ }
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ImportKeyStoreDialog_Error_Loading_Keystores);
+ }
+
+ return area;
+ }
+
+ @Override
+ protected Control createHelpControl(Composite parent)
+ {
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent.getShell(), HELP_ID);
+ return super.createHelpControl(parent);
+ }
+
+ private void updateTargetCombo()
+ {
+ final KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();
+ try
+ {
+ targetKsCombo.clearSelection();
+ targetKsCombo.setItems(new String[0]);
+ List<IKeyStore> keyStores = keyStoreManager.getKeyStores();
+ for (IKeyStore keyStore : keyStores)
+ {
+ if (keyStore != this.sourceKeyStore)
+ {
+ File ksFile = keyStore.getFile();
+ String comboItem = ksFile.getName() + " - " + ksFile.getAbsolutePath(); //$NON-NLS-1$
+ targetKsCombo.add(comboItem);
+ targetKsCombo.setData(comboItem, keyStore);
+ if (keyStore.equals(targetKeyStore))
+ {
+ targetKsCombo.select(targetKsCombo.indexOf(comboItem));
+ }
+ }
+ }
+ if (targetKsCombo.getSelectionIndex() == -1) //nothing is selected.
+ {
+ targetKeyStore = null;
+ }
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ImportKeyStoreDialog_Error_Loading_Keystores);
+ }
+
+ }
+
+ private void loadEntries()
+ {
+ try
+ {
+ aliasMap.clear();
+ if (!sourcePassword.isEmpty())
+ {
+ List<String> aliases = sourceKeyStore.getAliases(sourcePassword);
+ entriesTableViewer.setInput(aliases);
+ }
+ else
+ {
+ entriesTableViewer.setInput(new ArrayList<String>());
+ }
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ImportKeyStoreDialog_Error_Loading_Entries);
+ entriesTableViewer.setInput(new ArrayList<String>());
+ }
+ catch (InvalidPasswordException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ImportKeyStoreDialog_Invalid_Keystore_Passwd);
+ entriesTableViewer.setInput(new ArrayList<String>());
+ }
+ }
+
+ @Override
+ protected Control createButtonBar(Composite parent)
+ {
+ Control bar = super.createButtonBar(parent);
+ getButton(OK).setEnabled(false);
+ return bar;
+ }
+
+ public void validateUi()
+ {
+ boolean isValid = true;
+ setErrorMessage(null);
+ if (isValid && (sourceKeyStore == null))
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_Select_Source_Ks);
+ }
+ if (isValid && ((sourcePassword == null) || sourcePassword.isEmpty()))
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_Type_SourceKs_Passwd);
+ }
+ if (isValid)
+ {
+ try
+ {
+ if (!sourceKeyStore.isPasswordValid(sourcePassword))
+ {
+ isValid = false;
+ setErrorMessage("Wrong source keystore password.");
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ isValid = false;
+ setErrorMessage("Unable to access source keystore.\n" + e.getMessage());
+ }
+ catch (InvalidPasswordException e)
+ {
+ isValid = false;
+ setErrorMessage("Wrong source keystore password.");
+ }
+ }
+ if (isValid)
+ {
+ List<?> input = (List<?>) entriesTableViewer.getInput();
+ if (input != null)
+ {
+ int itemCount = input.size();
+ if (itemCount == 0)
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_No_Entries_To_Import,
+ IMessageProvider.WARNING);
+ }
+ if (entriesTableViewer.getCheckedElements().length == 0)
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_No_Entries_To_Import,
+ IMessageProvider.WARNING);
+ }
+ else
+ {
+ for (int i = 0; i < itemCount; i++)
+ {
+ EntryModel entryModel = (EntryModel) entriesTableViewer.getElementAt(i);
+ if (entriesTableViewer.getChecked(entryModel) && !entryModel.isVerified())
+ {
+ isValid = false;
+ setMessage(
+ CertificateManagerNLS.ImportKeyStoreDialog_Wrong_Entries_Passwd,
+ IMessageProvider.WARNING);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_No_Entries_To_Import,
+ IMessageProvider.WARNING);
+ }
+ }
+ if (isValid && (targetKeyStore == null))
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_Select_Target_Kesytore);
+ }
+
+ if (!isValid)
+ {
+ getButton(OK).setEnabled(false);
+ }
+ else
+ {
+ getButton(OK).setEnabled(true);
+ setErrorMessage(null);
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_Default_Message);
+ }
+ }
+
+ public IKeyStore getKeyStore()
+ {
+ return sourceKeyStore;
+ }
+
+ public Map<String, String> getAliases()
+ {
+ Map<String, String> selectedAliasMap = new HashMap<String, String>(selectedAlias.size());
+ for (String alias : selectedAlias)
+ {
+ selectedAliasMap.put(alias, aliasMap.get(alias));
+ }
+ return selectedAliasMap;
+ }
+
+ public IKeyStore getTargetKeyStore()
+ {
+ return targetKeyStore;
+ }
+
+ public String getPassword()
+ {
+ return sourcePassword;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/AbstractTreeNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/AbstractTreeNode.java
new file mode 100644
index 0000000..bea7353
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/AbstractTreeNode.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.model;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Abstract node for {@link KeystoreManagerView}
+ */
+public abstract class AbstractTreeNode implements ITreeNode
+{
+ private static final String UNSAVED_PASSWORD =
+ CertificateManagerNLS.AbstractTreeNode_UnsavedPassword_Tooltip;
+
+ private static final String SAVED_PASSWORD =
+ CertificateManagerNLS.AbstractTreeNode_SavedPassword_Tooltip;
+
+ private IStatus nodeStatus = Status.OK_STATUS;
+
+ private ITreeNode parent;
+
+ private String tooltip;
+
+ @Override
+ public String getTooltip()
+ {
+ if (tooltip != null)
+ {
+ return isPasswordSaved() ? SAVED_PASSWORD + "\n" + tooltip : UNSAVED_PASSWORD //$NON-NLS-1$
+ + "\n" + tooltip; //$NON-NLS-1$
+ }
+ else
+ {
+ return isPasswordSaved() ? SAVED_PASSWORD : UNSAVED_PASSWORD;
+ }
+ }
+
+ /**
+ * @return the nodeStatus
+ */
+ @Override
+ public IStatus getNodeStatus()
+ {
+ return nodeStatus;
+ }
+
+ /**
+ * @param nodeStatus the nodeStatus to set
+ */
+ @Override
+ public void setNodeStatus(IStatus nodeStatus)
+ {
+ this.nodeStatus = nodeStatus;
+ KeyStoreModelEventManager.getInstance().fireEvent(this, EventType.UPDATE);
+ }
+
+ /**
+ * @param tooltip the tooltip to set
+ */
+ @Override
+ public void setTooltip(String tooltip)
+ {
+ this.tooltip = tooltip;
+ }
+
+ /**
+ * @return the parent
+ */
+ @Override
+ public ITreeNode getParent()
+ {
+ return parent;
+ }
+
+ /**
+ * @param parent the parent to set
+ */
+ public void setParent(ITreeNode parent)
+ {
+ this.parent = parent;
+ }
+
+ @Override
+ public void addChild(ITreeNode newChild) throws KeyStoreManagerException
+ {
+ //Default implementation won't do nothing
+ }
+
+ @Override
+ public boolean testAttribute(Object target, String name, String value)
+ {
+ boolean result = false;
+ if (name.equals(PROP_NAME_NODE_STATUS))
+ {
+ if (value.equals(PROP_VALUE_NODE_STATUS_ERROR))
+ {
+ result = !getNodeStatus().isOK(); //true if there is an error
+ if (result)
+ {
+ setTooltip(getNodeStatus().getMessage());
+ }
+ }
+ else if (value.equals(PROP_VALUE_NODE_STATUS_OK))
+ {
+ result = getNodeStatus().isOK();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * For dummy nodes and root nodes it is false. Override for other nodes: {@link KeyStoreNode} and {@link EntryNode}
+ * @return
+ */
+ protected boolean isPasswordSaved()
+ {
+ return false;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/CertificateDetailsInfo.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/CertificateDetailsInfo.java
new file mode 100644
index 0000000..3d83690
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/CertificateDetailsInfo.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.util.Calendar;
+import java.util.Date;
+
+public class CertificateDetailsInfo
+{
+ private String alias;
+
+ /**
+ * Issuer name
+ */
+ private String commonName;
+
+ /**
+ * Owner name
+ */
+ private String organization;
+
+ private String organizationUnit;
+
+ private String locality;
+
+ private String country;
+
+ private String state;
+
+ private String entryPassword; //this is NOT the keystore password
+
+ private Date expirationDate;
+
+ public CertificateDetailsInfo(String alias, String commonName, String organization,
+ String organizationUnit, String locality, String country, String state,
+ String validity, String entryPassword)
+ {
+ this.alias = alias;
+ this.commonName = commonName;
+ this.organization = organization;
+ this.organizationUnit = organizationUnit;
+ this.locality = locality;
+ this.country = country;
+ this.state = state;
+ this.entryPassword = entryPassword;
+
+ int validityYears = Integer.parseInt(validity);
+
+ Calendar cal = Calendar.getInstance();
+ cal.add(Calendar.YEAR, validityYears);
+
+ this.expirationDate = cal.getTime();
+ }
+
+ /**
+ * @return the alias
+ */
+ public String getAlias()
+ {
+ return alias;
+ }
+
+ /**
+ * @return the commonName
+ */
+ public String getCommonName()
+ {
+ return commonName;
+ }
+
+ /**
+ * @return the organization
+ */
+ public String getOrganization()
+ {
+ return organization;
+ }
+
+ /**
+ * @return the organizationUnit
+ */
+ public String getOrganizationUnit()
+ {
+ return organizationUnit;
+ }
+
+ /**
+ * @return the locality
+ */
+ public String getLocality()
+ {
+ return locality;
+ }
+
+ /**
+ * @return the country
+ */
+ public String getCountry()
+ {
+ return country;
+ }
+
+ /**
+ * @return the expirationDate
+ */
+ public Date getExpirationDate()
+ {
+ return expirationDate;
+ }
+
+ /**
+ * @return the state
+ */
+ public String getState()
+ {
+ return state;
+ }
+
+ /**
+ * @return the keyPassword
+ */
+ public String getEntryPassword()
+ {
+ return entryPassword;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryDummyNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryDummyNode.java
new file mode 100644
index 0000000..a35b495
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryDummyNode.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+public class EntryDummyNode extends AbstractTreeNode implements ITreeNode
+{
+
+ public static final String DUMMY_NODE_ID = "DUMMY_NODE";
+
+ String alias = DUMMY_NODE_ID;
+
+ public EntryDummyNode(ITreeNode keyStoreModel)
+ {
+ setParent(keyStoreModel);
+ alias = DUMMY_NODE_ID;
+ }
+
+ @Override
+ public void refresh()
+ {
+ //default implementation does nothing.
+ }
+
+ @Override
+ public String getId()
+ {
+ return DUMMY_NODE_ID;
+ }
+
+ @Override
+ public String getName()
+ {
+ return "No Keys found";
+ }
+
+ @Override
+ public ImageDescriptor getIcon()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isLeaf()
+ {
+ return true;
+ }
+
+ @Override
+ public List<ITreeNode> getChildren()
+ {
+ return Collections.emptyList();
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java
new file mode 100644
index 0000000..1cf9d66
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableEntryException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Set;
+
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Represents one keystore element in {@link KeystoreManagerView}. It can be
+ * {@link Certificate} or {@link Key}.
+ */
+public class EntryNode extends AbstractTreeNode implements IKeyStoreEntry
+{
+ /**
+ * The constant contains the key pair DER object identifier.
+ */
+ public static final String KEY_PAIR_DER_OBJ_ID = "2.16.840.1.113793.23"; //$NON-NLS-1$
+
+ public static final int KEY_PASSWORD_MIN_SIZE = 6;
+
+ protected String alias;
+
+ private final String KEY_NONSAVED_PASSWORD_ICON_PATH = "icons/key.png"; //$NON-NLS-1$
+
+ private final String KEY_SAVED_PASSWORD_ICON_PATH = "icons/key_saved_password.png"; //$NON-NLS-1$
+
+ protected EntryNode()
+ {
+
+ }
+
+ /**
+ *
+ * @param keyStoreModel
+ * @param alias
+ * @throws KeyStoreManagerException
+ * if the alias is already listed in the tree
+ */
+ public EntryNode(ITreeNode keyStoreModel, String alias) throws KeyStoreManagerException
+ {
+ this.alias = alias.toLowerCase();
+ setParent(keyStoreModel);
+ if (!isKeyPairEntry())
+ {
+ keyStoreModel.addChild(this);
+ }
+
+ // notify key entry addition
+ // KeyStoreModelEventManager.getInstance().fireEvent(this, KeyStoreModelEvent.EventType.ADD);
+
+ // Obtaining certificate to get tooltip information
+ X509Certificate cert = getX509Certificate();
+ if (cert != null)
+ {
+ X500Name x500name;
+ try
+ {
+ x500name = new JcaX509CertificateHolder(cert).getSubject();
+
+ RDN commonName =
+ x500name.getRDNs(BCStyle.CN).length >= 1 ? x500name.getRDNs(BCStyle.CN)[0]
+ : null;
+ RDN organization =
+ x500name.getRDNs(BCStyle.O).length >= 1 ? x500name.getRDNs(BCStyle.O)[0]
+ : null;
+
+ // Adding tooltip information
+ String org =
+ organization != null ? organization.getFirst().getValue().toString()
+ : CertificateManagerNLS.CertificateInfoDialog_NotAvailableProperty;
+ String name =
+ commonName != null ? commonName.getFirst().getValue().toString()
+ : CertificateManagerNLS.CertificateInfoDialog_NotAvailableProperty;
+ this.setTooltip(NLS.bind(CertificateManagerNLS.CertificateBlock_KeyTooltip, org,
+ name));
+ }
+ catch (CertificateEncodingException e)
+ {
+ String errorMsg = "Error getting data from certificate";
+ StudioLogger.error(EntryNode.class, errorMsg, e);
+ throw new KeyStoreManagerException(errorMsg, e);
+ }
+ }
+ }
+
+ /*(non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getKeyStoreNode()
+ */
+ @Override
+ public IKeyStore getKeyStoreNode()
+ {
+ return (KeyStoreNode) getParent();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getAlias()
+ */
+ @Override
+ public String getAlias()
+ {
+ return alias;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #isCertificateEntry()
+ */
+ @Override
+ public boolean isCertificateEntry() throws KeyStoreException, KeyStoreManagerException
+ {
+ return getKeyStoreNode().getKeyStore().isCertificateEntry(alias);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #isKeyEntry()
+ */
+ @Override
+ public boolean isKeyEntry() throws KeyStoreException, KeyStoreManagerException
+ {
+ return getKeyStoreNode().getKeyStore().isKeyEntry(alias);
+ }
+
+ @Override
+ public boolean isKeyPairEntry()
+ {
+ X509Certificate certificate = getX509Certificate();
+ Set<String> criticalOIDs = certificate.getCriticalExtensionOIDs();
+ return (criticalOIDs != null) && criticalOIDs.contains(KEY_PAIR_DER_OBJ_ID);
+ }
+
+ /**
+ * @return {@link Certificate} if alias represents a certificate or null if
+ * the alias was not found (or if the type is not Certificate for
+ * the alias)
+ * @throws KeyStoreException
+ * if keystore not loaded yet
+ * @throws KeyStoreManagerException
+ */
+ private Certificate getCertificate() throws KeyStoreException, KeyStoreManagerException
+ {
+ Certificate certificate = null;
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ if (keyStore.isCertificateEntry(alias))
+ {
+ certificate = keyStore.getCertificate(alias);
+ }
+ else
+ {
+ // unknown type
+ StudioLogger.error(CertificateManagerNLS.bind(
+ CertificateManagerNLS.EntryNode_NotFoundOrTypeWrong, alias));
+ }
+ return certificate;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getKey(java.lang.String)
+ */
+ @Override
+ public Key getKey(String password) throws UnrecoverableKeyException, KeyStoreException,
+ NoSuchAlgorithmException, KeyStoreManagerException
+ {
+ Key key = null;
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ if (keyStore.isKeyEntry(alias))
+ {
+ key = keyStore.getKey(alias, password.toCharArray());
+ }
+
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getPrivateKey(java.lang.String)
+ */
+ @Override
+ public PrivateKey getPrivateKey(String password) throws UnrecoverableKeyException,
+ KeyStoreException, NoSuchAlgorithmException, KeyStoreManagerException,
+ InvalidKeyException
+ {
+ Key key = this.getKey(password);
+
+ if (!(key instanceof PrivateKey))
+ {
+ throw new InvalidKeyException("This is not a private key");
+ }
+
+ return (PrivateKey) key;
+ }
+
+ public Entry getKeyEntry(String password) throws KeyStoreException, NoSuchAlgorithmException,
+ KeyStoreManagerException, UnrecoverableEntryException
+ {
+ Entry key = null;
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ if (keyStore.isKeyEntry(alias))
+ {
+ key = keyStore.getEntry(alias, new KeyStore.PasswordProtection(password.toCharArray()));
+ }
+ return key;
+ }
+
+ /**
+ * Get all the certificates associated to this entry
+ *
+ * @return an Array of {@link Certificate}
+ * @throws KeyStoreException
+ * @throws KeyStoreManagerException
+ */
+ private Certificate[] getCertificateChain() throws KeyStoreException, KeyStoreManagerException
+ {
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ return keyStore.getCertificateChain(alias);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((alias == null) ? 0 : alias.hashCode());
+ result =
+ (prime * result) + ((getKeyStoreNode() == null) ? 0 : getKeyStoreNode().hashCode());
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (!(obj instanceof EntryNode))
+ {
+ return false;
+ }
+ EntryNode other = (EntryNode) obj;
+ if (alias == null)
+ {
+ if (other.alias != null)
+ {
+ return false;
+ }
+ }
+ else if (!alias.equals(other.alias))
+ {
+ return false;
+ }
+ if (getKeyStoreNode() == null)
+ {
+ if (other.getKeyStoreNode() != null)
+ {
+ return false;
+ }
+ }
+ else if (!getKeyStoreNode().equals(other.getKeyStoreNode()))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return "KeyStoreEntry [alias=" + alias + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public void refresh()
+ {
+ // keys does not need to be refreshed
+ }
+
+ @Override
+ public String getId()
+ {
+ return alias;
+ }
+
+ @Override
+ public String getName()
+ {
+ return alias;
+ }
+
+ @Override
+ public ImageDescriptor getIcon()
+ {
+ //decision: we will not support key-pair, so we will have just key items below keystore node.
+ ImageDescriptor descr = null;
+ if (isPasswordSaved())
+ {
+ //saved password
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, KEY_SAVED_PASSWORD_ICON_PATH);
+ }
+ else
+ {
+ //non saved password
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, KEY_NONSAVED_PASSWORD_ICON_PATH);
+ }
+ return descr;
+ }
+
+ @Override
+ public boolean isLeaf()
+ {
+ return true;
+ }
+
+ @Override
+ public List<ITreeNode> getChildren()
+ {
+ return new ArrayList<ITreeNode>(0); // it is the leaf of the tree
+ }
+
+ public static IKeyStoreEntry createSelfSignedNode(IKeyStore keystore, String keyStorePass,
+ String alias, CertificateDetailsInfo certificateDetailsInfo)
+ throws KeyStoreManagerException
+ {
+ KeyPair keyPair = null;
+
+ try
+ {
+ keyPair = KeyStoreUtils.genKeyPair();
+ X509Certificate x509Certificate =
+ KeyStoreUtils.createX509Certificate(keyPair, certificateDetailsInfo);
+
+ if (keyStorePass == null)
+ {
+ PasswordProvider provider = new PasswordProvider(keystore.getFile());
+ keyStorePass = provider.getKeyStorePassword(true);
+ }
+
+ PrivateKeyEntry privateKeyEntry =
+ KeyStoreUtils.createPrivateKeyEntry(keyPair, x509Certificate);
+ KeyStoreUtils.addEntry(keystore.getKeyStore(), keyStorePass.toCharArray(), keystore
+ .getFile(), alias, privateKeyEntry, certificateDetailsInfo.getEntryPassword()
+ .toCharArray());
+
+ //force reload - because keystore cache can be old due to key entries additions/removals
+ keystore.forceReload(keyStorePass.toCharArray(), false);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(e.getMessage(), e);
+ }
+
+ return new EntryNode((ITreeNode) keystore, alias);
+ }
+
+ public static IKeyStoreEntry createSelfSignedNode(IKeyStore keystore, String alias,
+ CertificateDetailsInfo certificateDetailsInfo) throws KeyStoreManagerException
+ {
+ return createSelfSignedNode(keystore, null, alias, certificateDetailsInfo);
+ }
+
+ @Override
+ public boolean testAttribute(Object target, String name, String value)
+ {
+ boolean result = super.testAttribute(target, name, value);
+ if (name.equals(PROP_NAME_NODE_STATUS))
+ {
+ if (value.equals(PROP_VALUE_NODE_STATUS_WARNING))
+ {
+ X509Certificate x509Certificate = getX509Certificate();
+ try
+ {
+ // check validity concerning the current date
+ x509Certificate.checkValidity();
+
+ // now check validity related to magic date provided by
+ // Google
+ Calendar date = GregorianCalendar.getInstance();
+ date.clear();
+ date.set(2033, Calendar.OCTOBER, 22);
+ x509Certificate.checkValidity(date.getTime());
+ }
+ catch (CertificateExpiredException e)
+ {
+ // certificate has expired in the current date; or
+ // certificate has expired before 22 Oct 2033
+ setTooltip(CertificateManagerNLS.bind(
+ CertificateManagerNLS.CertificatePeriodExpired_Issue,
+ x509Certificate.getNotAfter()));
+ result = true; // decorate node
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ // certificate is not yet valid in the current date; or
+ // certificate is not yet valid in 2033 => it must not
+ // happen but we need to deal with this case
+ setTooltip(CertificateManagerNLS.bind(
+ CertificateManagerNLS.CertificatePeriodNotYeatValid_Issue,
+ x509Certificate.getNotBefore()));
+ result = true; // decorate node
+ }
+ }
+ }
+ return result;
+
+ }
+
+ /**
+ * Get the first X509Certificate available in the entry
+ *
+ * @return
+ */
+ @Override
+ public X509Certificate getX509Certificate()
+ {
+ X509Certificate x509Certificate = null;
+ try
+ {
+ if (isCertificateEntry())
+ {
+ Certificate cert = getCertificate();
+ if (cert instanceof X509Certificate)
+ {
+ // Android certificate
+ x509Certificate = (X509Certificate) cert;
+ }
+ }
+ else if (isKeyEntry())
+ {
+ Certificate[] chain = getCertificateChain();
+ for (int i = 0; i < chain.length; i++)
+ {
+ Certificate cert = chain[i];
+ if (cert instanceof X509Certificate)
+ {
+ // Android certificate
+ x509Certificate = (X509Certificate) cert;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(EntryNode.class, CertificateManagerNLS.bind(
+ CertificateManagerNLS.EntryNode_ErrorGettingCertificateFromEntry, getAlias()),
+ e);
+ }
+ return x509Certificate;
+ }
+
+ @Override
+ protected boolean isPasswordSaved()
+ {
+ PasswordProvider pp = new PasswordProvider(getKeyStoreNode().getFile());
+ return pp.isPasswordSaved(alias);
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStore.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStore.java
new file mode 100644
index 0000000..53dcc5e
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStore.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.util.Date;
+import java.util.List;
+
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+
+public interface IKeyStore
+{
+
+ public int KEYSTORE_PASSWORD_MIN_SIZE = 6;
+
+ public int WRONG_KEYSTORE_TYPE_ERROR_CODE = 1;
+
+ PasswordProvider getPasswordProvider();
+
+ List<String> getAliases(String password) throws KeyStoreManagerException,
+ InvalidPasswordException;
+
+ /**
+ * Returns the {@link KeyStore}
+ * @throws KeyStoreManagerException
+ */
+ KeyStore getKeyStore() throws KeyStoreManagerException;
+
+ /**
+ * Load if needed and returns all entries for this KeyStore
+ * @param password
+ * @return
+ * @throws KeyStoreManagerException
+ * @throws InvalidPasswordException
+ */
+ List<IKeyStoreEntry> getEntries(String password) throws KeyStoreManagerException,
+ InvalidPasswordException;
+
+ /**
+ * Load if needed and returns the entry with the given alias.
+ * @param alias The alias of the desired entry.
+ * @param keystorePassword the password of the keystore
+ * @return The desired entry.
+ * @throws KeyStoreManagerException
+ * @throws InvalidPasswordException
+ */
+ IKeyStoreEntry getEntry(String alias, String keystorePassword) throws KeyStoreManagerException,
+ InvalidPasswordException;
+
+ /**
+ * @param password from keystore
+ * Forces keystore reload
+ * @throws KeyStoreManagerException
+ * @throws InvalidPasswordException
+ */
+ void forceReload(char[] charArray, boolean updateUi) throws KeyStoreManagerException,
+ InvalidPasswordException;
+
+ /**
+ * Returns this key store file
+ * @return
+ */
+ File getFile();
+
+ /**
+ * @return this keystore type
+ */
+ String getType();
+
+ /**
+ * Set this keystore type. This is intended to be used only during creation.
+ * This method won't change the keystore type or convert it to another type.
+ * @param type
+ * @throws KeyStoreManagerException
+ */
+ void setType(String type) throws KeyStoreManagerException;
+
+ /**
+ * Set the backup date for this keystore
+ * @param lastBackupDate
+ */
+ void setLastBackupDate(Date lastBackupDate);
+
+ /**
+ * Gets the last backup date for this keystore
+ * @return null if not backed up yet, a date otherwise
+ */
+ Date getLastBackupDate();
+
+ /**
+ * Deletes a key entry with the given alias
+ * @param alias The alias representing the key to be removed.
+ * @throws KeyStoreManagerException
+ */
+ void removeKey(String alias) throws KeyStoreManagerException;
+
+ /**
+ * Deletes a list of key entries from the keystore.
+ * @param aliases The list of aliases representing the keys to be removed.
+ * @throws KeyStoreManagerException
+ */
+ void removeKeys(List<String> aliases) throws KeyStoreManagerException;
+
+ /**
+ * @param password
+ */
+ public boolean isPasswordValid(String password) throws KeyStoreManagerException,
+ InvalidPasswordException;
+
+ /**
+ * Return the password of the keystore.
+ * If the password is not saved and {@code promptPassword} is set to {@code true}, then a dialog will be opened so the user can enter the password.
+ * @return Return the password of the keystore.
+ */
+ String getKeyStorePassword(boolean promptPassword);
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStoreEntry.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStoreEntry.java
new file mode 100644
index 0000000..7db617b
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStoreEntry.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.X509Certificate;
+
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+
+public interface IKeyStoreEntry
+{
+ /**
+ * @return {@link Key} if the alias represents the private key associated to this entry
+ * or null if the alias was not found (or if the type is not Key for the alias)
+ * @throws NoSuchAlgorithmException if no algorithm to recover key not found
+ * @throws KeyStoreException if keystore not loaded yet
+ * @throws UnrecoverableKeyException if wrong password for the key
+ * @throws KeyStoreManagerException
+ */
+ Key getKey(String password) throws UnrecoverableKeyException, KeyStoreException,
+ NoSuchAlgorithmException, KeyStoreManagerException;
+
+ /**
+ * @return The key represented by this node as a PrivateKey.
+ * @throws NoSuchAlgorithmException if no algorithm to recover key not found
+ * @throws KeyStoreException if keystore not loaded yet
+ * @throws UnrecoverableKeyException if wrong password for the key
+ * @throws KeyStoreManagerException
+ * @throws InvalidKeyException If this key is not a {@link PrivateKey}.
+ * */
+ PrivateKey getPrivateKey(String password) throws UnrecoverableKeyException, KeyStoreException,
+ NoSuchAlgorithmException, KeyStoreManagerException, InvalidKeyException;
+
+ /**
+ * @return true if this entry contains a private key
+ * @throws KeyStoreException if the keystore has not been initialized (loaded).
+ * @throws KeyStoreManagerException
+ */
+ boolean isKeyEntry() throws KeyStoreException, KeyStoreManagerException;
+
+ /**
+ * @return true if this entry contains a certificate
+ * @throws KeyStoreException if the keystore has not been initialized (loaded).
+ * @throws KeyStoreManagerException
+ */
+ boolean isCertificateEntry() throws KeyStoreException, KeyStoreManagerException;
+
+ /**
+ * @return true if this entry is a key pair
+ */
+ boolean isKeyPairEntry();
+
+ /**
+ * @return the alias
+ */
+ String getAlias();
+
+ /**
+ * Get the first X509Certificate available in the entry
+ * @return
+ */
+ X509Certificate getX509Certificate();
+
+ /**
+ * @return The keystore node that holds this entry.
+ * */
+ public IKeyStore getKeyStoreNode();
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/ITreeNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/ITreeNode.java
new file mode 100644
index 0000000..5edf9de
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/ITreeNode.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.security.KeyStoreException;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IActionFilter;
+
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+
+public interface ITreeNode extends IActionFilter
+{
+
+ public static final String PROP_VALUE_NODE_STATUS_OK =
+ "com.motorolamobility.studio.android.certmanager.core.property.nodeStatusOk"; //$NON-NLS-1$
+
+ public static final String PROP_VALUE_NODE_STATUS_KEYSTORE_TYPE_OK =
+ "com.motorolamobility.studio.android.certmanager.core.property.keystoreTypeOk"; //$NON-NLS-1$
+
+ /**
+ * Property value used to check if the node has an error status.
+ */
+ public static final String PROP_VALUE_NODE_STATUS_ERROR =
+ "com.motorolamobility.studio.android.certmanager.core.property.nodeStatusError"; //$NON-NLS-1$
+
+ public static final String PROP_VALUE_NODE_STATUS_WARNING =
+ "com.motorolamobility.studio.android.certmanager.core.property.nodeStatusWarning"; //$NON-NLS-1$
+
+ /**
+ * Property name used to test the status of the node.
+ */
+ public static final String PROP_NAME_NODE_STATUS =
+ "com.motorolamobility.studio.android.certmanager.core.property.nodeStatus"; //$NON-NLS-1$
+
+ public static final String PROP_NAMESPACE =
+ "com.motorolamobility.studio.android.certmanager.core.property";
+
+ /**
+ * Method responsible to reload the node itself and its children
+ */
+ void refresh() throws KeyStoreManagerException;
+
+ /**
+ * @return the id
+ */
+ String getId();
+
+ /**
+ * @return the name
+ */
+ String getName();
+
+ /**
+ * @return the icon
+ */
+ ImageDescriptor getIcon();
+
+ /**
+ * @return true if it does not accept a child, false otherwise
+ */
+ boolean isLeaf();
+
+ /**
+ * Set the node Status, allowing the tree to decorate itself on errors.
+ * Is status is ERROR the icon will be decorated with a error image and tooltip will be replaced by status.getMessage() if available.
+ * @param status
+ */
+ void setNodeStatus(IStatus status);
+
+ /**
+ * Retrieves the current node status.
+ * @return
+ */
+ IStatus getNodeStatus();
+
+ /**
+ * Set the tooltip to be displayed for this node.
+ * @param tooltip
+ */
+ void setTooltip(String tooltip);
+
+ /**
+ * @return this node tooltip text
+ */
+ String getTooltip();
+
+ /**
+ * Get parent of the tree node
+ * @return null if it is the tree root, non-null if is a child node
+ */
+ ITreeNode getParent();
+
+ /**
+ * Retrieves list of children (without any filter)
+ * @return collection of {@link ITreeNode} that are child of this abstract tree node
+ * @throws KeyStoreException
+ * @throws KeyStoreManagerException
+ */
+ List<ITreeNode> getChildren() throws KeyStoreManagerException;
+
+ void addChild(ITreeNode newChild) throws KeyStoreManagerException;
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreNode.java
new file mode 100644
index 0000000..884fe84
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreNode.java
@@ -0,0 +1,786 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.preferences.DialogWithToggleUtils;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Represents a keystore visual item for the {@link KeystoreManagerView}.
+ *
+ * @author gdpr78
+ *
+ */
+public class KeyStoreNode extends AbstractTreeNode implements IKeyStore
+{
+ public static final String WARN_ABOUT_UNSUPPORTED_ENTRIES_PREFERENCE =
+ CertificateManagerActivator.PLUGIN_ID + ".warnAboutUnsupportedEntries"; //$NON-NLS-1$
+
+ private static final String DUMMY_NODE = "DUMMY_NODE"; //$NON-NLS-1$
+
+ private final File keyStoreFile;
+
+ private KeyStore keyStore;
+
+ private Date lastBackupDate;
+
+ private String type;
+
+ /**
+ * Alias to {@link EntryNode}
+ */
+ private final Map<String, ITreeNode> entries = new LinkedHashMap<String, ITreeNode>();
+
+ private final String KEYSTORE_NONSAVED_PASSWORD_ICON_PATH = "icons/keystore.png"; //$NON-NLS-1$
+
+ private final String KEYSTORE_SAVED_PASSWORD_ICON_PATH = "icons/keystore_saved_password.png"; //$NON-NLS-1$
+
+ private static final String WRONG_KEYSTORE_TYPE_ICON_PATH = "icons/keystore_incorrect_type.png";
+
+ private final PasswordProvider passwordProvider;
+
+ private boolean ignoreRefresh;
+
+ private boolean quiet;
+
+ private boolean skipNextReload = false;
+
+ private boolean typeVerified;
+
+ public KeyStoreNode(File path)
+ {
+ this.keyStoreFile = path;
+ passwordProvider = new PasswordProvider(keyStoreFile);
+ updateStatus();
+ }
+
+ public KeyStoreNode(File path, String type)
+ {
+ this.keyStoreFile = path;
+ this.type = type;
+ passwordProvider = new PasswordProvider(keyStoreFile);
+ updateStatus();
+ }
+
+ public KeyStoreNode(File keyStoreFile, KeyStore keyStore)
+ {
+ this(keyStoreFile);
+ this.keyStore = keyStore;
+ this.type = keyStore.getType();
+ }
+
+ @Override
+ public PasswordProvider getPasswordProvider()
+ {
+ return passwordProvider;
+ }
+
+ @Override
+ public String getKeyStorePassword(boolean promptPassword)
+ {
+ String password = null;
+ boolean keepTrying = true;
+
+ //keep asking password until user either enter the correct password or cancel the operation
+ while (keepTrying)
+ {
+ try
+ {
+ try
+ {
+ keepTrying = false;
+ password = getPasswordProvider().getKeyStorePassword(promptPassword);
+ if (password != null)
+ {
+ isPasswordValid(password);
+ }
+ }
+ catch (InvalidPasswordException e)
+ {
+ getPasswordProvider().deleteKeyStoreSavedPasswordNode();
+ password = null;
+ keepTrying = true;
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ password = null;
+ keepTrying = false;
+
+ StudioLogger.info(
+ this.getClass(),
+ CertificateManagerNLS.KeyStoreNode_CouldNotGetKeyStorePassword
+ + e.getLocalizedMessage());
+ }
+ }
+
+ return password;
+ }
+
+ /**
+ * @return the path
+ */
+ @Override
+ public File getFile()
+ {
+ return keyStoreFile;
+ }
+
+ @Override
+ public KeyStore getKeyStore() throws KeyStoreManagerException
+ {
+ return getKeyStore(true);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore#
+ * getKeyStore()
+ */
+ public KeyStore getKeyStore(boolean load) throws KeyStoreManagerException
+ {
+ if (keyStore == null)
+ {
+ boolean tryAgain = false;
+ boolean useSavedPass = true;
+ String password = null;
+ do
+ {
+ if (tryAgain)
+ {
+ useSavedPass = false;
+ }
+ password = passwordProvider.getKeyStorePassword(true, useSavedPass);
+ tryAgain = false;
+ if (password != null)
+ {
+ try
+ {
+ keyStore = loadKeystore(password.toCharArray());
+ setTooltip(null);
+ if (load)
+ {
+ loadEntries();
+ }
+ }
+ catch (InvalidPasswordException e)
+ {
+ tryAgain = true;
+ }
+ }
+ else
+ {
+ setTooltip(CertificateManagerNLS.KeyStoreNode_CouldNotLoadKeystore_Tooltip);
+ }
+ }
+ while (tryAgain);
+ }
+
+ return keyStore;
+ }
+
+ public KeyStore getKeyStore(String password) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ if ((keyStore == null) && (password != null))
+ {
+ keyStore = loadKeystore(password.toCharArray());
+ loadEntries();
+ }
+ else
+ {
+ //just check if given password is valid for this keystore
+ isPasswordValid(password);
+ }
+
+ return keyStore;
+ }
+
+ @Override
+ public boolean isPasswordValid(String password) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ KeyStore myKeyStore = null;
+ if (password != null)
+ {
+ myKeyStore = loadKeystore(password.toCharArray());
+ }
+ else
+ {
+ throw new InvalidPasswordException(CertificateManagerNLS.KeyStoreNode_Password_NotNull);
+ }
+
+ return myKeyStore != null;
+ }
+
+ protected KeyStore loadKeystore(char[] password) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ KeyStore keyStore = null;
+ setNodeStatus(Status.OK_STATUS);
+ setTooltip(null);
+ try
+ {
+ if (!typeVerified && type.equalsIgnoreCase("jceks")) //$NON-NLS-1$
+ {
+ //Try to load this as JKS.
+ keyStore = KeyStoreUtils.loadKeystore(keyStoreFile, password, "JKS"); //$NON-NLS-1$
+ if (keyStore != null)
+ {
+ //Keystore type is actually wrong, it's a jks keystore.
+ EclipseUtils.showWarningDialog(
+ CertificateManagerNLS.KeyStoreNode_Wrong_KeystoreType_Title, NLS.bind(
+ CertificateManagerNLS.KeyStoreNode_Wrong_KeystoreType_Message,
+ getName()));
+ setType("JKS"); //$NON-NLS-1$
+ typeVerified = true;
+ }
+ }
+ }
+ catch (KeyStoreManagerException keyStoreManagerException)
+ {
+ //Do nothing, let's try with the correct type.
+ }
+ catch (InvalidPasswordException invalidPasswordException)
+ {
+ setNodeStatus(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID,
+ CertificateManagerNLS.KeyStoreNode_InvalidPassword));
+ throw invalidPasswordException;
+ }
+
+ try
+ {
+ keyStore = KeyStoreUtils.loadKeystore(keyStoreFile, password, type);
+ setNodeStatus(Status.OK_STATUS);
+ }
+ catch (KeyStoreManagerException keyStoreManagerException)
+ {
+ setNodeStatus(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID,
+ IKeyStore.WRONG_KEYSTORE_TYPE_ERROR_CODE,
+ CertificateManagerNLS.KeyStoreNode_KeystoreTypeWrong_NodeStatus, null));
+ throw keyStoreManagerException;
+ }
+ catch (InvalidPasswordException invalidPasswordException)
+ {
+ setNodeStatus(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID,
+ CertificateManagerNLS.KeyStoreNode_InvalidPassword));
+ throw invalidPasswordException;
+ }
+ return keyStore;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((keyStoreFile == null) ? 0 : keyStoreFile.hashCode());
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (!(obj instanceof KeyStoreNode))
+ {
+ return false;
+ }
+ KeyStoreNode other = (KeyStoreNode) obj;
+ if (keyStoreFile == null)
+ {
+ if (other.keyStoreFile != null)
+ {
+ return false;
+ }
+ }
+ else if (!keyStoreFile.equals(other.keyStoreFile))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return getName() + " - ( " + getId() + " )"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public void refresh() throws KeyStoreManagerException
+ {
+ if (!ignoreRefresh)
+ {
+ if (!skipNextReload)
+ {
+ keyStore = null;
+ skipNextReload = false;
+ }
+ entries.clear();
+ updateStatus();
+ if (getNodeStatus().isOK())
+ {
+ quiet = true;
+ loadEntries();
+ quiet = false;
+ passwordProvider.cleanModel(new ArrayList<String>(entries.keySet()));
+ }
+ }
+ else
+ {
+ setIgnoreRefresh(false);
+ }
+ }
+
+ private void setIgnoreRefresh(boolean ignoreRefresh)
+ {
+ this.ignoreRefresh = ignoreRefresh;
+ }
+
+ @Override
+ public String getId()
+ {
+ return keyStoreFile.getAbsolutePath();
+ }
+
+ @Override
+ public String getName()
+ {
+ return keyStoreFile.getName();
+ }
+
+ @Override
+ public ImageDescriptor getIcon()
+ {
+ ImageDescriptor descr = null;
+ if (!isStoreTypeCorrect())
+ {
+ //wrong keystore type
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WRONG_KEYSTORE_TYPE_ICON_PATH);
+ }
+ else if (isPasswordSaved())
+ {
+ //saved password
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID,
+ KEYSTORE_SAVED_PASSWORD_ICON_PATH);
+ }
+ else
+ {
+ //non saved password
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID,
+ KEYSTORE_NONSAVED_PASSWORD_ICON_PATH);
+ }
+ return descr;
+ }
+
+ @Override
+ public boolean isLeaf()
+ {
+ return false;
+ }
+
+ @Override
+ public List<ITreeNode> getChildren() throws KeyStoreManagerException
+ {
+ ArrayList<ITreeNode> children = new ArrayList<ITreeNode>(entries.values());
+ return children;
+ }
+
+ private void loadEntries() throws KeyStoreManagerException
+ {
+ if (entries.size() == 1)
+ {
+ ITreeNode entryNode = entries.get(DUMMY_NODE); //$NON-NLS-1$
+ if (entryNode != null)
+ {
+ entries.remove(DUMMY_NODE); //$NON-NLS-1$
+ KeyStoreModelEventManager.getInstance().fireEvent(entryNode, EventType.REMOVE);
+ }
+ }
+ entries.clear();
+ KeyStore keyStore = getKeyStore(false);
+ if (keyStore != null)
+ {
+ Enumeration<String> aliases;
+ try
+ {
+ aliases = keyStore.aliases();
+ }
+ catch (KeyStoreException e)
+ {
+ throw new KeyStoreManagerException(CertificateManagerNLS.bind(
+ CertificateManagerNLS.KeyStoreModel_Error_GettingAliasesFromKeystore,
+ getName()), e);
+ }
+
+ List<String> keyPairEntries = new ArrayList<String>();
+ while (aliases.hasMoreElements())
+ {
+ String alias = aliases.nextElement();
+ EntryNode keyStoreEntry = new EntryNode(this, alias);
+ if (!keyStoreEntry.isKeyPairEntry())
+ {
+ //we will not support key pairs
+ entries.put(alias, keyStoreEntry);
+ }
+ else
+ {
+ //is key pair
+ keyPairEntries.add(alias);
+ String msg =
+ CertificateManagerNLS.bind(
+ CertificateManagerNLS.KeyStoreNode_KeyPairNotMapped_LogMessage,
+ alias);
+ StudioLogger.debug(msg);
+ }
+ }
+ if ((keyPairEntries != null) && !keyPairEntries.isEmpty())
+ {
+ //found key pairs
+ DialogWithToggleUtils.showInformation(WARN_ABOUT_UNSUPPORTED_ENTRIES_PREFERENCE,
+ CertificateManagerNLS.KeyStoreNode_KeyPairNotMapped_Title,
+ CertificateManagerNLS.KeyStoreNode_KeyPairNotMapped_Message);
+ }
+
+ if (entries.isEmpty())
+ {
+ entries.put(DUMMY_NODE, new EntryDummyNode(this)); //$NON-NLS-1$
+ }
+ }
+ else
+ {
+ setNodeStatus(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID,
+ CertificateManagerNLS.KeyStoreNode_UseRefresh_StatusNode));
+ }
+ }
+
+ private void updateStatus()
+ {
+ setNodeStatus(Status.OK_STATUS);
+ if (!keyStoreFile.exists())
+ {
+ setNodeStatus(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID,
+ CertificateManagerNLS.KeyStoreNode_KeystoreFileNotFound));
+ }
+ }
+
+ @Override
+ public void addChild(ITreeNode newChild)
+ {
+ if (entries.size() == 1)
+ {
+ ITreeNode entryNode = entries.get(DUMMY_NODE); //$NON-NLS-1$
+ if (entryNode != null)
+ {
+ entries.remove(DUMMY_NODE); //$NON-NLS-1$
+ KeyStoreModelEventManager.getInstance().fireEvent(entryNode, EventType.REMOVE);
+ }
+ }
+ if ((newChild instanceof IKeyStoreEntry) || (newChild instanceof EntryDummyNode))
+ {
+ EntryNode entryNode = (EntryNode) newChild;
+ String alias = entryNode.getAlias();
+ entries.put(alias, entryNode);
+ if (!quiet && !(newChild instanceof EntryDummyNode))
+ {
+ KeyStoreModelEventManager.getInstance().fireEvent(newChild, EventType.ADD);
+ }
+ }
+ }
+
+ /**
+ * @return the lastBackupDate
+ */
+ @Override
+ public Date getLastBackupDate()
+ {
+ return lastBackupDate;
+ }
+
+ /**
+ * @param lastBackupDate
+ * the lastBackupDate to set
+ */
+ @Override
+ public void setLastBackupDate(Date lastBackupDate)
+ {
+ this.lastBackupDate = lastBackupDate;
+ try
+ {
+ KeyStoreManager.getInstance().setBackupDate(this, lastBackupDate);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Could not set backup date for keystore");
+ }
+ KeyStoreModelEventManager.getInstance().fireEvent(this, EventType.UPDATE);
+ }
+
+ /**
+ * @return the type
+ */
+ @Override
+ public String getType()
+ {
+ return type != null ? type : KeyStore.getDefaultType().toUpperCase();
+ }
+
+ /**
+ * @param type
+ * the type to set
+ * @throws KeyStoreManagerException
+ */
+ @Override
+ public void setType(String type) throws KeyStoreManagerException
+ {
+ this.type = type;
+ KeyStoreManager.getInstance().updateKeyStoreType(this);
+ }
+
+ @Override
+ public List<IKeyStoreEntry> getEntries(String password) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ getKeyStore(password);
+ ArrayList<IKeyStoreEntry> children = new ArrayList<IKeyStoreEntry>(entries.size());
+ for (ITreeNode treeNode : entries.values())
+ {
+ if (treeNode instanceof IKeyStoreEntry)
+ {
+ children.add((IKeyStoreEntry) treeNode);
+ }
+ }
+ return children;
+ }
+
+ @Override
+ public IKeyStoreEntry getEntry(String alias, String keystorePassword)
+ throws KeyStoreManagerException, InvalidPasswordException
+ {
+ IKeyStoreEntry result = null;
+ for (IKeyStoreEntry entry : getEntries(keystorePassword))
+ {
+ if (entry.getAlias().equalsIgnoreCase(alias))
+ {
+ result = entry;
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public List<String> getAliases(String password) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ getKeyStore(password);
+
+ ArrayList<String> children = new ArrayList<String>(entries.size());
+ for (ITreeNode treeNode : entries.values())
+ {
+ if (treeNode instanceof IKeyStoreEntry)
+ {
+ children.add(((IKeyStoreEntry) treeNode).getAlias());
+ }
+ }
+ return children;
+ }
+
+ @Override
+ public void removeKey(String alias) throws KeyStoreManagerException
+ {
+ String password = passwordProvider.getKeyStorePassword(true, true);
+ if (password != null)
+ {
+ KeyStoreUtils.deleteEntry(keyStore, password.toCharArray(), keyStoreFile, alias);
+ try
+ {
+ forceReload(password.toCharArray(), false);
+ }
+ catch (InvalidPasswordException e)
+ {
+ //Should never happen.
+ StudioLogger.debug("Could reload ks after removing entry, invalid password"); //$NON-NLS-1$
+ }
+
+ ITreeNode entryNode = entries.remove(alias);
+ KeyStoreModelEventManager.getInstance().fireEvent(entryNode, EventType.REMOVE);
+ if (entries.isEmpty())
+ {
+ EntryDummyNode entryDummyNode = new EntryDummyNode(this);
+ entries.put(DUMMY_NODE, entryDummyNode); //$NON-NLS-1$
+ KeyStoreModelEventManager.getInstance().fireEvent(entryDummyNode, EventType.ADD);
+ }
+ }
+ else
+ {
+ // password not found
+ throw new KeyStoreManagerException(
+ CertificateManagerNLS.KeyStoreNode_NotFoundOrIncorrectPasswordToDeleteEntry
+ + alias);
+ }
+
+ }
+
+ @Override
+ public void removeKeys(List<String> aliases) throws KeyStoreManagerException
+ {
+ String password = passwordProvider.getKeyStorePassword(true, true);
+ if (password != null)
+ {
+ for (String alias : aliases)
+ {
+ KeyStoreUtils.deleteEntry(keyStore, password.toCharArray(), keyStoreFile, alias);
+
+ ITreeNode entryNode = entries.remove(alias);
+ KeyStoreModelEventManager.getInstance().fireEvent(entryNode, EventType.REMOVE);
+ }
+ try
+ {
+ forceReload(password.toCharArray(), false);
+ }
+ catch (InvalidPasswordException e)
+ {
+ //Should never happen.
+ StudioLogger.debug("Could reload ks after removing entry, invalid password"); //$NON-NLS-1$
+ }
+ if (entries.isEmpty())
+ {
+ EntryDummyNode entryDummyNode = new EntryDummyNode(this);
+ entries.put(DUMMY_NODE, entryDummyNode); //$NON-NLS-1$
+ KeyStoreModelEventManager.getInstance().fireEvent(entryDummyNode, EventType.ADD);
+ }
+ }
+ else
+ {
+ // password not found
+ throw new KeyStoreManagerException(
+ CertificateManagerNLS.KeyStoreNode_IncorrectPasswordToDeleteEntries_Error);
+ }
+
+ }
+
+ @Override
+ public boolean testAttribute(Object target, String name, String value)
+ {
+ boolean result = super.testAttribute(target, name, value);
+ if (name.equals(PROP_NAME_NODE_STATUS))
+ {
+ if (value.equals(PROP_VALUE_NODE_STATUS_ERROR))
+ {
+ if (!isStoreTypeCorrect())
+ {
+ //when store type is incorrect the icon is changed, not decorated.
+ result = false;
+ }
+ else if (!keyStoreFile.exists())
+ {
+ // keystore not found
+ result = true;
+ setTooltip(CertificateManagerNLS.KeyStoreNode_ErrorKeystoreNotFound);
+ }
+ }
+ else if (value.equals(PROP_VALUE_NODE_STATUS_KEYSTORE_TYPE_OK))
+ {
+ result = isStoreTypeCorrect();
+ }
+
+ }
+ return result;
+ }
+
+ @Override
+ public void forceReload(char[] password, boolean updateUi) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ keyStore = loadKeystore(password);
+
+ if (updateUi)
+ {
+ skipNextReload = true;
+ KeyStoreModelEventManager.getInstance().fireEvent(this, EventType.REFRESH);
+ }
+ }
+
+ @Override
+ protected boolean isPasswordSaved()
+ {
+ PasswordProvider pp = new PasswordProvider(getFile());
+ return pp.isPasswordSaved();
+ }
+
+ protected boolean isStoreTypeCorrect()
+ {
+ return getNodeStatus().getCode() != WRONG_KEYSTORE_TYPE_ERROR_CODE;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreRootNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreRootNode.java
new file mode 100644
index 0000000..5c07df7
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreRootNode.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Node that is the parent of keyStores (root node of {@link KeystoreManagerView})
+ */
+public class KeyStoreRootNode extends AbstractTreeNode
+{
+ //Map from absolute file path to KeyStoreModel
+ private final List<ITreeNode> keyStores = new ArrayList<ITreeNode>();
+
+ /**
+ * Adds keystore to root node of the tree
+ * @param keyStoreModel
+ * @throws KeyStoreManagerException if the keystore is already listed in the tree
+ */
+ public void addKeyStoreNode(KeyStoreNode keyStoreModel) throws KeyStoreManagerException
+ {
+ if (!keyStores.contains(keyStoreModel))
+ {
+ keyStores.add(keyStoreModel);
+ keyStoreModel.setParent(this);
+
+ KeyStoreModelEventManager.getInstance().fireEvent(keyStoreModel,
+ KeyStoreModelEvent.EventType.ADD);
+ }
+ else
+ {
+ //error - notify
+ throw new KeyStoreManagerException(CertificateManagerNLS.bind(
+ CertificateManagerNLS.KeyStoreRootNode_Error_AlreadyMappedKeystorePath,
+ keyStoreModel.getFile().getAbsolutePath()));
+ }
+ }
+
+ public void removeKeyStore(KeyStoreNode keyStoreModel)
+ {
+ keyStores.remove(keyStoreModel);
+ KeyStoreModelEventManager.getInstance().fireEvent(keyStoreModel,
+ KeyStoreModelEvent.EventType.REMOVE);
+ File keysToreFile = keyStoreModel.getFile();
+
+ PasswordProvider password = new PasswordProvider(keysToreFile);
+
+ try
+ {
+ password.deleteKeyStoreSavedPasswordNode();
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e.getMessage());
+ }
+
+ }
+
+ @Override
+ public void refresh()
+ {
+ //Not necessary, root nod can't be refreshed
+ }
+
+ @Override
+ public String getId()
+ {
+ return ""; //not necessary - root node //$NON-NLS-1$
+ }
+
+ @Override
+ public String getName()
+ {
+ return ""; //not necessary - root node //$NON-NLS-1$
+ }
+
+ @Override
+ public ImageDescriptor getIcon()
+ {
+ return null; //not necessary - root node
+ }
+
+ @Override
+ public boolean isLeaf()
+ {
+ return false; //root node
+ }
+
+ @Override
+ public ITreeNode getParent()
+ {
+ return null; //invisible node
+ }
+
+ @Override
+ public List<ITreeNode> getChildren()
+ {
+ return new ArrayList<ITreeNode>(keyStores);
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/SigningAndKeysModelManager.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/SigningAndKeysModelManager.java
new file mode 100644
index 0000000..d4493f6
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/SigningAndKeysModelManager.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.BackwardKeystoreManager;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Provides services to map and unmap keystores.
+ * Also get access to the root node and populates on first access (based on {@link KeyStoreManager}).
+ *
+ */
+public class SigningAndKeysModelManager
+{
+ private KeyStoreRootNode keyStoresRootNode = new KeyStoreRootNode();
+
+ private static SigningAndKeysModelManager _instance = null;
+
+ private SigningAndKeysModelManager()
+ {
+ }
+
+ public static synchronized SigningAndKeysModelManager getInstance()
+ {
+ if (_instance == null)
+ {
+ _instance = new SigningAndKeysModelManager();
+ _instance.populateKeyStoreRootNode();
+ }
+ return _instance;
+ }
+
+ public File[] getKeystoreFiles()
+ {
+ List<ITreeNode> nodes = keyStoresRootNode.getChildren();
+
+ File[] files = new File[nodes.size()];
+ int i = 0;
+ for (ITreeNode node : nodes)
+ {
+
+ File file = ((KeyStoreNode) node).getFile();
+ files[i++] = file;
+ }
+
+ return files;
+ }
+
+ public KeyStoreRootNode populateKeyStoreRootNode()
+ {
+ try
+ {
+ List<IKeyStore> keyStores = KeyStoreManager.getInstance().getKeyStores();
+ if (keyStores != null)
+ {
+ if (keyStores.size() > 0)
+ {
+ //there are items mapped on persistence
+ for (IKeyStore keyStore : keyStores)
+ {
+ if (keyStore instanceof KeyStoreNode)
+ {
+ keyStoresRootNode.addKeyStoreNode((KeyStoreNode) keyStore);
+ }
+ }
+ }
+ else
+ {
+ //we do not have any item mapped in persistence
+ //try to import from old Motodev keystore
+ //(probably it is the first time user is trying to use the view)
+ BackwardKeystoreManager backwardKeystoreManager = new BackwardKeystoreManager();
+ backwardKeystoreManager.mapOldKeystore();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(KeystoreManagerView.class, e.getMessage(), e);
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.KeystoreManagerView_ErrorLoadingMappedKeystoresFromPersistence,
+ e.getMessage());
+ }
+
+ return keyStoresRootNode;
+ }
+
+ public void unmapKeyStore(KeyStoreNode keyStoreNode)
+ {
+ keyStoresRootNode.removeKeyStore(keyStoreNode);
+ try
+ {
+ File file = keyStoreNode.getFile();
+ PasswordProvider passwordProvider = new PasswordProvider(file);
+ passwordProvider.deleteKeyStoreSavedPasswordNode();
+ KeyStoreManager.getInstance().removeKeyStore(keyStoreNode);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog("Error unmapping KeyStore", NLS.bind(
+ "Could not unmap the keystore file {0}", keyStoreNode.getFile()), new Status(
+ IStatus.ERROR, "Error unmapping KeyStore",
+ CertificateManagerActivator.PLUGIN_ID, e));
+ }
+ }
+
+ public void mapKeyStore(KeyStoreNode keyStoreNode) throws KeyStoreManagerException
+ {
+ keyStoresRootNode.addKeyStoreNode(keyStoreNode);
+ KeyStoreManager.getInstance().addKeyStore(keyStoreNode);
+ }
+
+ /**
+ * @return the keyStoresRootNode (populated through {@link SigningAndKeysModelManager#getInstance(), in the first access}
+ */
+ public KeyStoreRootNode getKeyStoresRootNode()
+ {
+ return keyStoresRootNode;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/ExpiresInColumnLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/ExpiresInColumnLabelProvider.java
new file mode 100644
index 0000000..ed911c8
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/ExpiresInColumnLabelProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.tree;
+
+import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.util.Locale;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+
+public class ExpiresInColumnLabelProvider extends ColumnLabelProvider
+{
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ if (element instanceof IKeyStoreEntry)
+ {
+ EntryNode keyStoreEntry = (EntryNode) element;
+ X509Certificate x509Certificate = keyStoreEntry.getX509Certificate();
+ //Android certificate
+ return getExpiresInDate(x509Certificate);
+ }
+ return "";
+ }
+
+ /**
+ * Returns the date where the certificate expires
+ * @param cert
+ * @return
+ */
+ private String getExpiresInDate(X509Certificate x509Certificate)
+ {
+ return (x509Certificate != null) ? DateFormat.getDateInstance(DateFormat.MEDIUM,
+ Locale.getDefault()).format(x509Certificate.getNotAfter()) : "";
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/KeystoreManagerTreeContentProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/KeystoreManagerTreeContentProvider.java
new file mode 100644
index 0000000..34a08a6
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/KeystoreManagerTreeContentProvider.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.tree;
+
+import java.util.List;
+
+import org.eclipse.jface.viewers.ILazyTreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+public class KeystoreManagerTreeContentProvider implements ILazyTreeContentProvider
+{
+
+ private final TreeViewer treeViewer;
+
+ public KeystoreManagerTreeContentProvider(TreeViewer viewer)
+ {
+ this.treeViewer = viewer;
+ }
+
+ @Override
+ public void dispose()
+ {
+ //Nothing
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ //Nothing
+ }
+
+ @Override
+ public void updateElement(Object parent, int index)
+ {
+ if (parent instanceof ITreeNode)
+ {
+ ITreeNode parentNode = (ITreeNode) parent;
+ ITreeNode child = null;
+ try
+ {
+ List<ITreeNode> children = parentNode.getChildren();
+ if (!children.isEmpty())
+ {
+ child = children.get(index);
+ }
+ }
+ catch (Exception e)
+ {
+ child = null;
+ }
+
+ if (child != null)
+ {
+ treeViewer.replace(parent, index, child);
+ try
+ {
+ if (child.getChildren().isEmpty())
+ {
+ treeViewer.setHasChildren(child, !child.isLeaf());
+ }
+ else
+ {
+ treeViewer.setChildCount(child, child.getChildren().size());
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e.getMessage());
+ }
+ }
+ }
+
+ }
+
+ @Override
+ public void updateChildCount(Object element, int currentChildCount)
+ {
+ if (element instanceof ITreeNode)
+ {
+ ITreeNode treeNode = (ITreeNode) element;
+ int childCount = 0;
+ try
+ {
+ treeNode.refresh();
+ List<ITreeNode> children = treeNode.getChildren();
+ if (!children.isEmpty())
+ {
+ childCount = children.size();
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error(e.getMessage());
+ }
+
+ if (childCount != currentChildCount)
+ {
+ treeViewer.setChildCount(element, childCount);
+ }
+ }
+ }
+
+ @Override
+ public ITreeNode getParent(Object element)
+ {
+ if (element instanceof ITreeNode)
+ {
+ ITreeNode treeNode = (ITreeNode) element;
+ return treeNode.getParent();
+ }
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/LastBackupDateColumnLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/LastBackupDateColumnLabelProvider.java
new file mode 100644
index 0000000..8fc4877
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/LastBackupDateColumnLabelProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.tree;
+
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+public class LastBackupDateColumnLabelProvider extends ColumnLabelProvider
+{
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ if (element instanceof IKeyStore)
+ {
+ IKeyStore iKeyStore = (IKeyStore) element;
+
+ if (iKeyStore.getLastBackupDate() != null)
+ {
+ SimpleDateFormat formatter =
+ new SimpleDateFormat("MMM dd yyyy HH:mm:ss", Locale.getDefault());
+ return formatter.format(iKeyStore.getLastBackupDate());
+ }
+ }
+ return "";
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/NameAliasColumnLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/NameAliasColumnLabelProvider.java
new file mode 100644
index 0000000..5377ab4
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/NameAliasColumnLabelProvider.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.tree;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.IDecoratorManager;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+public class NameAliasColumnLabelProvider extends ColumnLabelProvider
+{
+ final IDecoratorManager decorator;
+
+ public NameAliasColumnLabelProvider()
+ {
+ decorator = PlatformUI.getWorkbench().getDecoratorManager();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getImage(java.lang.Object)
+ */
+ @Override
+ public Image getImage(Object element)
+ {
+ Image result = null;
+ if (element instanceof ITreeNode)
+ {
+ ITreeNode node = (ITreeNode) element;
+ Image defaultImage = null;
+ if (node.getIcon() != null)
+ {
+ defaultImage = node.getIcon().createImage();
+ result = decorator.decorateImage(defaultImage, element);
+ }
+ if (result == null)
+ {
+ result = defaultImage;
+ }
+ }
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ if (element instanceof ITreeNode)
+ {
+ ITreeNode node = (ITreeNode) element;
+ return node.getName();
+ }
+ return ""; //other items do not need to show this column with data
+ }
+
+ @Override
+ public void update(ViewerCell cell)
+ {
+ Object cellElement = cell.getElement();
+ cell.setText(getText(cellElement));
+ if (getImage(cellElement) != null)
+ {
+ cell.setImage(getImage(cellElement));
+ }
+ }
+
+ @Override
+ public String getToolTipText(Object element)
+ {
+ if (element instanceof ITreeNode)
+ {
+ ITreeNode treeNode = (ITreeNode) element;
+
+ return treeNode.getTooltip();
+ }
+ return super.getToolTipText(element);
+ }
+
+ @Override
+ public int getToolTipTimeDisplayed(Object object)
+ {
+ return 4000;
+ }
+
+ @Override
+ public int getToolTipDisplayDelayTime(Object object)
+ {
+ return 500;
+ }
+
+ @Override
+ public Point getToolTipShift(Object object)
+ {
+ return new Point(5, 5);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.BaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
+ */
+ @Override
+ public void addListener(ILabelProviderListener listener)
+ {
+ decorator.addListener(listener);
+ super.addListener(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.BaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
+ */
+ @Override
+ public void removeListener(ILabelProviderListener listener)
+ {
+ decorator.removeListener(listener);
+ super.removeListener(listener);
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/PathColumnLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/PathColumnLabelProvider.java
new file mode 100644
index 0000000..32fa02b
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/PathColumnLabelProvider.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.tree;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+
+public class PathColumnLabelProvider extends ColumnLabelProvider
+{
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ if (element instanceof KeyStoreNode)
+ {
+ KeyStoreNode keyStoreModel = (KeyStoreNode) element;
+ return keyStoreModel.getFile().getAbsolutePath();
+ }
+ return ""; //other items do not need to show this column with data
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/TypeColumnLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/TypeColumnLabelProvider.java
new file mode 100644
index 0000000..a8a9fd4
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/TypeColumnLabelProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.tree;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+public class TypeColumnLabelProvider extends ColumnLabelProvider
+{
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ if (element instanceof IKeyStore)
+ {
+ IKeyStore iKeyStore = (IKeyStore) element;
+ return iKeyStore.getType();
+ }
+ return ""; //other items do not need to show this column with data
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizard.java
new file mode 100644
index 0000000..f949f0f
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizard.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.wizards.BaseWizard;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+/**
+ * Wizard to create an Android key.
+ */
+public class CreateKeyWizard extends BaseWizard
+{
+
+ private static final String WIZARD_BANNER = "icons/wizban/create_key_wiz.png"; //$NON-NLS-1$
+
+ private boolean success = false;
+
+ /**
+ * Wizard page to allow the user to inform the key pair alias and
+ * distinguished name.
+ */
+ private final CreateKeyWizardPage createkeyWizardPage;
+
+ public CreateKeyWizard(IKeyStore keystore)
+ {
+ setupWizardUi();
+ createkeyWizardPage = new CreateKeyWizardPage(keystore);
+ }
+
+ public CreateKeyWizard(IKeyStore keystore, String keystorePassword,
+ IJobChangeListener createKeyJobListener)
+ {
+ setupWizardUi();
+ createkeyWizardPage =
+ new CreateKeyWizardPage(keystore, keystorePassword, createKeyJobListener);
+ }
+
+ private void setupWizardUi()
+ {
+ setWindowTitle(CertificateManagerNLS.CreateSelfSignedCertificateWizardPage_Title);
+ setDefaultPageImageDescriptor(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#createPageControls(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPageControls(Composite pageContainer)
+ {
+ super.createPageControls(pageContainer);
+
+ //the shell has the same help as its single page
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(getShell(), CreateKeyWizardPage.CREATE_SELF_SIGNED_CERTIFICATE_HELP_ID);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @seecom.motorola.studio.android.wizards.BaseWizard#
+ * doPerformFinish()
+ */
+ @Override
+ protected boolean doPerformFinish()
+ {
+ success = createkeyWizardPage.createKey();
+ return success;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#addPages()
+ */
+ @Override
+ public void addPages()
+ {
+ super.addPages();
+ addPage(createkeyWizardPage);
+ }
+
+ /**
+ * Returns the alias of the just created key or null otherwise.
+ */
+ public String getAlias()
+ {
+ return success ? createkeyWizardPage.getTrueAlias() : null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizardPage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizardPage.java
new file mode 100644
index 0000000..286cbeb
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizardPage.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.jface.wizard.IWizard;
+
+import com.motorola.studio.android.wizards.BaseWizardPage;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.job.CreateKeyJob;
+import com.motorolamobility.studio.android.certmanager.ui.composite.NewKeyBlock;
+import com.motorolamobility.studio.android.certmanager.ui.model.CertificateDetailsInfo;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+/**
+ * Wizard page to create an Android key.
+ */
+public class CreateKeyWizardPage extends BaseWizardPage
+{
+ private IKeyStore keystore = null;
+
+ private String alias = null;
+
+ private String keyStorePass;
+
+ public static final String CREATE_SELF_SIGNED_CERTIFICATE_HELP_ID =
+ CertificateManagerActivator.PLUGIN_ID + ".create-self-cert";
+
+ private IJobChangeListener createKeyJobListener = null;
+
+ /**
+ * The default constructor.
+ */
+ public CreateKeyWizardPage(IKeyStore keystore)
+ {
+ super(new NewKeyBlock(), CertificateManagerNLS.CreateSelfSignedCertificateWizardPage_Title,
+ CertificateManagerNLS.CreateSelfSignedCertificateWizardPage_Description,
+ CREATE_SELF_SIGNED_CERTIFICATE_HELP_ID); //$NON-NLS-2$
+ ((NewKeyBlock) block).setBaseWizardPage(this);
+ this.keystore = keystore;
+ }
+
+ public CreateKeyWizardPage(IKeyStore keystore, String keystorePassword,
+ IJobChangeListener createKeyJobListener)
+ {
+ this(keystore);
+ setKeyStorePass(keystorePassword);
+ this.createKeyJobListener = createKeyJobListener;
+ }
+
+ /**
+ * Obtains the key pair alias defined by user.
+ *
+ * @return The key pair alias.
+ */
+ public String getAlias()
+ {
+ return ((NewKeyBlock) block).getAlias();
+ }
+
+ /**
+ * Obtains the common name defined by user.
+ *
+ * @return The common name.
+ */
+ public String getCommonName()
+ {
+ return ((NewKeyBlock) block).getCommonName();
+ }
+
+ /**
+ * Obtains the organization defined by user.
+ *
+ * @return The organization.
+ */
+ public String getOrganization()
+ {
+ return ((NewKeyBlock) block).getOrganization();
+ }
+
+ /**
+ * Obtains the organization unit defined by user.
+ *
+ * @return The organization unit.
+ */
+ public String getOrganizationUnit()
+ {
+ return ((NewKeyBlock) block).getOrganizationUnit();
+ }
+
+ /**
+ * Obtains the locality defined by user.
+ *
+ * @return The locality.
+ */
+ public String getLocality()
+ {
+ return ((NewKeyBlock) block).getLocality();
+ }
+
+ /**
+ * Obtains the state defined by user.
+ *
+ * @return The state.
+ */
+ public String getState()
+ {
+ return ((NewKeyBlock) block).getState();
+ }
+
+ /**
+ * Obtains the country defined by user.
+ *
+ * @return The country.
+ */
+ public String getCountry()
+ {
+ return ((NewKeyBlock) block).getCountry();
+ }
+
+ /**
+ * Obtains the validity defined by user.
+ *
+ * @return The validity.
+ */
+ public String getValidity()
+ {
+ return ((NewKeyBlock) block).getValidity();
+ }
+
+ public String getEntryPassword()
+ {
+ return ((NewKeyBlock) block).getKeyPassword();
+ }
+
+ public String getEntryConfirmPassword()
+ {
+ return ((NewKeyBlock) block).getKeyConfirmPassword();
+ }
+
+ public boolean needToSaveKeyEntryPassword()
+ {
+ return ((NewKeyBlock) block).needToSaveKeyPassword();
+ }
+
+ public boolean createKey()
+ {
+ boolean successfullyCreated = true;
+ alias = getAlias();
+
+ if (isPageCompleteWithAllFieldsBlank())
+ {
+ successfullyCreated = true;
+ }
+ else
+ {
+ final CertificateDetailsInfo certificateDetailsInfo =
+ new CertificateDetailsInfo(alias, getCommonName(), getOrganization(),
+ getOrganizationUnit(), getLocality(), getCountry(), getState(),
+ getValidity(), getEntryPassword());
+ CreateKeyJob createKeyJob =
+ new CreateKeyJob("Create key job", (NewKeyBlock) block, certificateDetailsInfo,
+ keystore, keyStorePass);
+
+ if (createKeyJobListener != null)
+ {
+ createKeyJob.addJobChangeListener(createKeyJobListener);
+ }
+ createKeyJob.schedule();
+
+ successfullyCreated = true;
+ }
+
+ return successfullyCreated;
+ }
+
+ /**
+ * @param keystoreNode
+ */
+ public void setKeyStore(IKeyStore keystoreNode)
+ {
+ this.keystore = keystoreNode;
+ }
+
+ /*
+ * If all fields are blank and this page is under CreateKeystoreWizard context,
+ * then if all fields are blank the page is considered complete and no keypair will be created.
+ */
+ public boolean isPageCompleteWithAllFieldsBlank()
+ {
+ boolean result = false;
+ IWizard wizardContext = getWizard();
+
+ //in the context of CreateKeyStoreWizard and if this is NOT the current page, then allow all fields blank
+ //be a valid complete page
+ if ((wizardContext instanceof CreateKeystoreWizard) && !isCurrentPage()
+ && areAllFieldsBlank())
+ {
+ result = true;
+ }
+
+ return result;
+ }
+
+ /*
+ * return true if all fields are blank
+ */
+ private boolean areAllFieldsBlank()
+ {
+ boolean result = false;
+ if (getAlias().isEmpty() && getCommonName().isEmpty() && getOrganization().isEmpty()
+ && getOrganizationUnit().isEmpty() && getLocality().isEmpty()
+ && getState().isEmpty() && getCountry().isEmpty() && getEntryPassword().isEmpty()
+ && getEntryConfirmPassword().isEmpty())
+ {
+ result = true;
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.jface.wizard.WizardPage#isPageComplete()
+ */
+ @Override
+ public boolean isPageComplete()
+ {
+ if (this.block == null)
+ {
+ return true;
+ }
+ return this.block.isPageComplete() || isPageCompleteWithAllFieldsBlank();
+ }
+
+ /**
+ * This method just works.
+ * @return
+ */
+ public String getTrueAlias()
+ {
+ return alias;
+ }
+
+ public void setKeyStorePass(String password)
+ {
+ this.keyStorePass = password;
+ }
+
+ /**
+ * @return the keystore
+ */
+ public IKeyStore getKeystore()
+ {
+ return keystore;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.DialogPage#setVisible(boolean)
+ */
+ @Override
+ public void setVisible(boolean visible)
+ {
+ super.setVisible(visible);
+ if (visible)
+ {
+ ((NewKeyBlock) block).setFocus();
+ }
+
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystorePage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystorePage.java
new file mode 100644
index 0000000..9630e66
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystorePage.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.List;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+
+public class CreateKeystorePage extends WizardPage
+{
+
+ private static final String CREATE_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".new_keystore"; //$NON-NLS-1$
+
+ private Text keystoreFilenameText;
+
+ private ComboViewer keystoreTypeComboViewer;
+
+ private Text keystorePasswordText;
+
+ private Text keystoreConfirmPasswordText;
+
+ private String keystorePassword;
+
+ private boolean initialValidation = true;
+
+ private boolean userChangedPasswordConfirmation = false;
+
+ private boolean userChangedPassword = false;
+
+ SelectionListener selectionListener = new SelectionListener()
+ {
+
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ validatePage();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e)
+ {
+ //nothing to do...
+ }
+ };
+
+ private Button savePassword;
+
+ private Button useTypeAsExtensionCheckBox;
+
+ protected boolean useTypeAsExtensionCheckBoxPreviousState = true;
+
+ /**
+ * @param pageName
+ */
+ protected CreateKeystorePage(String pageName)
+ {
+ super(pageName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createControl(Composite parent)
+ {
+ Composite mainComposite = new Composite(parent, SWT.FILL);
+ mainComposite.setLayout(new GridLayout(3, false));
+ mainComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ setTitle(CertificateManagerNLS.CreateKeystorePage_CreateKeystore);
+ setMessage(CertificateManagerNLS.CreateKeystorePage_WizardDefaultMessage);
+
+ createFilenameSection(mainComposite);
+ createKeystoreTypeSection(mainComposite);
+ createFilenameExtensionSection(mainComposite);
+
+ setKeystoreFilenameExtension();
+
+ //LINE TO SEPARATE PASSWORD SECTION FROM KEYSTORE DETAILS SECTION
+ Label separator1 = new Label(mainComposite, SWT.SEPARATOR | SWT.HORIZONTAL);
+ separator1.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
+
+ createKeystorePasswordSection(mainComposite);
+ createConfirmPasswordSection(mainComposite);
+ createSavePasswordSection(mainComposite);
+
+ validatePage();
+
+ setControl(mainComposite);
+
+ //set help id for this page
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, CREATE_KEYSTORE_HELP_ID);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(mainComposite, CREATE_KEYSTORE_HELP_ID);
+ }
+
+ /**
+ * @param mainComposite
+ */
+ private void createKeystoreTypeSection(Composite parent)
+ {
+ Label keystoreTypeLabel = new Label(parent, SWT.NONE);
+ keystoreTypeLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keystoreTypeLabel.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreType);
+
+ keystoreTypeComboViewer = new ComboViewer(parent, SWT.READ_ONLY);
+ keystoreTypeComboViewer.getCombo().setLayoutData(
+ new GridData(SWT.FILL, SWT.NONE, true, false, 1, 1));
+ keystoreTypeComboViewer.setContentProvider(new IStructuredContentProvider()
+ {
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ //do nothing
+ }
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object[] getElements(Object inputElement)
+ {
+ return ((List<String>) inputElement).toArray();
+ }
+ });
+ keystoreTypeComboViewer.setLabelProvider(new ILabelProvider()
+ {
+
+ @Override
+ public void removeListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property)
+ {
+ return false;
+ }
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public void addListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public String getText(Object element)
+ {
+ return (String) element;
+ }
+
+ @Override
+ public Image getImage(Object element)
+ {
+ return null;
+ }
+ });
+
+ keystoreTypeComboViewer.setInput(KeyStoreManager.getInstance().getAvailableTypes());
+
+ keystoreTypeComboViewer.getCombo().addSelectionListener(new SelectionAdapter()
+ {
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ useTypeAsExtensionCheckBox.setEnabled(true);
+ useTypeAsExtensionCheckBox.setSelection(useTypeAsExtensionCheckBoxPreviousState);
+
+ if (useTypeAsExtensionCheckBox.getSelection())
+ {
+ setKeystoreFilenameExtension();
+ }
+ }
+ });
+
+ for (int i = 0; i < keystoreTypeComboViewer.getCombo().getItemCount(); i++)
+ {
+ if (keystoreTypeComboViewer.getCombo().getItem(i)
+ .compareToIgnoreCase(KeyStoreManager.getInstance().getDefaultType()) == 0)
+ {
+ keystoreTypeComboViewer.getCombo().select(i);
+ }
+ }
+
+ keystoreTypeComboViewer.getCombo().addModifyListener(new ModifyListener()
+ {
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ if (useTypeAsExtensionCheckBox != null)
+ {
+ useTypeAsExtensionCheckBox.setEnabled(false);
+ useTypeAsExtensionCheckBox.setSelection(false);
+ }
+ }
+ });
+
+ //fill the third column with a blank label
+ Label separator2 = new Label(parent, SWT.NONE);
+ separator2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ }
+
+ /**
+ * Set the extension of the keystore based on selected keystore type and the user's choice to use it or not as the extension.
+ * If the user typed a custom keystore type, then the filename extension is set to ".keystore".
+ * */
+ protected void setKeystoreFilenameExtension()
+ {
+ String keystoreFilename = keystoreFilenameText.getText();
+ String keystoreType = keystoreTypeComboViewer.getCombo().getText();
+
+ List<String> availableTypes = KeyStoreManager.getInstance().getAvailableTypes();
+ availableTypes
+ .add(CertificateManagerNLS.CreateKeystorePage_DefaultKeystoreFilenameExtension);
+
+ for (String availableType : availableTypes)
+ {
+ String availableTypeExtension = "." + availableType.toLowerCase(); //$NON-NLS-1$
+ if (keystoreFilename.endsWith(availableTypeExtension))
+ {
+ keystoreFilename =
+ keystoreFilename.substring(0, keystoreFilename.length()
+ - availableTypeExtension.length());
+ break;
+ }
+ }
+
+ keystoreFilenameText.setText(keystoreFilename + "." + keystoreType.toLowerCase()); //$NON-NLS-1$
+ }
+
+ private void createFilenameExtensionSection(Composite mainComposite)
+ {
+ useTypeAsExtensionCheckBox = new Button(mainComposite, SWT.CHECK);
+ useTypeAsExtensionCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false,
+ 3, 1));
+ useTypeAsExtensionCheckBox
+ .setText(CertificateManagerNLS.CreateKeystorePage_UseKeystoreTypeAsExtension);
+ useTypeAsExtensionCheckBox.setSelection(true);
+
+ useTypeAsExtensionCheckBox.addSelectionListener(new SelectionAdapter()
+ {
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ useTypeAsExtensionCheckBoxPreviousState = useTypeAsExtensionCheckBox.getSelection();
+ if (useTypeAsExtensionCheckBox.getSelection())
+ {
+ setKeystoreFilenameExtension();
+ }
+ }
+ });
+ }
+
+ /**
+ * @param mainComposite
+ */
+ private void createSavePasswordSection(Composite mainComposite)
+ {
+ savePassword = new Button(mainComposite, SWT.CHECK);
+ savePassword.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ savePassword.setText(CertificateManagerNLS.CreateKeystorePage_SaveThisPassword);
+ savePassword.setSelection(false);
+ }
+
+ /**
+ * @param mainComposite
+ */
+ private void createConfirmPasswordSection(Composite mainComposite)
+ {
+ Label keystoreConfirmPasswordLabel = new Label(mainComposite, SWT.NONE);
+ keystoreConfirmPasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false,
+ 1, 1));
+ keystoreConfirmPasswordLabel
+ .setText(CertificateManagerNLS.CreateKeystorePage_KeystoreConfirmPasswordLabel);
+
+ keystoreConfirmPasswordText =
+ new Text(mainComposite, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
+ keystoreConfirmPasswordText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
+ 1, 1));
+ keystoreConfirmPasswordText.addSelectionListener(selectionListener);
+ keystoreConfirmPasswordText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ userChangedPasswordConfirmation = true;
+ validatePage();
+ }
+ });
+
+ //fill the third column with a blank label
+ Label separator2 = new Label(mainComposite, SWT.NONE);
+ separator2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ }
+
+ /**
+ * @param mainComposite
+ */
+ private void createKeystorePasswordSection(Composite mainComposite)
+ {
+ Label keystorePasswordLabel = new Label(mainComposite, SWT.NONE);
+ keystorePasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keystorePasswordLabel
+ .setText(CertificateManagerNLS.CreateKeystorePage_KeystorePasswordLabel);
+
+ keystorePasswordText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
+ keystorePasswordText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ keystorePasswordText.addSelectionListener(selectionListener);
+ keystorePasswordText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ keystorePassword = keystorePasswordText.getText();
+ userChangedPassword = true;
+ validatePage();
+ }
+ });
+
+ //fill the third column with a blank label
+ @SuppressWarnings("unused")
+ Label separator = new Label(mainComposite, SWT.NONE);
+ keystorePasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ }
+
+ /**
+ * @param mainComposite
+ */
+ private void createFilenameSection(Composite mainComposite)
+ {
+ Label keystoreFilenameLabel = new Label(mainComposite, SWT.NONE);
+ keystoreFilenameLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keystoreFilenameLabel
+ .setText(CertificateManagerNLS.CreateKeystorePage_KeystoreFilenameLabel);
+
+ keystoreFilenameText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER);
+ keystoreFilenameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ keystoreFilenameText.setText(generateKeyStoreFilename());
+ keystoreFilenameText.addSelectionListener(selectionListener);
+ keystoreFilenameText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ validatePage();
+ }
+ });
+
+ Button chooseLocation = new Button(mainComposite, SWT.PUSH);
+ chooseLocation.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
+ chooseLocation.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreFilenameBrowse);
+ chooseLocation.addSelectionListener(new SelectionAdapter()
+ {
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ Shell shell = Display.getCurrent().getActiveShell();
+
+ FileDialog dialog = new FileDialog(shell, SWT.SAVE);
+
+ String keystoreFilenameStr = dialog.open();
+
+ if (keystoreFilenameStr != null)
+ {
+ keystoreFilenameText.setText(keystoreFilenameStr);
+ }
+ }
+ });
+ }
+
+ private void validatePage()
+ {
+ boolean pageComplete = true;
+
+ String errorMessage = null;
+
+ String message = CertificateManagerNLS.CreateKeystorePage_WizardDefaultMessage;
+
+ int messageType = IMessageProvider.NONE;
+
+ if (initialValidation == true)
+ {
+ //when the wizard opens, does not show any errors
+ pageComplete = false;
+ initialValidation = false;
+ }
+ else
+ {
+ //password text and confirmation password text must match
+ if (!keystorePasswordText.getText().equals(keystoreConfirmPasswordText.getText()))
+ {
+ //if the user hasn't started typing the confirmation password,
+ //then just show an info, instead of an error
+ if (userChangedPasswordConfirmation)
+ {
+ errorMessage = CertificateManagerNLS.CreateKeystorePage_PasswordDoesNotMatch;
+ pageComplete = false;
+ }
+ else
+ {
+ message = CertificateManagerNLS.CreateKeystorePage_ConfirmPasswordInfoMsg;
+ messageType = IMessageProvider.INFORMATION;
+ pageComplete = false;
+ }
+ }
+ //check password size according to keytool specification
+ if (keystorePasswordText.getText().length() < KeyStoreNode.KEYSTORE_PASSWORD_MIN_SIZE)
+ {
+ if (userChangedPassword)
+ {
+ errorMessage =
+ CertificateManagerNLS
+ .bind(CertificateManagerNLS.CreateKeystorePage_PasswordMinSizeMessage,
+ KeyStoreNode.KEYSTORE_PASSWORD_MIN_SIZE); //$NON-NLS-1$
+ pageComplete = false;
+ }
+ else
+ {
+ message = CertificateManagerNLS.CreateKeystorePage_SetPasswordInfoMsg;
+ messageType = IMessageProvider.INFORMATION;
+ pageComplete = false;
+ }
+ }
+
+ //check if store type is filled
+ if (keystoreTypeComboViewer.getCombo().getText().isEmpty())
+ {
+ errorMessage = CertificateManagerNLS.CreateKeystorePage_SetKeystoreType;
+ pageComplete = false;
+ }
+
+ //check if filename is valid
+ try
+ {
+ File keystoreFile = new File(keystoreFilenameText.getText().trim());
+ Path keystorePath = new Path(keystoreFilenameText.getText().trim());
+ if (!keystorePath.isValidPath(keystoreFile.getCanonicalPath()))
+ {
+ //throw the same exception as getCanonicalPath() in order to do not duplicate code
+ throw new IOException();
+ }
+ }
+ catch (IOException e)
+ {
+ errorMessage = CertificateManagerNLS.CreateKeystorePage_FilenameSyntaxError;
+ pageComplete = false;
+ }
+ if (keystoreFilenameText.getText().trim().isEmpty())
+ {
+ errorMessage = CertificateManagerNLS.ImportKeystorePage_FilenameCannotBeEmpty;
+ pageComplete = false;
+ }
+ }
+
+ setMessage(message, messageType);
+ setErrorMessage(errorMessage);
+ setPageComplete(pageComplete);
+ }
+
+ /**
+ * Generate a valid filename for a new keystore.
+ * The file must not exist, so a serial number is added to it as necessary.
+ * @return An standard keystore filename.
+ * */
+ private String generateKeyStoreFilename()
+ {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss_SSS"); //$NON-NLS-1$
+ String timestamp = dateFormat.format(Calendar.getInstance().getTime());
+
+ //initial keystore filename with timestamp
+ String keystoreFilenameStr =
+ System.getProperty("user.home") + System.getProperty("file.separator") //$NON-NLS-1$ //$NON-NLS-2$
+ + CertificateManagerNLS.bind(
+ CertificateManagerNLS.CreateKeystorePage_DefaultKeystoreFilename,
+ timestamp);
+
+ File keystoreFile = new File(keystoreFilenameStr);
+
+ //while file already exists, generate a new one using a new timestamp
+ while (keystoreFile.exists())
+ {
+ timestamp = dateFormat.format(Calendar.getInstance().getTime());
+ keystoreFilenameStr =
+ System.getProperty("user.home") + System.getProperty("file.separator") //$NON-NLS-1$ //$NON-NLS-2$
+ + CertificateManagerNLS
+ .bind(CertificateManagerNLS.CreateKeystorePage_DefaultKeystoreFilename,
+ timestamp);
+ keystoreFile = new File(keystoreFilenameStr);
+ }
+
+ return keystoreFilenameStr;
+ }
+
+ /**
+ * As this page works independently of other pages, it has its own version of performFinish().
+ * Wizards that use this page must call this method to effectively create the new keystore.
+ * @return {@code true} if the keystore were successfully created, {@code false} otherwise.
+ * */
+ public KeyStoreNode createKeyStore()
+ {
+ boolean successfullyCreated = true;
+ File keystoreFile = null;
+ KeyStoreNode keystoreNode = null;
+
+ try
+ {
+ keystoreFile = new File(keystoreFilenameText.getText().trim());
+ if (validateKeyStoreFile(keystoreFile))
+ {
+ keystoreNode =
+ (KeyStoreNode) KeyStoreManager.createKeyStore(keystoreFile,
+ keystoreTypeComboViewer.getCombo().getText(), keystorePasswordText
+ .getText().toCharArray());
+
+ SigningAndKeysModelManager.getInstance().mapKeyStore(keystoreNode);
+ }
+ else
+ {
+ //file already exist and will not be overwritten
+ successfullyCreated = false;
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ //in case of error, the keystore wasn't properly created and the file should not be left on file system
+ if (keystoreFile != null)
+ {
+ keystoreFile.delete();
+ }
+
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.CreateKeystorePage_ErrorCreatingKeystore, NLS.bind(
+ CertificateManagerNLS.CreateKeystorePage_ErrorOnKeyStoreFileCreation,
+ keystoreFilenameText.getText()));
+ successfullyCreated = false;
+ }
+
+ if (successfullyCreated && savePassword.getSelection())
+ {
+ savePassword(keystoreFile);
+ }
+
+ return successfullyCreated ? keystoreNode : null;
+ }
+
+ /**
+ * @param keystoreFile
+ */
+ private void savePassword(File keystoreFile)
+ {
+ try
+ {
+ PasswordProvider passwordProvider = new PasswordProvider(keystoreFile);
+ passwordProvider.saveKeyStorePassword(keystorePasswordText.getText());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showWarningDialog(
+ CertificateManagerNLS.CreateKeystorePage_CouldNotSavePassword,
+ e.getLocalizedMessage());
+ }
+ }
+
+ /* If file exists and the user chooses to overwrite it, the key store file is valid and return value is true.
+ * If file exists and the user do not want to overwrite the file, then the keystore file is considered invalid and the return value is false.
+ * If file does not exist, then the file is valid and the return value is true.
+ * */
+ private boolean validateKeyStoreFile(File keystoreFile)
+ {
+ boolean result = true;
+
+ if (keystoreFile.exists())
+ {
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+
+ result =
+ MessageDialog.openQuestion(shell,
+ CertificateManagerNLS.CreateKeystorePage_ConfirmFileOverwrite,
+ NLS.bind(CertificateManagerNLS.CreateKeystorePage_ConfirmReplaceFile,
+ keystoreFile.getAbsolutePath()));
+ if (result)
+ {
+ //file will be recreated
+ keystoreFile.delete();
+ }
+ }
+ return result;
+ }
+
+ public String getPassword()
+ {
+ return keystorePassword;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystoreWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystoreWizard.java
new file mode 100644
index 0000000..12c0e48
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystoreWizard.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+
+/**
+ *
+ */
+public class CreateKeystoreWizard extends Wizard
+{
+
+ private final CreateKeystorePage createKeystorePage;
+
+ private final CreateKeyWizardPage createKeyPairPage;
+
+ private static final String WIZARD_BANNER = "icons/wizban/create_keystore_wiz.png"; //$NON-NLS-1$
+
+ private static final String KEYSTORE_KEY_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".keystore-key-help-id";
+
+ private KeyStoreNode createdKeystoreNode;
+
+ /**
+ *
+ */
+ public CreateKeystoreWizard()
+ {
+ this(null);
+ }
+
+ public CreateKeystoreWizard(IJobChangeListener createKeystoreJobListener)
+ {
+ setWindowTitle(CertificateManagerNLS.CreateKeystoreWizard_CreateNewKeyStore);
+ setDefaultPageImageDescriptor(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER));
+
+ this.createKeyPairPage = new CreateKeyWizardPage(null, "", createKeystoreJobListener);
+ this.createKeystorePage =
+ new CreateKeystorePage(CertificateManagerNLS.CreateKeystoreWizard_CreateNewKeyStore);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#createPageControls(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPageControls(Composite pageContainer)
+ {
+ super.createPageControls(pageContainer);
+
+ //the shell has a generic help that talks about keystore and keys
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(getShell(), KEYSTORE_KEY_HELP_ID);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#performFinish()
+ */
+ @Override
+ public boolean performFinish()
+ {
+ createdKeystoreNode = createKeystorePage.createKeyStore();
+ if (createdKeystoreNode != null)
+ {
+ createKeyPairPage.setKeyStore(createdKeystoreNode);
+ createKeyPairPage.setKeyStorePass(createKeystorePage.getPassword());
+ createKeyPairPage.createKey();
+ }
+
+ //check if the keystore was created
+ return (createdKeystoreNode != null);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#addPages()
+ */
+ @Override
+ public void addPages()
+ {
+ this.addPage(createKeystorePage);
+ this.addPage(createKeyPairPage);
+ }
+
+ /**
+ * @return the createdKeystoreNode
+ */
+ public KeyStoreNode getCreatedKeystoreNode()
+ {
+ return createdKeystoreNode;
+ }
+
+ public String getCreatedKeystorePassword()
+ {
+ String result = null;
+ if (createKeystorePage != null)
+ {
+ result = createKeystorePage.getPassword();
+ }
+
+ return result;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystorePage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystorePage.java
new file mode 100644
index 0000000..b9b0582
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystorePage.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.FileUtil;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+
+public class ImportKeystorePage extends WizardPage
+{
+
+ private Text keystoreFilename;
+
+ private ComboViewer keystoreType;
+
+ public static final String IMPORT_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".import_keystore"; //$NON-NLS-1$
+
+ private SelectionListener selectionListener = new SelectionAdapter()
+ {
+
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ validatePage();
+ }
+ };
+
+ private boolean userChangedFilename = false;
+
+ private Composite mainComposite;
+
+ private File keystoreFile;
+
+ private String keystoreTypeString;
+
+ protected boolean keystoreAlreadyMapped = false;
+
+ private IKeyStore keyStoreNode;
+
+ /**
+ * @param pageName
+ */
+ protected ImportKeystorePage(String pageName)
+ {
+ super(pageName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createControl(Composite parent)
+ {
+ mainComposite = new Composite(parent, SWT.FILL);
+ mainComposite.setLayout(new GridLayout(3, false));
+ mainComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ setTitle(CertificateManagerNLS.ImportKeystorePage_Title);
+ setMessage(CertificateManagerNLS.ImportKeystorePage_Description);
+
+ createFilenameSection(mainComposite);
+ createKeystoreTypeSection(mainComposite);
+
+ validatePage();
+
+ setControl(mainComposite);
+
+ //set help id for this page
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, IMPORT_KEYSTORE_HELP_ID);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(mainComposite, IMPORT_KEYSTORE_HELP_ID);
+ }
+
+ private void createFilenameSection(Composite mainComposite)
+ {
+ Label keystoreFilenameLabel = new Label(mainComposite, SWT.NONE);
+ keystoreFilenameLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keystoreFilenameLabel
+ .setText(CertificateManagerNLS.CreateKeystorePage_KeystoreFilenameLabel);
+
+ keystoreFilename = new Text(mainComposite, SWT.SINGLE | SWT.BORDER);
+ keystoreFilename.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ keystoreFilename.addSelectionListener(selectionListener);
+ keystoreFilename.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ userChangedFilename = true;
+ validatePage();
+ }
+ });
+
+ Button chooseLocation = new Button(mainComposite, SWT.PUSH);
+ chooseLocation.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
+ chooseLocation.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreFilenameBrowse);
+ chooseLocation.addSelectionListener(new SelectionAdapter()
+ {
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ Shell shell = Display.getCurrent().getActiveShell();
+
+ FileDialog dialog = new FileDialog(shell, SWT.OPEN);
+
+ String keystoreFilenameStr = dialog.open();
+
+ if (keystoreFilenameStr != null)
+ {
+ keystoreFilename.setText(keystoreFilenameStr);
+ keystoreType.getCombo().setFocus();
+ }
+ }
+ });
+ }
+
+ private void createKeystoreTypeSection(Composite parent)
+ {
+ Label keystoreTypeLabel = new Label(parent, SWT.NONE);
+ keystoreTypeLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keystoreTypeLabel.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreType);
+
+ keystoreType = new ComboViewer(parent, SWT.READ_ONLY);
+ keystoreType.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false, 1, 1));
+ keystoreType.setContentProvider(new IStructuredContentProvider()
+ {
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ //do nothing
+ }
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object[] getElements(Object inputElement)
+ {
+ return ((List<String>) inputElement).toArray();
+ }
+ });
+ keystoreType.setLabelProvider(new ILabelProvider()
+ {
+
+ @Override
+ public void removeListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property)
+ {
+ return false;
+ }
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public void addListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public String getText(Object element)
+ {
+ return (String) element;
+ }
+
+ @Override
+ public Image getImage(Object element)
+ {
+ return null;
+ }
+ });
+
+ keystoreType.setInput(KeyStoreManager.getInstance().getAvailableTypes());
+
+ for (int i = 0; i < keystoreType.getCombo().getItemCount(); i++)
+ {
+ if (keystoreType.getCombo().getItem(i)
+ .compareToIgnoreCase(KeyStoreManager.getInstance().getDefaultType()) == 0)
+ {
+ keystoreType.getCombo().select(i);
+ }
+ }
+
+ keystoreType.getCombo().addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ validatePage();
+ }
+ });
+
+ //fill the third column with a blank label
+ Label separator2 = new Label(parent, SWT.NONE);
+ separator2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ }
+
+ protected boolean validatePage()
+ {
+ String errorMessage = null;
+ boolean pageComplete = true;
+ keystoreAlreadyMapped = false;
+
+ keystoreFile = new File(keystoreFilename.getText());
+ keystoreTypeString = keystoreType.getCombo().getText();
+
+ if (keystoreType.getCombo().getText().isEmpty())
+ {
+ errorMessage = CertificateManagerNLS.ImportKeystorePage_KeystoreTypeCannotBeEmpty;
+ pageComplete = false;
+ }
+
+ if (userChangedFilename && !keystoreFile.exists())
+ {
+ errorMessage =
+ NLS.bind(CertificateManagerNLS.ImportKeystorePage_FileDoesNotExist,
+ keystoreFilename.getText());
+ pageComplete = false;
+ }
+
+ if (keystoreFile.exists())
+ {
+ if (keystoreFile.isFile())
+ {
+ int fileSize = -1;
+ try
+ {
+ fileSize = FileUtil.getFileSize(keystoreFile);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ if (fileSize <= 0)
+ {
+ errorMessage =
+ NLS.bind(CertificateManagerNLS.ImportKeystorePage_FileEmpty,
+ keystoreFilename.getText());
+ pageComplete = false;
+ }
+ }
+ else if (keystoreFile.isDirectory())
+ {
+ errorMessage =
+ NLS.bind(
+ CertificateManagerNLS.ImportKeystorePage_DirectoryNotAllowedErrorMsg,
+ keystoreFilename.getText());
+ pageComplete = false;
+ }
+ }
+
+ if (keystoreFilename.getText().isEmpty())
+ {
+ errorMessage = CertificateManagerNLS.ImportKeystorePage_FilenameCannotBeEmpty;
+ pageComplete = false;
+ }
+
+ if (KeyStoreManager.getInstance().isKeystoreMapped(keystoreFile))
+ {
+ errorMessage =
+ NLS.bind(CertificateManagerNLS.ImportKeystorePage_KeystoreAlreadyMapped,
+ keystoreFilename.getText());
+ keystoreAlreadyMapped = true;
+ pageComplete = false;
+ }
+
+ setErrorMessage(errorMessage);
+ setPageComplete(pageComplete);
+
+ return pageComplete;
+ }
+
+ /**
+ * Import the keystore using the information provided by the user.
+ * @return True if the keystore was imported, false otherwise.
+ * */
+ protected boolean importKeystore(String password, boolean savePassword)
+ {
+ boolean successfullyImported = true;
+
+ validatePage();
+
+ if (isPageComplete())
+ {
+
+ KeyStoreNode keyStoreNode =
+ new KeyStoreNode(keystoreFile, keystoreType.getCombo().getText());
+
+ try
+ {
+ SigningAndKeysModelManager.getInstance().mapKeyStore(keyStoreNode);
+
+ if (savePassword)
+ {
+ PasswordProvider passwordProvider = new PasswordProvider(keystoreFile);
+ passwordProvider.saveKeyStorePassword(password);
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ //keystore already mapped
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.ImportKeystorePage_CouldNotImportKeystore,
+ e.getMessage());
+ successfullyImported = false;
+ }
+ }
+ else
+ {
+ successfullyImported = false;
+ }
+
+ return successfullyImported;
+ }
+
+ /**
+ * Import the keystore using the information provided by the user.
+ * @return True if the keystore was imported, false otherwise.
+ * */
+ public boolean importKeystore()
+ {
+ return importKeystore(null, false);
+ }
+
+ /**
+ *
+ * @return
+ */
+ protected IKeyStore getSelectedKeystore()
+ {
+ if ((keyStoreNode == null)
+ || !keyStoreNode.getFile().equals(keystoreFile)
+ || ((keyStoreNode.getFile().equals(keystoreFile)) && keyStoreNode.getType()
+ .equalsIgnoreCase(keystoreTypeString)))
+ {
+ keyStoreNode = new KeyStoreNode(keystoreFile, keystoreTypeString);
+ }
+ return keyStoreNode;
+ }
+
+ /**
+ * @return the mainComposite
+ */
+ protected Composite getMainComposite()
+ {
+ return mainComposite;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystoreWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystoreWizard.java
new file mode 100644
index 0000000..55e6d97
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystoreWizard.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+public class ImportKeystoreWizard extends Wizard
+{
+ ImportKeystorePage importKeystorePage = null;
+
+ private static final String WIZARD_BANNER = "icons/wizban/import_keystore_wiz.png"; //$NON-NLS-1$
+
+ public ImportKeystoreWizard()
+ {
+ setWindowTitle(CertificateManagerNLS.ImportKeystorePage_Title);
+ setDefaultPageImageDescriptor(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER));
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#createPageControls(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPageControls(Composite pageContainer)
+ {
+ super.createPageControls(pageContainer);
+
+ //the shell has the same help as its page
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(getShell(), ImportKeystorePage.IMPORT_KEYSTORE_HELP_ID);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#performFinish()
+ */
+ @Override
+ public boolean performFinish()
+ {
+ return importKeystorePage.importKeystore();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#addPages()
+ */
+ @Override
+ public void addPages()
+ {
+ importKeystorePage =
+ new ImportKeystorePage(CertificateManagerNLS.ImportKeystoreWizard_ImportKeystore);
+ addPage(importKeystorePage);
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignaturePage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignaturePage.java
new file mode 100644
index 0000000..cca8989
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignaturePage.java
@@ -0,0 +1,686 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.internal.resources.Folder;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
+import org.eclipse.ui.dialogs.ISelectionStatusValidator;
+import org.eclipse.ui.model.WorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.views.navigator.ResourceComparator;
+
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+@SuppressWarnings("restriction")
+public class RemoveExternalPackageSignaturePage extends WizardPage
+{
+ private Text sourceDirText = null;
+
+ private Button browseDirButton = null;
+
+ private Button workspaceDirButton = null;
+
+ private Tree packagesTree = null;
+
+ private Button selectAllButton = null;
+
+ private Button deselectAllButton = null;
+
+ private WizardSelection selection = null;
+
+ protected Composite mainComposite = null;
+
+ /**
+ * Create a new wizard page based on selection
+ *
+ * @param pageName
+ * the page name
+ * @param selection
+ * the selection
+ */
+ public RemoveExternalPackageSignaturePage(String pageName, IStructuredSelection selection)
+ {
+ super(pageName);
+ setDescription(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION);
+ setTitle(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE);
+ this.selection = new WizardSelection(selection);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets
+ * .Composite)
+ */
+ @Override
+ public void createControl(Composite parent)
+ {
+ this.mainComposite = new Composite(parent, SWT.NULL);
+ // create new layout with 3 columns of different sizes
+ GridLayout layout = new GridLayout(4, false);
+ this.mainComposite.setLayout(layout);
+
+ Label sourceDirLabel = new Label(this.mainComposite, SWT.NONE);
+ sourceDirLabel.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_LABEL);
+
+ GridData layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ sourceDirLabel.setLayoutData(layoutData);
+
+ this.sourceDirText = new Text(this.mainComposite, SWT.BORDER);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
+ this.sourceDirText.setLayoutData(layoutData);
+ this.sourceDirText.addListener(SWT.Modify, new SourceDirectoryTextListener());
+
+ this.browseDirButton = new Button(this.mainComposite, SWT.PUSH);
+ this.browseDirButton.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_FILESYSTEM);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ this.browseDirButton.setLayoutData(layoutData);
+ this.browseDirButton.addListener(SWT.Selection, new BrowseButtonListener());
+
+ this.workspaceDirButton = new Button(this.mainComposite, SWT.PUSH);
+ this.workspaceDirButton.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ this.workspaceDirButton.setLayoutData(layoutData);
+ this.workspaceDirButton.addListener(SWT.Selection, new WorkspaceButtonListener());
+
+ createExtendedArea(this.mainComposite);
+
+ createPackageTreeLabel();
+
+ this.packagesTree = new Tree(this.mainComposite, SWT.BORDER | SWT.CHECK | SWT.V_SCROLL);
+ layoutData = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 2);
+ layoutData.heightHint = 150;
+ this.packagesTree.setLayoutData(layoutData);
+ this.packagesTree.addListener(SWT.Selection, new TreeSelectionListener());
+
+ Composite selectionButtons = new Composite(this.mainComposite, SWT.FILL);
+ layoutData = new GridData(SWT.FILL, SWT.TOP, false, true, 1, 2);
+ selectionButtons.setLayoutData(layoutData);
+ FillLayout row = new FillLayout(SWT.VERTICAL);
+ row.spacing = 3;
+ selectionButtons.setLayout(row);
+
+ this.selectAllButton = new Button(selectionButtons, SWT.PUSH);
+ this.selectAllButton
+ .setText(CertificateManagerNLS.PACKAGE_EXPORT_WIZARD_AREA_SELECT_ALL_BUTTON);
+ SelectionButtonsListener selectionButtonsListener = new SelectionButtonsListener();
+ this.selectAllButton.addListener(SWT.Selection, selectionButtonsListener);
+
+ this.deselectAllButton = new Button(selectionButtons, SWT.PUSH);
+ this.deselectAllButton
+ .setText(CertificateManagerNLS.PACKAGE_EXPORT_WIZARD_AREA_DESELECT_ALL_BUTTON);
+ this.deselectAllButton.addListener(SWT.Selection, selectionButtonsListener);
+
+ this.sourceDirText.setText(this.selection.getSelectedDirectory());
+ populateTree(this.selection.getSelectedPackages());
+ updatePageComplete();
+ setControl(this.mainComposite);
+ }
+
+ protected void createPackageTreeLabel()
+ {
+ GridData layoutData;
+ Label packagesLabel = new Label(this.mainComposite, SWT.NONE);
+ packagesLabel
+ .setText(CertificateManagerNLS.RemoveExternalPackageSignaturePage_Package_Tree_Label);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1);
+ packagesLabel.setLayoutData(layoutData);
+ }
+
+ /**
+ * Create a composite area after the basic composite Subclasses that need
+ * more than the basic package selection screen should override this method
+ *
+ * @param mainComposite
+ */
+ protected void createExtendedArea(Composite parent)
+ {
+ PlatformUI
+ .getWorkbench()
+ .getHelpSystem()
+ .setHelp(parent,
+ CertificateManagerActivator.UNSIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID);
+ }
+
+ /**
+ * Populates the tree with the packages of base dir Requires a valid folder
+ * set as source dir
+ */
+ private void populateTree(List<String> selection)
+ {
+ File sourceDir = getSourcePath().toFile();
+ Color gray = new Color(null, 130, 130, 130);
+ this.packagesTree.removeAll();
+ if (sourceDir.isDirectory() && sourceDir.canWrite())
+ {
+ File[] list = sourceDir.listFiles();
+ for (File file : list)
+ {
+ if (file.canRead() && file.isFile() && file.getName().endsWith("apk")) //$NON-NLS-1$
+ {
+ TreeItem fileItem = new TreeItem(this.packagesTree, SWT.NONE);
+ String text = file.getName();
+ if (!file.canWrite())
+ {
+ text += " [" + CertificateManagerNLS.READ_ONLY_TEXT //$NON-NLS-1$
+ + "]"; //$NON-NLS-1$
+ fileItem.setForeground(gray);
+ }
+
+ fileItem.setText(text);
+ fileItem.setData(file);
+ if ((selection != null) && selection.contains(file.getName())
+ && file.canWrite())
+ {
+ fileItem.setChecked(true);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Validates if the source directory is valid one
+ *
+ * @return true if the source dir text is valid, false otherwise
+ */
+ private boolean isSourceDirValid()
+ {
+
+ String messageAux = null;
+ int severity = IMessageProvider.NONE;
+
+ /*
+ * Check if the selected location is valid, even if non existent.
+ */
+ IPath path = new Path(this.sourceDirText.getText());
+
+ // Test if path is blank, to warn user instead of show an error message
+ if (this.sourceDirText.getText().equals("")) //$NON-NLS-1$
+ {
+ messageAux =
+
+ CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_EMPTY;
+ severity = IMessageProvider.INFORMATION;
+ }
+
+ /*
+ * Do Win32 Validation
+ */
+ if ((messageAux == null) && Platform.getOS().equalsIgnoreCase(Platform.OS_WIN32))
+ {
+ // test path size
+ if (path.toString().length() > 255)
+ {
+ messageAux =
+
+ CertificateManagerNLS.SELECTOR_MESSAGE_LOCATION_ERROR_PATH_TOO_LONG;
+ severity = IMessageProvider.WARNING;
+ }
+ String device = path.getDevice();
+ File deviceFile = null;
+ if (device != null)
+ {
+ deviceFile = new File(path.getDevice());
+ }
+
+ if ((device != null) && !deviceFile.exists())
+ {
+ messageAux =
+
+ CertificateManagerNLS.SELECTOR_MESSAGE_LOCATION_ERROR_INVALID_DEVICE + " ["
+ + device + "]";
+ severity = IMessageProvider.ERROR;
+ }
+
+ }
+ // test if path is absolute
+ if (messageAux == null)
+ {
+ if (!path.isAbsolute() || !path.toFile().exists())
+ {
+ messageAux =
+
+ CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_INVALID;
+ severity = IMessageProvider.ERROR;
+ }
+ }
+
+ if (messageAux == null)
+ {
+ for (String folderName : path.segments())
+ {
+ if (!ResourcesPlugin.getWorkspace().validateName(folderName, IResource.FOLDER)
+ .isOK())
+ {
+ messageAux =
+
+ CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_INVALID;
+ severity = IMessageProvider.ERROR;
+
+ }
+ }
+ }
+
+ if ((messageAux == null) && ((path.toFile().exists() && !path.toFile().isDirectory())))
+ {
+ messageAux =
+
+ CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_NOT_DIRECTORY;
+ severity = IMessageProvider.ERROR;
+
+ }
+
+ /*
+ * Setting message
+ */
+ if (messageAux == null)
+ {
+ messageAux = CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION;
+ severity = IMessageProvider.NONE;
+ }
+ setMessage(messageAux, severity);
+ return severity == IMessageProvider.NONE;
+ }
+
+ /**
+ * @return the path of base dir where packages are located
+ */
+ public IPath getSourcePath()
+ {
+ return new Path(this.sourceDirText.getText());
+ }
+
+ /**
+ *
+ * @return the list with selected packages
+ */
+ public List<String> getSelectedPackages()
+ {
+ ArrayList<String> selected = new ArrayList<String>();
+ for (TreeItem item : this.packagesTree.getItems())
+ {
+ if (item.getChecked())
+ {
+ selected.add(item.getData().toString());
+ }
+ }
+
+ return selected;
+ }
+
+ /**
+ * Update the page status, validating each field of this page Subclasses
+ * that overrides createExtendedArea method should override this method too
+ * to validate the new fields
+ */
+ public void updatePageComplete()
+ {
+
+ String messageAux = null;
+ int severity = IMessageProvider.NONE;
+
+ /*
+ * Check if there are available certificates and if selection isn't null
+ */
+ if (isSourceDirValid())
+ {
+ if (this.packagesTree.getItemCount() == 0)
+ {
+ messageAux =
+
+ CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_NO_AVAILABLE_PACKAGES;
+ severity = IMessageProvider.ERROR;
+ }
+ }
+ else
+ {
+ messageAux = getMessage();
+ severity = getMessageType();
+ }
+
+ if ((messageAux == null) && (getSelectedPackages().size() == 0))
+ {
+ messageAux =
+
+ CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_NO_PACKAGES_SELECTED;
+ severity = IMessageProvider.INFORMATION;
+ }
+
+ if (messageAux == null)
+ {
+ messageAux =
+
+ CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION;
+ severity = IMessageProvider.NONE;
+ }
+
+ setMessage(messageAux, severity);
+ setPageComplete(severity == IMessageProvider.NONE);
+
+ }
+
+ /**
+ * This class implements the listener of filesystem button, opening the browse
+ * window and updating the dir text
+ */
+ class BrowseButtonListener implements Listener
+ {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
+ * .Event)
+ */
+ @Override
+ public void handleEvent(Event event)
+ {
+ DirectoryDialog dialog =
+ new DirectoryDialog(
+ RemoveExternalPackageSignaturePage.this.mainComposite.getShell());
+ dialog.setFilterPath(!RemoveExternalPackageSignaturePage.this.sourceDirText.getText()
+ .trim().equals("") ? RemoveExternalPackageSignaturePage.this.sourceDirText
+ .getText() : null);
+ String path = dialog.open();
+ if (path != null)
+ {
+ RemoveExternalPackageSignaturePage.this.sourceDirText.setText(path);
+ populateTree(null);
+ updatePageComplete();
+ }
+ }
+
+ }
+
+ /**
+ * This class implements the listener of workspace button, opening the browse
+ * window and updating the dir text
+ */
+ class WorkspaceButtonListener implements Listener
+ {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
+ * .Event)
+ */
+ @Override
+ public void handleEvent(Event event)
+ {
+ ElementTreeSelectionDialog dialog =
+ new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(),
+ new WorkbenchContentProvider());
+ dialog.setTitle(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE_SIMPLE);
+ dialog.setMessage(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_CHOOSE);
+
+ // set the workspace as the limit
+ dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
+ dialog.setComparator(new ResourceComparator(ResourceComparator.NAME));
+
+ //don't display files
+ dialog.addFilter(new ViewerFilter()
+ {
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element)
+ {
+ boolean filtered = false;
+
+ if (element instanceof IFile)
+ {
+ filtered = true;
+ }
+ return !filtered;
+ }
+ });
+
+ //user can select only one folder
+ dialog.setValidator(new ISelectionStatusValidator()
+ {
+
+ @Override
+ public IStatus validate(Object[] selection)
+ {
+ IStatus valid =
+ new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID, ""); //$NON-NLS-1$
+ if (selection.length == 1)
+ {
+ if (selection[0] instanceof Folder)
+ {
+ valid =
+ new Status(IStatus.OK, CertificateManagerActivator.PLUGIN_ID,
+ ""); //$NON-NLS-1$
+ }
+ }
+ return valid;
+ }
+ });
+
+ String path = null;
+ if (dialog.open() == IDialogConstants.OK_ID)
+ {
+ Folder resource = (Folder) dialog.getFirstResult();
+ path = resource.getLocation().toString();
+ }
+
+ if (path != null)
+ {
+ RemoveExternalPackageSignaturePage.this.sourceDirText.setText(path);
+ populateTree(null);
+ updatePageComplete();
+ }
+ }
+ }
+
+ /**
+ * Listener to validate any SourceDirectory text Change
+ */
+ class SourceDirectoryTextListener implements Listener
+ {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
+ * .Event)
+ */
+ @Override
+ public void handleEvent(Event event)
+ {
+ RemoveExternalPackageSignaturePage.this.packagesTree.removeAll();
+ if (isSourceDirValid())
+ {
+ populateTree(null);
+ }
+ updatePageComplete();
+ }
+
+ }
+
+ /**
+ * This class handles clicks on select all and deselect all buttons
+ */
+ class SelectionButtonsListener implements Listener
+ {
+
+ /**
+ * Check/Uncheck all items
+ *
+ * @param check
+ * : true for check, false for unckeck
+ */
+ private void setCheckedAll(boolean check)
+ {
+ for (TreeItem item : RemoveExternalPackageSignaturePage.this.packagesTree.getItems())
+ {
+ item.setChecked(check);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
+ * .Event)
+ */
+ @Override
+ public void handleEvent(Event event)
+ {
+ if (event.widget == RemoveExternalPackageSignaturePage.this.selectAllButton)
+ {
+ setCheckedAll(true);
+ }
+ else if (event.widget == RemoveExternalPackageSignaturePage.this.deselectAllButton)
+ {
+ setCheckedAll(false);
+ }
+ updatePageComplete();
+ }
+
+ }
+
+ /**
+ * Listener to update wizard status according tree selection
+ */
+ class TreeSelectionListener implements Listener
+ {
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
+ * .Event)
+ */
+ @Override
+ public void handleEvent(Event event)
+ {
+ updatePageComplete();
+ }
+
+ }
+
+ /**
+ * This class gets the workspace selection and makes a suitable selection to
+ * the wizard
+ */
+ class WizardSelection
+ {
+ private ArrayList<String> packages = null;
+
+ private IPath directory = null;
+
+ public WizardSelection(IStructuredSelection selection)
+ {
+ this.packages = new ArrayList<String>();
+ Iterator<?> iterator = selection.iterator();
+ while (iterator.hasNext())
+ {
+ Object obj = iterator.next();
+ if (obj instanceof IFile)
+ {
+ IFile file = (IFile) obj;
+
+ if (file.getLocation().getFileExtension().equals("apk")) //$NON-NLS-1$
+ {
+ if (this.directory == null)
+ {
+ this.directory = file.getLocation().removeLastSegments(1);
+ this.packages.add(file.getName());
+ }
+ else
+ {
+ if (file.getLocation().matchingFirstSegments(this.directory) == this.directory
+ .segmentCount())
+ {
+ this.packages.add(file.getName());
+ }
+ }
+ }
+ }
+ else if (obj instanceof IFolder)
+ {
+ if (this.directory == null)
+ {
+ this.directory = ((IFolder) obj).getLocation();
+ }
+ }
+ }
+ if (this.directory == null)
+ {
+ this.directory = new Path(""); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ *
+ * @return the selected directory
+ */
+ public String getSelectedDirectory()
+ {
+ return this.directory.toOSString();
+ }
+
+ /**
+ *
+ * @return the selected packages
+ */
+ public List<String> getSelectedPackages()
+ {
+ return this.packages;
+ }
+
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignatureWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignatureWizard.java
new file mode 100644
index 0000000..7783262
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignatureWizard.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.JarFile;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.packaging.PackageFile;
+
+/**
+ * This Wizard removes a signature of a package. based on a root dir, It shows a
+ * list of packages to remove signature
+ */
+public class RemoveExternalPackageSignatureWizard extends Wizard
+{
+ private RemoveExternalPackageSignaturePage page = null;
+
+ public RemoveExternalPackageSignatureWizard(IStructuredSelection selection)
+ {
+ setWindowTitle(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE);
+ setNeedsProgressMonitor(true);
+ this.page = new RemoveExternalPackageSignaturePage("removeSigPage", selection);
+ setDefaultPageImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID,
+ CertificateManagerActivator.REMOVE_SIGNATURE_WIZ_BAN));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.wizard.Wizard#addPages()
+ */
+ @Override
+ public void addPages()
+ {
+ addPage(this.page);
+ }
+
+ /**
+ * Finishes this wizard removing packages signatures
+ */
+ @Override
+ public boolean performFinish()
+ {
+ final List<String> defectivePackages = new ArrayList<String>();
+ IRunnableWithProgress finishAction = new IRunnableWithProgress()
+ {
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException,
+ InterruptedException
+ {
+ List<String> selectedFiles =
+ RemoveExternalPackageSignatureWizard.this.page.getSelectedPackages();
+ monitor.beginTask(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE,
+ selectedFiles.size());
+ for (String selected : selectedFiles)
+ {
+ File file = new File(selected);
+ monitor.setTaskName(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_OPERATION
+ + " " + file.getName());
+ if ((file != null) && file.exists() && file.isFile() && file.canWrite())
+ {
+ OutputStream fileToWrite = null;
+ JarFile jar = null;
+ PackageFile pack = null;
+ try
+ {
+ // Open package and remove signature
+ jar = new JarFile(file);
+ pack = new PackageFile(jar);
+ try
+ {
+ pack.removeMetaEntryFiles();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(
+ RemoveExternalPackageSignatureWizard.class.toString(),
+ "Impossible to delete temporary files");
+ throw e;
+ }
+
+ // Write the new package file
+ fileToWrite = new FileOutputStream(file);
+ pack.write(fileToWrite);
+ PackageFile.zipAlign(file);
+ }
+ catch (IOException e)
+ {
+ defectivePackages.add(selected);
+ StudioLogger.error(
+ RemoveExternalPackageSignatureWizard.class.toString(),
+ "Impossible write to package: " + selected + " "
+ + e.getMessage());
+ }
+ catch (SecurityException e)
+ {
+ defectivePackages.add(selected);
+ StudioLogger.error(
+ RemoveExternalPackageSignatureWizard.class.toString(),
+ "Impossible write to package: " + selected + " "
+ + e.getMessage());
+ }
+ finally
+ {
+
+ System.gc(); // Force garbage collector to avoid
+ // errors when deleting temp files
+
+ try
+ {
+ if (jar != null)
+ {
+ jar.close();
+ }
+
+ if (pack != null)
+ {
+ pack.removeTemporaryEntryFiles();
+ }
+
+ if (fileToWrite != null)
+ {
+ fileToWrite.close();
+ }
+ }
+ catch (IOException e)
+ {
+ // Silent exception. Only log the deletion
+ // exception.
+ StudioLogger.error(CertificateManagerActivator.PLUGIN_ID,
+ "Deleting temporary files");
+ }
+ }
+ }
+ else
+ {
+ defectivePackages.add(selected);
+ }
+ monitor.worked(1);
+ }
+ monitor.done();
+ }
+
+ };
+
+ try
+ {
+ PlatformUI.getWorkbench().getProgressService()
+ .runInUI(new ProgressMonitorDialog(getShell()), finishAction, null);
+ }
+ catch (InvocationTargetException e1)
+ {
+ StudioLogger.error(RemoveExternalPackageSignatureWizard.class.toString(),
+ "Error running finish actions");
+ }
+ catch (InterruptedException e1)
+ {
+ StudioLogger.error(RemoveExternalPackageSignatureWizard.class.toString(),
+ "Error running finish actions");
+ }
+
+ if (ResourcesPlugin.getWorkspace().getRoot().getLocation()
+ .isPrefixOf(this.page.getSourcePath()))
+ {
+ org.eclipse.ui.actions.WorkspaceModifyOperation op =
+ new org.eclipse.ui.actions.WorkspaceModifyOperation()
+ {
+
+ @Override
+ protected void execute(IProgressMonitor monitor) throws CoreException,
+ InvocationTargetException, InterruptedException
+ {
+ for (IContainer container : ResourcesPlugin
+ .getWorkspace()
+ .getRoot()
+ .findContainersForLocation(
+ RemoveExternalPackageSignatureWizard.this.page
+ .getSourcePath()))
+ {
+
+ container.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+ }
+
+ }
+
+ };
+ try
+ {
+ PlatformUI.getWorkbench().getProgressService().run(false, false, op);
+ }
+ catch (InvocationTargetException e)
+ {
+ StudioLogger.error(RemoveExternalPackageSignatureWizard.class.toString(),
+ "Error refreshing workspace");
+ }
+ catch (InterruptedException e)
+ {
+ StudioLogger.error(RemoveExternalPackageSignatureWizard.class.toString(),
+ "Error refreshing workspace");
+ }
+ }
+
+ if (!defectivePackages.isEmpty())
+ {
+ MultiStatus errors =
+ new MultiStatus(CertificateManagerActivator.PLUGIN_ID, IStatus.ERROR,
+ CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_ERROR_REASON, null);
+ for (String defect : defectivePackages)
+ {
+ errors.add(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID, defect));
+ }
+
+ ErrorDialog errorBox =
+ new ErrorDialog(getShell(),
+ CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE,
+ CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_ERROR, errors,
+ IStatus.ERROR);
+ errorBox.open();
+ }
+
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.jface.wizard.Wizard#createPageControls(org.eclipse.swt.widgets
+ * .Composite)
+ */
+ @Override
+ public void createPageControls(Composite pageContainer)
+ {
+ super.createPageControls(pageContainer);
+ PlatformUI
+ .getWorkbench()
+ .getHelpSystem()
+ .setHelp(getShell(),
+ CertificateManagerActivator.UNSIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID);
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystorePage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystorePage.java
new file mode 100644
index 0000000..71ecaef
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystorePage.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+/**
+ * Enables selection of a keystore (similar to {@link ImportKeystorePage} functionality.
+ * It adds a checkbox button that enables user to add the imported keystore into Signing and Keys view.
+ */
+public class SelectExistentKeystorePage extends ImportKeystorePage
+{
+ private static final int SMALL_TEXT_SIZE = 64;
+
+ public static final String SELECT_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".select_keystore"; //$NON-NLS-1$
+
+ private Button alsoImportIntoView = null;
+
+ private boolean importIntoView = true;
+
+ private Label keystorePasswordLabel;
+
+ private Text keystorePassword;
+
+ private Button savePasswordCheckBox;
+
+ private boolean canSavePassword = false;
+
+ private String password = null;
+
+ private SelectionListener selectionListener = new SelectionAdapter()
+ {
+
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ validatePage();
+ }
+ };
+
+ protected SelectExistentKeystorePage(String pageName)
+ {
+ super(pageName);
+ }
+
+ @Override
+ public void createControl(Composite parent)
+ {
+ super.createControl(parent);
+ setTitle(CertificateManagerNLS.SelectExistentKeystorePage_WizardPageTitle);
+ setMessage(CertificateManagerNLS.SelectExistentKeystorePage_WizardPageMessage);
+
+ //KEYSTORE PASSWORD SECTION
+ keystorePasswordLabel = new Label(getMainComposite(), SWT.NONE);
+ keystorePasswordLabel
+ .setText(CertificateManagerNLS.SelectExistentKeystorePage_KeystorePasswordLabel); //$NON-NLS-2$
+
+ keystorePassword = new Text(getMainComposite(), SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
+ keystorePassword.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ keystorePassword.setTextLimit(SMALL_TEXT_SIZE);
+ keystorePassword.addSelectionListener(selectionListener);
+ keystorePassword.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ password = keystorePassword.getText();
+ validatePage();
+ }
+ });
+
+ //Creates the save password checkbox
+ savePasswordCheckBox = new Button(getMainComposite(), SWT.CHECK);
+ savePasswordCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ savePasswordCheckBox.setText(CertificateManagerNLS.PasswordProvider_SaveThisPassword);
+ savePasswordCheckBox.setSelection(false);
+ savePasswordCheckBox.setVisible(importIntoView);
+ savePasswordCheckBox.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ //update according to check status
+ canSavePassword = savePasswordCheckBox.getSelection();
+ }
+
+ });
+
+ alsoImportIntoView = new Button(getMainComposite(), SWT.CHECK);
+ alsoImportIntoView.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ alsoImportIntoView
+ .setText(CertificateManagerNLS.SelectExistentKeystorePage_CheckboxText_AlsoImportIntoSigningView);
+ alsoImportIntoView.setSelection(importIntoView);
+ alsoImportIntoView.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ //update according to check status
+ importIntoView = alsoImportIntoView.getSelection();
+ savePasswordCheckBox.setEnabled(importIntoView);
+ canSavePassword = importIntoView && savePasswordCheckBox.getSelection();
+ }
+
+ });
+
+ //set help id for this page
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(getMainComposite(), SELECT_KEYSTORE_HELP_ID);
+ }
+
+ /**
+ * @return the importIntoView
+ */
+ public boolean needToImportIntoView()
+ {
+ return importIntoView;
+ }
+
+ /**
+ * @return the password
+ */
+ protected String getPassword()
+ {
+ return password;
+ }
+
+ @Override
+ protected boolean validatePage()
+ {
+ boolean pageComplete = super.validatePage();
+
+ String infoMessage = CertificateManagerNLS.SelectExistentKeystorePage_WizardPageMessage;
+ String errorMessage = null;
+
+ if (pageComplete)
+ {
+ if (!keystoreAlreadyMapped)
+ {
+ if (keystorePassword.getText().isEmpty())
+ {
+ pageComplete = false;
+ errorMessage = CertificateManagerNLS.CertificateBlock_EnterPassword_InfoMessage;
+ }
+ setMessage(infoMessage);
+ setErrorMessage(errorMessage);
+ setPageComplete(pageComplete);
+ }
+ }
+
+ return pageComplete;
+ }
+
+ /**
+ * @return the canSavePassword
+ */
+ protected boolean canSavePassword()
+ {
+ return canSavePassword;
+ }
+
+ /* (non-Javadoc)
+ * @see com.motorolamobility.studio.android.certmanager.ui.wizards.ImportKeystorePage#importKeystore()
+ */
+ @Override
+ public boolean importKeystore()
+ {
+ return importKeystore(getPassword(), canSavePassword());
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystoreWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystoreWizard.java
new file mode 100644
index 0000000..d5612df
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystoreWizard.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+
+/**
+ * Enables selection of a keystore (similar to {@link ImportKeystoreWizard} functionality.
+ * It adds a checkbox button that enables user to add the imported keystore into Signing and Keys view.
+ */
+public class SelectExistentKeystoreWizard extends Wizard
+{
+ protected SelectExistentKeystorePage selectExistentKeystorePage = null;
+
+ private static final String WIZARD_BANNER = "icons/wizban/import_keystore_wiz.png"; //$NON-NLS-1$
+
+ public static final String SELECT_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".select_keystore"; //$NON-NLS-1$
+
+ public SelectExistentKeystoreWizard()
+ {
+ setWindowTitle(CertificateManagerNLS.ImportKeystoreWizard_ImportKeystore);
+ setDefaultPageImageDescriptor(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER));
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#createPageControls(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPageControls(Composite pageContainer)
+ {
+ super.createPageControls(pageContainer);
+
+ //the shell has the same help as its page
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(getShell(), SELECT_KEYSTORE_HELP_ID);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#performFinish()
+ */
+ @Override
+ public boolean performFinish()
+ {
+ //check password and keystore type before importing
+ IKeyStore iKeyStore = selectExistentKeystorePage.getSelectedKeystore();
+ if (iKeyStore instanceof KeyStoreNode)
+ {
+ KeyStoreNode keyStoreNode = (KeyStoreNode) iKeyStore;
+ try
+ {
+ keyStoreNode.isPasswordValid(selectExistentKeystorePage.getPassword());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ selectExistentKeystorePage
+ .setErrorMessage(CertificateManagerNLS.SelectExistentKeystoreWizard_Error_KeystoreType);
+ //let dialog opened
+ return false;
+ }
+ catch (InvalidPasswordException e)
+ {
+ selectExistentKeystorePage
+ .setErrorMessage(CertificateManagerNLS.SelectExistentKeystoreWizard_Error_InvalidPassword);
+ //let dialog opened
+ return false;
+ }
+ }
+
+ if (selectExistentKeystorePage.needToImportIntoView())
+ {
+ //if user asked to import item in the Signing and keys view
+ selectExistentKeystorePage.importKeystore();
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#addPages()
+ */
+ @Override
+ public void addPages()
+ {
+ selectExistentKeystorePage =
+ new SelectExistentKeystorePage(
+ CertificateManagerNLS.SelectExistentKeystoreWizard_BrowseExistentKeystore_PageTitle);
+ addPage(selectExistentKeystorePage);
+ }
+
+ /**
+ *
+ * @return
+ */
+ public IKeyStore getSelectedKeystore()
+ {
+ IKeyStore iKeyStore = selectExistentKeystorePage.getSelectedKeystore();
+ return iKeyStore;
+ }
+
+ /**
+ *
+ * @return true if need to import into view, false otherwise
+ */
+ public boolean canSavePassword()
+ {
+ return selectExistentKeystorePage.canSavePassword();
+ }
+
+ /**
+ *
+ * @return true if need to import into view, false otherwise
+ */
+ public String getPassword()
+ {
+ return selectExistentKeystorePage.getPassword();
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackagePage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackagePage.java
new file mode 100644
index 0000000..75898eb
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackagePage.java
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+
+/**
+ * This class implements the page of signature of external packages wizard It
+ * extends the page that removes the signature and implements the needed fields
+ */
+public class SignExternalPackagePage extends RemoveExternalPackageSignaturePage
+{
+
+ private Label keystoreLabel = null;
+
+ private Label keysLabel = null;
+
+ private Combo keystoreCombo = null;
+
+ private Text keystorePassword = null;
+
+ private Button loadKeystore = null;
+
+ private Button savePassword = null;
+
+ private Combo keysCombo = null;
+
+ private String keyEntryPassword;
+
+ private String keyStoreType;
+
+ PasswordProvider pP = null;
+
+ private IKeyStore initialSelectedKeyStore = null;
+
+ private IKeyStoreEntry initialSelectedEntry = null;
+
+ private IKeyStore selectedKeystore = null;
+
+ SelectionAdapter loadKeysSelectionAdapter = new SelectionAdapter()
+ {
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e)
+ {
+ widgetSelected(e);
+ };
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ setKeyEntries();
+ }
+ };
+
+ /**
+ * Create a new wizard page based on selection
+ *
+ * @param pageName
+ * the page name
+ * @param selection
+ * the selection
+ */
+ public SignExternalPackagePage(String pageName, IStructuredSelection selection,
+ IKeyStore selectedIKeyStore, IKeyStoreEntry selectedEntry)
+ {
+ super(pageName, selection);
+ this.initialSelectedKeyStore = selectedIKeyStore;
+ this.initialSelectedEntry = selectedEntry;
+ setDescription(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION);
+ setTitle(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE);
+ }
+
+ private HashMap<String, IKeyStore> getAvailableKeystores()
+ {
+ HashMap<String, IKeyStore> keystores = new HashMap<String, IKeyStore>();
+ Iterator<IKeyStore> iterator = null;
+ try
+ {
+ if ((KeyStoreManager.getInstance() != null)
+ && (KeyStoreManager.getInstance().getKeyStores() != null))
+ {
+ iterator = KeyStoreManager.getInstance().getKeyStores().iterator();
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error(this.getClass(), "Error retrieving keystore list", e); //$NON-NLS-1$
+ }
+
+ while ((iterator != null) && (iterator.hasNext()))
+ {
+ KeyStoreNode keystore = (KeyStoreNode) iterator.next();
+
+ keystores.put(keystore.toString(), keystore);
+ }
+ return keystores;
+
+ }
+
+ /**
+ * @param keystorePath
+ * @return key strings for the selected keystore
+ */
+ private final String[] getAvailableEntriesForKeystore(IKeyStore keystore)
+ {
+ ArrayList<String> entries = new ArrayList<String>();
+
+ if (keystore != null)
+ {
+
+ pP = new PasswordProvider(keystore.getFile());
+ String password = null;
+ try
+ {
+ // retrieve the saved password
+ password = pP.getKeyStorePassword(false);
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ StudioLogger.error(this.getClass(), "Error retrieving keys from keystore", e1); //$NON-NLS-1$
+ }
+
+ if (password == null)
+ {
+ // password is not saved
+ if (!this.keystorePassword.getText().isEmpty())
+ {
+ // get the password from the wizard
+ password = this.keystorePassword.getText();
+ }
+ }
+ else
+ {
+ // the password was saved
+ try
+ {
+ keystore.isPasswordValid(password);
+ }
+ catch (InvalidPasswordException e)
+ {
+ if (!this.keystorePassword.getText().isEmpty())
+ {
+ // the saved password is invalid, get the password from the wizard
+ password = this.keystorePassword.getText();
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ //this exception should never happen here as it was handled at some point before
+ StudioLogger.error("This keystore was imported with wrong store type"); //$NON-NLS-1$
+ }
+ }
+ try
+ {
+ try
+ {
+ if (password != null)
+ {
+ // validate the password that was saved or from the wizard
+ keystore.isPasswordValid(password);
+ if (this.keystorePassword.getText().isEmpty())
+ {
+ // block the password fields if the password saved is valid
+ this.keystorePassword.setText(password);
+ this.keystorePassword.setEnabled(false);
+ this.savePassword.setSelection(true);
+ this.savePassword.setEnabled(false);
+ this.loadKeystore.setEnabled(false);
+ }
+ }
+ List<IKeyStoreEntry> keys = keystore.getEntries(password);
+
+ if ((keys.size() > 0) && (password != null))
+ {
+ this.keyStoreType = keystore.getType();
+ Iterator<IKeyStoreEntry> iterator2 = keys.iterator();
+ while ((iterator2 != null) && (iterator2.hasNext()))
+ {
+ EntryNode keyEntry = (EntryNode) iterator2.next();
+ entries.add(keyEntry.getId());
+ }
+
+ }
+
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error(this.getClass(), "Error retrieving keys from keystore", e); //$NON-NLS-1$
+ }
+
+ }
+ catch (InvalidPasswordException e)
+ {
+ setErrorMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Invalid_Keystore_Pass);
+ this.keystorePassword.setText(""); //$NON-NLS-1$
+ this.keystorePassword.setFocus(); //select the password text box so the user can retype the password
+ }
+ }
+
+ return entries.toArray(new String[0]);
+ }
+
+ /**
+ * Fill the key entries combo
+ *
+ */
+ private void setKeyEntries()
+ {
+ setErrorMessage(null);
+
+ String keystoreSelected = keystoreCombo.getItem(keystoreCombo.getSelectionIndex());
+
+ this.selectedKeystore = (IKeyStore) keystoreCombo.getData(keystoreSelected);
+ String[] availableKeys = getAvailableEntriesForKeystore(this.selectedKeystore);
+
+ if (availableKeys.length > 0)
+ {
+ keysCombo.setItems(availableKeys);
+ int selectedEntryIndex = 0;
+
+ if (initialSelectedEntry != null)
+ {
+ selectedEntryIndex = keysCombo.indexOf(initialSelectedEntry.getAlias());
+ initialSelectedEntry = null; //the selectedEntry only serves as first selection
+ }
+
+ keysCombo.select(selectedEntryIndex > 0 ? selectedEntryIndex : 0);
+
+ updatePageComplete();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorola.studio.android.packaging.ui.wizards.RemoveExternalPackageSignaturePage
+ * #createExtendedArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected void createExtendedArea(Composite parent)
+ {
+ GridData layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+
+ // Keystore label
+ this.keystoreLabel = new Label(parent, SWT.NONE);
+ this.keystoreLabel.setText(CertificateManagerNLS.SIGN_WIZARD_AREA_SIGN_KEYSTORE_LABEL);
+ this.keystoreLabel.setLayoutData(layoutData);
+
+ // Keystore combo
+ this.keystoreCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.SINGLE);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1);
+ this.keystoreCombo.setLayoutData(layoutData);
+ keystoreCombo.addSelectionListener(new SelectionAdapter()
+ {
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ keystorePassword.setText(""); //$NON-NLS-1$
+ keystorePassword.setEnabled(true);
+ savePassword.setSelection(false);
+ savePassword.setEnabled(false);
+ loadKeystore.setEnabled(false);
+ keysCombo.removeAll();
+ setKeyEntries();
+ if (keystorePassword.getEnabled())
+ {
+ keystorePassword.setFocus();
+ }
+ //it only serves as
+ initialSelectedKeyStore = null;
+ }
+
+ });
+
+ // Keystore password label
+ Label keystorePasswordLabel = new Label(parent, SWT.NONE);
+ keystorePasswordLabel
+ .setText(CertificateManagerNLS.CreateKeystorePage_KeystorePasswordLabel);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ keystorePasswordLabel.setLayoutData(layoutData);
+
+ // Keystore password combo
+ this.keystorePassword = new Text(parent, SWT.BORDER | SWT.PASSWORD);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1);
+ this.keystorePassword.setLayoutData(layoutData);
+ this.keystorePassword.addListener(SWT.Modify, new Listener()
+ {
+ @Override
+ public void handleEvent(Event event)
+ {
+ if (keystorePassword.getText().isEmpty())
+ {
+ loadKeystore.setEnabled(false);
+ savePassword.setEnabled(false);
+ }
+ else
+ {
+ loadKeystore.setEnabled(true);
+ savePassword.setEnabled(true);
+ }
+ keysCombo.removeAll();
+ updatePageComplete();
+ }
+ });
+ this.keystorePassword.addSelectionListener(loadKeysSelectionAdapter);
+
+ // Load key entries Button
+ this.loadKeystore = new Button(parent, SWT.PUSH);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ this.loadKeystore.setLayoutData(layoutData);
+ this.loadKeystore.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_LOAD);
+ this.loadKeystore.setEnabled(false);
+ this.loadKeystore.addSelectionListener(loadKeysSelectionAdapter);
+
+ // Save Keystore Password checkbox
+ this.savePassword = new Button(parent, SWT.CHECK);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1);
+ this.savePassword.setLayoutData(layoutData);
+ this.savePassword.setText(CertificateManagerNLS.PasswordProvider_SaveThisPassword);
+ this.savePassword.setEnabled(false);
+ this.savePassword.setSelection(false);
+
+ // key entry label
+ this.keysLabel = new Label(parent, SWT.NONE);
+ this.keysLabel.setText(CertificateManagerNLS.SIGN_WIZARD_AREA_SIGN_KEYS_LABEL);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ this.keysLabel.setLayoutData(layoutData);
+
+ // key entry combo
+ this.keysCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.SINGLE);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1);
+ this.keysCombo.setLayoutData(layoutData);
+
+ PlatformUI
+ .getWorkbench()
+ .getHelpSystem()
+ .setHelp(parent,
+ CertificateManagerActivator.SIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID);
+
+ populateKeyStoreCombo();
+ }
+
+ @Override
+ protected void createPackageTreeLabel()
+ {
+ GridData layoutData;
+ Label packagesLabel = new Label(this.mainComposite, SWT.NONE);
+ packagesLabel.setText(CertificateManagerNLS.SignExternalPackagePage_Package_Tree_Label);
+ layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1);
+ packagesLabel.setLayoutData(layoutData);
+ }
+
+ protected void populateKeyStoreCombo()
+ {
+ HashMap<String, IKeyStore> availableKeystores = getAvailableKeystores();
+ if (availableKeystores.size() > 0)
+ {
+
+ for (String keystoreKey : availableKeystores.keySet())
+ {
+ IKeyStore newKeystore = availableKeystores.get(keystoreKey);
+ this.keystoreCombo.setData(keystoreKey, availableKeystores.get(keystoreKey));
+ this.keystoreCombo.add(newKeystore.toString());
+
+ if (initialSelectedKeyStore != null)
+ {
+ if (initialSelectedKeyStore.equals(newKeystore))
+ {
+ //select combo with the item selected in Signing and keys view
+ keystoreCombo.select(keystoreCombo.indexOf(newKeystore.toString()));
+ setKeyEntries();
+ }
+ }
+ }
+
+ if (initialSelectedKeyStore == null)
+ {
+ this.keystoreCombo.select(0);
+ }
+ }
+ }
+
+ /**
+ *
+ * @return the key entry selected by user
+ */
+ public IKeyStoreEntry getSelectedKeyEntry()
+ {
+ IKeyStoreEntry result = null;
+ try
+ {
+ result =
+ this.selectedKeystore.getEntry(
+ this.keysCombo.getItem(this.keysCombo.getSelectionIndex()),
+ getKeystorePassword());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ // should never happen
+ StudioLogger.error("Could not retrieve entry while signing package"); //$NON-NLS-1$
+ }
+ catch (InvalidPasswordException e)
+ {
+ // should never happen
+ StudioLogger.error("Invalid password while retrieving entry to sign package"); //$NON-NLS-1$
+ }
+
+ return result;
+ }
+
+ /**
+ *
+ * @return the keystore selected by user
+ */
+ public IKeyStore getSelectedKeyStore()
+ {
+ return this.selectedKeystore;
+ }
+
+ /**
+ *
+ * @return the keystore password entered by user
+ */
+ public String getKeystorePassword()
+ {
+ return this.keystorePassword.getText();
+ }
+
+ /**
+ *
+ * @return key entry password
+ */
+ public String getKeyEntryPassword()
+ {
+
+ try
+ {
+ this.keyEntryPassword =
+ pP.getPassword(this.keysCombo.getItem(this.keysCombo.getSelectionIndex()), true);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error(this.getClass(), "Error retrieving keys entry password", e); //$NON-NLS-1$
+ }
+ return this.keyEntryPassword;
+ }
+
+ public PasswordProvider getPasswordProvider()
+ {
+ return pP;
+ }
+
+ /**
+ *
+ * @return the keystore type
+ */
+ public String getKeyStoreType()
+ {
+ return this.keyStoreType;
+ }
+
+ /**
+ * Update the page status, validating each field of this page The basic
+ * validation is made by superclass
+ */
+ @Override
+ public void updatePageComplete()
+ {
+ super.updatePageComplete();
+ int severity = getMessageType();
+ String messageAux = severity == IMessageProvider.NONE ? null : getMessage();
+
+ if (messageAux == null)
+ {
+ if (!(((this.keystoreCombo != null) && (this.keystoreCombo.getItemCount() > 0)
+ && (this.keystoreCombo.getItem(this.keystoreCombo.getSelectionIndex()) != null) && !this.keystoreCombo
+ .getItem(this.keystoreCombo.getSelectionIndex()).equalsIgnoreCase("")) && ((this.keysCombo != null) //$NON-NLS-1$
+ && (this.keysCombo.getItemCount() > 0)
+ && (this.keysCombo.getItem(this.keysCombo.getSelectionIndex()) != null) && !this.keysCombo
+ .getItem(this.keysCombo.getSelectionIndex()).equalsIgnoreCase("")))) //$NON-NLS-1$
+ {
+ messageAux =
+
+ CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_NO_CERTIFICATE_ERROR;
+ severity = IMessageProvider.ERROR;
+ }
+
+ if (messageAux == null)
+ {
+ messageAux =
+
+ CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION;
+ severity = IMessageProvider.NONE;
+ }
+
+ setMessage(messageAux, severity);
+ setPageComplete(severity == IMessageProvider.NONE);
+ }
+
+ }
+
+ /**
+ * @return checkbox save password
+ */
+ public boolean getSavePasswordSelection()
+ {
+ return this.savePassword.getSelection();
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackageWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackageWizard.java
new file mode 100644
index 0000000..ca9541f
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackageWizard.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.security.UnrecoverableKeyException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.JarFile;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.packaging.PackageFile;
+import com.motorolamobility.studio.android.certmanager.packaging.sign.PackageFileSigner;
+import com.motorolamobility.studio.android.certmanager.packaging.sign.SignException;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+
+/**
+ * This Wizard signs a package. based on a root dir, It shows a list o packages
+ * to sign and let user choose a certificate to use
+ */
+public class SignExternalPackageWizard extends Wizard
+{
+ private SignExternalPackagePage page = null;
+
+ public SignExternalPackageWizard(IStructuredSelection selection, IKeyStore selectedKeyStore)
+ {
+ this(selection, selectedKeyStore, null);
+ }
+
+ public SignExternalPackageWizard(IStructuredSelection selection, IKeyStore selectedKeyStore,
+ IKeyStoreEntry selectedEntry)
+ {
+ setWindowTitle(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE);
+ setNeedsProgressMonitor(true);
+ setHelpAvailable(false);
+ this.page =
+ new SignExternalPackagePage("signPage", selection, selectedKeyStore, selectedEntry);
+ setDefaultPageImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID,
+ CertificateManagerActivator.SIGNATURE_WIZ_BAN));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.wizard.Wizard#addPages()
+ */
+ @Override
+ public void addPages()
+ {
+ addPage(this.page);
+ }
+
+ /**
+ * Finishes this wizard, signing the selected packages
+ */
+ @Override
+ public boolean performFinish()
+ {
+ final List<String> defectivePackages = new ArrayList<String>();
+ IRunnableWithProgress finishAction = new IRunnableWithProgress()
+ {
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException,
+ InterruptedException
+ {
+ List<String> selectedFiles =
+ SignExternalPackageWizard.this.page.getSelectedPackages();
+ monitor.beginTask(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE,
+ selectedFiles.size() * 2);
+ for (String selected : selectedFiles)
+ {
+ File file = new File(selected);
+ monitor.setTaskName(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_OPERATION
+ + " " + file.getName());
+ if ((file != null) && file.exists() && file.isFile() && file.canWrite())
+ {
+ OutputStream fileToWrite = null;
+ PackageFile pack = null;
+ JarFile jar = null;
+ try
+ {
+
+ // Update monitor
+ monitor.worked(1);
+ monitor.setTaskName(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_OPERATION
+ + " " + file.getName());
+
+ String keyStorePassword =
+ SignExternalPackageWizard.this.page.getKeystorePassword();
+ if (SignExternalPackageWizard.this.page.getSavePasswordSelection())
+ {
+ SignExternalPackageWizard.this.page.getPasswordProvider()
+ .saveKeyStorePassword(keyStorePassword);
+ }
+ String keyEntryPassword =
+ SignExternalPackageWizard.this.page.getKeyEntryPassword();
+ boolean keepTrying;
+ if (keyEntryPassword != null)
+ {
+ keepTrying = true;
+ }
+ else
+ {
+ keepTrying = false;
+ throw new Exception();
+ }
+ while (keepTrying)
+ {
+ try
+ {
+ // Open package and remove signature
+ jar = new JarFile(file);
+ pack = new PackageFile(jar);
+ pack.removeMetaEntryFiles();
+
+ // Sign the new package
+ PackageFileSigner.signPackage(pack,
+ SignExternalPackageWizard.this.page
+ .getSelectedKeyEntry(), keyEntryPassword,
+ PackageFileSigner.MOTODEV_STUDIO);
+ keepTrying = false;
+ }
+ catch (UnrecoverableKeyException sE)
+ {
+ keyEntryPassword =
+ SignExternalPackageWizard.this.page
+ .getPasswordProvider().getPassword(
+ SignExternalPackageWizard.this.page
+ .getSelectedKeyEntry()
+ .getAlias(), true, false);
+ if (keyEntryPassword == null)
+ {
+ keepTrying = false;
+ }
+ else
+ {
+ keepTrying = true;
+ }
+ }
+ }
+
+ // Write the new package file
+ fileToWrite = new FileOutputStream(file);
+ pack.write(fileToWrite);
+ PackageFile.zipAlign(file);
+ }
+ catch (IOException e)
+ {
+ defectivePackages.add(selected);
+ StudioLogger.error(
+ SignExternalPackageWizard.class.toString(),
+ "Impossible write to package: " + selected + " "
+ + e.getMessage());
+ }
+ catch (SignException e)
+ {
+ defectivePackages.add(selected);
+ StudioLogger.error(
+ SignExternalPackageWizard.class.toString(),
+ "Impossible sign the package: " + selected + " "
+ + e.getMessage());
+ }
+ catch (SecurityException e)
+ {
+ defectivePackages.add(selected);
+ StudioLogger.error(
+ SignExternalPackageWizard.class.toString(),
+ "Impossible sign the package: " + selected + " "
+ + e.getMessage());
+ }
+ catch (Exception e)
+ {
+ defectivePackages.add(selected);
+ StudioLogger.error(
+ SignExternalPackageWizard.class.toString(),
+ "Impossible sign the package: " + selected + " "
+ + e.getMessage());
+ }
+ finally
+ {
+ System.gc(); // Force garbage collector to avoid
+ // errors when deleting temp files
+
+ try
+ {
+ if (pack != null)
+ {
+ pack.removeTemporaryEntryFiles();
+ }
+
+ if (fileToWrite != null)
+ {
+ fileToWrite.close();
+ }
+
+ if (jar != null)
+ {
+ jar.close();
+ }
+ }
+ catch (IOException e)
+ {
+ // Silent exception. Only log the deletion
+ // exception.
+ StudioLogger.error(CertificateManagerActivator.PLUGIN_ID,
+ "Deleting temporary files");
+ }
+ }
+ }
+ else
+ {
+ defectivePackages.add(selected);
+ }
+ monitor.worked(1);
+ }
+ monitor.done();
+ }
+
+ };
+
+ try
+ {
+ PlatformUI.getWorkbench().getProgressService()
+ .runInUI(new ProgressMonitorDialog(getShell()), finishAction, null);
+ }
+ catch (InvocationTargetException e1)
+ {
+ StudioLogger.error(SignExternalPackageWizard.class.toString(),
+ "Error running finish actions");
+ }
+ catch (InterruptedException e1)
+ {
+ StudioLogger.error(SignExternalPackageWizard.class.toString(),
+ "Error running finish actions");
+ }
+
+ if (ResourcesPlugin.getWorkspace().getRoot().getLocation()
+ .isPrefixOf(this.page.getSourcePath()))
+ {
+ WorkspaceModifyOperation op = new WorkspaceModifyOperation()
+ {
+
+ @Override
+ protected void execute(IProgressMonitor monitor) throws CoreException,
+ InvocationTargetException, InterruptedException
+ {
+ for (IContainer container : ResourcesPlugin
+ .getWorkspace()
+ .getRoot()
+ .findContainersForLocation(
+ SignExternalPackageWizard.this.page.getSourcePath()))
+ {
+
+ container.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+ }
+
+ }
+
+ };
+ try
+ {
+ PlatformUI.getWorkbench().getProgressService().run(false, false, op);
+ }
+ catch (InvocationTargetException e)
+ {
+ StudioLogger.error(SignExternalPackageWizard.class.toString(),
+ "Error refreshing workspace");
+ }
+ catch (InterruptedException e)
+ {
+ StudioLogger.error(SignExternalPackageWizard.class.toString(),
+ "Error refreshing workspace");
+ }
+ }
+ if (!defectivePackages.isEmpty())
+ {
+ MultiStatus errors =
+ new MultiStatus(CertificateManagerActivator.PLUGIN_ID, IStatus.ERROR,
+ CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_ERROR_REASON, null);
+ for (String defect : defectivePackages)
+ {
+ errors.add(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID, defect));
+ }
+
+ ErrorDialog errorBox =
+ new ErrorDialog(getShell(),
+ CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE,
+ CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_ERROR, errors,
+ IStatus.ERROR);
+ errorBox.open();
+ }
+ return true;
+
+ }
+
+ @Override
+ public void createPageControls(Composite pageContainer)
+ {
+ super.createPageControls(pageContainer);
+ PlatformUI
+ .getWorkbench()
+ .getHelpSystem()
+ .setHelp(getShell(),
+ CertificateManagerActivator.SIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID);
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/views/KeystoreManagerView.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/views/KeystoreManagerView.java
new file mode 100644
index 0000000..2cd4988
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/views/KeystoreManagerView.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2012 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.motorolamobility.studio.android.certmanager.views;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.event.IKeyStoreModelListener;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreRootNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+import com.motorolamobility.studio.android.certmanager.ui.tree.ExpiresInColumnLabelProvider;
+import com.motorolamobility.studio.android.certmanager.ui.tree.KeystoreManagerTreeContentProvider;
+import com.motorolamobility.studio.android.certmanager.ui.tree.LastBackupDateColumnLabelProvider;
+import com.motorolamobility.studio.android.certmanager.ui.tree.NameAliasColumnLabelProvider;
+import com.motorolamobility.studio.android.certmanager.ui.tree.PathColumnLabelProvider;
+import com.motorolamobility.studio.android.certmanager.ui.tree.TypeColumnLabelProvider;
+
+/**
+ * View to manage certificates under MOTODEV Studio for Android
+ */
+public class KeystoreManagerView extends ViewPart implements IKeyStoreModelListener
+{
+ /**
+ * The ID of the view as specified by the extension.
+ */
+ public static final String ID = "com.motorola.studio.android.packaging.ui.signingview"; //$NON-NLS-1$
+
+ private TreeViewer viewer;
+
+ /**
+ * This is a callback that will allow us
+ * to create the viewer and initialize it.
+ */
+ @Override
+ public void createPartControl(Composite parent)
+ {
+ viewer =
+ new TreeViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER
+ | SWT.FULL_SELECTION | SWT.VIRTUAL | SWT.MULTI); //Virtual is required due to ILazyTreeContentProvider
+ viewer.setUseHashlookup(true);
+ viewer.setAutoExpandLevel(0);
+
+ viewer.setContentProvider(new KeystoreManagerTreeContentProvider(viewer));
+ viewer.setInput(getInitalInput());
+ viewer.expandToLevel(getInitalInput(), 1);
+ ColumnViewerToolTipSupport.enableFor(viewer);
+
+ getSite().setSelectionProvider(viewer);
+
+ Tree tree = viewer.getTree();
+ tree.setLinesVisible(true);
+ tree.setHeaderVisible(true);
+ tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ {
+ TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.NONE);
+ treeViewerColumn.setLabelProvider(new NameAliasColumnLabelProvider());
+ TreeColumn trclmnNewColumn = treeViewerColumn.getColumn();
+ trclmnNewColumn.setWidth(250);
+ trclmnNewColumn
+ .setText(CertificateManagerNLS.CertificateManagerView_NameAlias_ColumnName);
+
+ tree.setSortColumn(treeViewerColumn.getColumn());
+ tree.setSortDirection(SWT.DOWN);
+ }
+ {
+ TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.NONE);
+ treeViewerColumn.setLabelProvider(new TypeColumnLabelProvider());
+ TreeColumn trclmnNewColumn = treeViewerColumn.getColumn();
+ trclmnNewColumn.setWidth(75);
+ trclmnNewColumn.setText(CertificateManagerNLS.CertificateManagerView_Type_ColumnName);
+ }
+ {
+ TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.NONE);
+ treeViewerColumn.setLabelProvider(new ExpiresInColumnLabelProvider());
+ TreeColumn trclmnExpiresIn = treeViewerColumn.getColumn();
+ trclmnExpiresIn.setWidth(100);
+ trclmnExpiresIn
+ .setText(CertificateManagerNLS.CertificateManagerView_ExpiresIn_ColumnName);
+ }
+ {
+ TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.NONE);
+ treeViewerColumn.setLabelProvider(new LastBackupDateColumnLabelProvider());
+ TreeColumn trclmnLastBackupDate = treeViewerColumn.getColumn();
+ trclmnLastBackupDate.setWidth(125);
+ trclmnLastBackupDate
+ .setText(CertificateManagerNLS.CertificateManagerView_LastBackupDate_ColumnName);
+ }
+ {
+ TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.LEFT);
+ treeViewerColumn.setLabelProvider(new PathColumnLabelProvider());
+ TreeColumn trclmnPath = treeViewerColumn.getColumn();
+ trclmnPath.setWidth(500);
+ trclmnPath.setText(CertificateManagerNLS.CertificateManagerView_Path_ColumnName);
+ }
+
+ // Create the help context id for the viewer's control
+ PlatformUI
+ .getWorkbench()
+ .getHelpSystem()
+ .setHelp(viewer.getControl(),
+ "com.motorolamobility.studio.android.certmanager.viewer"); //$NON-NLS-1$
+
+ hookContextMenu();
+
+ getSite().setSelectionProvider(viewer);
+
+ //register listener for model changes
+ KeyStoreModelEventManager.getInstance().addListener(this);
+ }
+
+ private void hookContextMenu()
+ {
+ MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
+ menuMgr.setRemoveAllWhenShown(true);
+ menuMgr.addMenuListener(new IMenuListener()
+ {
+ @Override
+ public void menuAboutToShow(IMenuManager manager)
+ {
+ fillContextMenu(manager);
+ }
+ });
+ Menu menu = menuMgr.createContextMenu(viewer.getControl());
+ viewer.getControl().setMenu(menu);
+ getSite().registerContextMenu(menuMgr, viewer);
+ }
+
+ private void fillContextMenu(IMenuManager manager)
+ {
+ // Other plug-ins can contribute there actions here
+ // manager.add(openClose);
+ manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+ }
+
+ /**
+ * Loads the keystores from preference and <user_home>\motodevstudio\tools\motodev.keystore
+ * @return root node (invisible) that contains as children the keystores.
+ */
+ private Object getInitalInput()
+ {
+ return SigningAndKeysModelManager.getInstance().getKeyStoresRootNode();
+ }
+
+ /**
+ * Passing the focus request to the viewer's control.
+ */
+ @Override
+ public void setFocus()
+ {
+ viewer.getControl().setFocus();
+ }
+
+ public TreeViewer getTreeViewer()
+ {
+ return viewer;
+ }
+
+ /**
+ * Closing the view
+ */
+ @Override
+ public void dispose()
+ {
+ super.dispose();
+ //remove listener for model changes
+ KeyStoreModelEventManager.getInstance().removeListener(this);
+ }
+
+ /* (non-Javadoc)
+ * @see com.motorolamobility.studio.android.certmanager.event.IKeyStoreModelListener#handleNodeAdditionEvent(com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent)
+ */
+ @Override
+ public void handleNodeAdditionEvent(final KeyStoreModelEvent keyStoreModeEvent)
+ {
+ Display display = Display.getDefault();
+ if (!display.isDisposed())
+ {
+ display.syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ ITreeNode treeNodeItem = keyStoreModeEvent.getTreeNodeItem();
+ ITreeNode parentNode = treeNodeItem.getParent();
+
+ /* (parentNode instanceof KeyStoreRootNode) is a workaround to add nodes to the root node
+ * since getTreeViewer().getExpandedState(parentNode) always return false when the parentNode
+ * is the root node (KeyStoreRootNode in this case)
+ */
+ if (getTreeViewer().getExpandedState(parentNode)
+ || (parentNode instanceof KeyStoreRootNode))
+ {
+ getTreeViewer().add(parentNode, treeNodeItem);
+ }
+ else
+ {
+ List<ITreeNode> children;
+ try
+ {
+ children = parentNode.getChildren();
+ }
+ catch (KeyStoreManagerException e)
+ {
+ children = Collections.emptyList();
+ }
+
+ if (children.size() > 0)
+ {
+ getTreeViewer().setChildCount(parentNode, children.size());
+ }
+ }
+ }
+ });
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.motorolamobility.studio.android.certmanager.event.IKeyStoreModelListener#handleNodeRemovalEvent(com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent)
+ */
+ @Override
+ public void handleNodeRemovalEvent(final KeyStoreModelEvent keyStoreModeEvent)
+ {
+ Display display = Display.getDefault();
+ if (!display.isDisposed())
+ {
+ display.syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ if (!getTreeViewer().getTree().isDisposed())
+ {
+ getTreeViewer().remove(keyStoreModeEvent.getTreeNodeItem());
+ }
+ }
+ });
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.motorolamobility.studio.android.certmanager.event.IKeyStoreModelListener#handleNodeUpdateEvent(com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent)
+ */
+ @Override
+ public void handleNodeUpdateEvent(final KeyStoreModelEvent keyStoreModeEvent)
+ {
+ Display display = Display.getDefault();
+ if (!display.isDisposed())
+ {
+ display.asyncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ ITreeNode treeNode = keyStoreModeEvent.getTreeNodeItem();
+ getTreeViewer().update(treeNode, null);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void handleNodeCollapseEvent(final KeyStoreModelEvent keyStoreModelEvent)
+ {
+ Display display = Display.getDefault();
+ if (!display.isDisposed())
+ {
+ display.asyncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ ITreeNode treeNode = keyStoreModelEvent.getTreeNodeItem();
+ //Ugly workaround to avoid JFace treeViewer to enter in a infinite loop asking for children all the time.
+ getTreeViewer().remove(treeNode);
+ getTreeViewer().add(treeNode.getParent(), treeNode);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void handleNodeRefreshEvent(final KeyStoreModelEvent keyStoreModelEvent)
+ {
+ Display display = Display.getDefault();
+ if (!display.isDisposed())
+ {
+ display.asyncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ ITreeNode treeNode = keyStoreModelEvent.getTreeNodeItem();
+ if (treeNode != null)
+ {
+ try
+ {
+ getTreeViewer().remove(treeNode, treeNode.getChildren().toArray());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. "
+ + e.getMessage());
+ }
+
+ getTreeViewer().refresh(treeNode, true);
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public void handleNodeClearEvent(final KeyStoreModelEvent keyStoreModelEvent)
+ {
+ Display display = Display.getDefault();
+ if (!display.isDisposed())
+ {
+ display.syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ ITreeNode treeNode = keyStoreModelEvent.getTreeNodeItem();
+ if (treeNode != null)
+ {
+ try
+ {
+ getTreeViewer().remove(treeNode, treeNode.getChildren().toArray());
+ getTreeViewer().setChildCount(treeNode, 0);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. "
+ + e.getMessage());
+ }
+ }
+ }
+ });
+ }
+ }
+} \ No newline at end of file