Merge change 21617 into donut
* changes: ADT Export wizard now calls ZipAlign
This commit is contained in:
@@ -454,12 +454,17 @@ public class AdtPlugin extends AbstractUIPlugin {
|
|||||||
|
|
||||||
/** Returns the adb path relative to the sdk folder */
|
/** Returns the adb path relative to the sdk folder */
|
||||||
public static String getOsRelativeAdb() {
|
public static String getOsRelativeAdb() {
|
||||||
return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_ADB;
|
return SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_ADB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the zipalign path relative to the sdk folder */
|
||||||
|
public static String getOsRelativeZipAlign() {
|
||||||
|
return SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_ZIPALIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the emulator path relative to the sdk folder */
|
/** Returns the emulator path relative to the sdk folder */
|
||||||
public static String getOsRelativeEmulator() {
|
public static String getOsRelativeEmulator() {
|
||||||
return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_EMULATOR;
|
return SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_EMULATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the absolute adb path */
|
/** Returns the absolute adb path */
|
||||||
@@ -467,6 +472,11 @@ public class AdtPlugin extends AbstractUIPlugin {
|
|||||||
return getOsSdkFolder() + getOsRelativeAdb();
|
return getOsSdkFolder() + getOsRelativeAdb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the absolute zipalign path */
|
||||||
|
public static String getOsAbsoluteZipAlign() {
|
||||||
|
return getOsSdkFolder() + getOsRelativeZipAlign();
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the absolute traceview path */
|
/** Returns the absolute traceview path */
|
||||||
public static String getOsAbsoluteTraceview() {
|
public static String getOsAbsoluteTraceview() {
|
||||||
return getOsSdkFolder() + SdkConstants.OS_SDK_TOOLS_FOLDER +
|
return getOsSdkFolder() + SdkConstants.OS_SDK_TOOLS_FOLDER +
|
||||||
|
|||||||
@@ -106,10 +106,6 @@ public class AndroidConstants {
|
|||||||
public final static Pattern PATTERN_RESOURCES_S_AP_ =
|
public final static Pattern PATTERN_RESOURCES_S_AP_ =
|
||||||
Pattern.compile("resources-.*\\.ap_", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
|
Pattern.compile("resources-.*\\.ap_", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
|
||||||
|
|
||||||
public final static String FN_ADB = SdkConstants.FN_ADB;
|
|
||||||
|
|
||||||
public final static String FN_EMULATOR = SdkConstants.FN_EMULATOR;
|
|
||||||
|
|
||||||
public final static String FN_TRACEVIEW =
|
public final static String FN_TRACEVIEW =
|
||||||
(SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
|
(SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
|
||||||
"traceview.exe" : "traceview"; //$NON-NLS-1$ //$NON-NLS-2$
|
"traceview.exe" : "traceview"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|||||||
@@ -41,17 +41,17 @@ import java.util.zip.ZipOutputStream;
|
|||||||
* Export helper for project.
|
* Export helper for project.
|
||||||
*/
|
*/
|
||||||
public final class ExportHelper {
|
public final class ExportHelper {
|
||||||
|
|
||||||
private static IExportCallback sCallback;
|
private static IExportCallback sCallback;
|
||||||
|
|
||||||
public interface IExportCallback {
|
public interface IExportCallback {
|
||||||
void startExportWizard(IProject project);
|
void startExportWizard(IProject project);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCallback(IExportCallback callback) {
|
public static void setCallback(IExportCallback callback) {
|
||||||
sCallback = callback;
|
sCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void startExportWizard(IProject project) {
|
public static void startExportWizard(IProject project) {
|
||||||
if (sCallback != null) {
|
if (sCallback != null) {
|
||||||
sCallback.startExportWizard(project);
|
sCallback.startExportWizard(project);
|
||||||
@@ -69,30 +69,30 @@ public final class ExportHelper {
|
|||||||
IFolder outputFolder = BaseProjectHelper.getOutputFolder(project);
|
IFolder outputFolder = BaseProjectHelper.getOutputFolder(project);
|
||||||
if (outputFolder != null) {
|
if (outputFolder != null) {
|
||||||
IPath binLocation = outputFolder.getLocation();
|
IPath binLocation = outputFolder.getLocation();
|
||||||
|
|
||||||
// make the full path to the package
|
// make the full path to the package
|
||||||
String fileName = project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
|
String fileName = project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
|
||||||
|
|
||||||
File file = new File(binLocation.toOSString() + File.separator + fileName);
|
File file = new File(binLocation.toOSString() + File.separator + fileName);
|
||||||
|
|
||||||
if (file.exists() == false || file.isFile() == false) {
|
if (file.exists() == false || file.isFile() == false) {
|
||||||
MessageDialog.openInformation(Display.getCurrent().getActiveShell(),
|
MessageDialog.openError(Display.getCurrent().getActiveShell(),
|
||||||
"Android IDE Plug-in",
|
"Android IDE Plug-in",
|
||||||
String.format("Failed to export %1$s: %2$s doesn't exist!",
|
String.format("Failed to export %1$s: %2$s doesn't exist!",
|
||||||
project.getName(), file.getPath()));
|
project.getName(), file.getPath()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ok now pop up the file save window
|
// ok now pop up the file save window
|
||||||
FileDialog fileDialog = new FileDialog(shell, SWT.SAVE);
|
FileDialog fileDialog = new FileDialog(shell, SWT.SAVE);
|
||||||
|
|
||||||
fileDialog.setText("Export Project");
|
fileDialog.setText("Export Project");
|
||||||
fileDialog.setFileName(fileName);
|
fileDialog.setFileName(fileName);
|
||||||
|
|
||||||
String saveLocation = fileDialog.open();
|
String saveLocation = fileDialog.open();
|
||||||
if (saveLocation != null) {
|
if (saveLocation != null) {
|
||||||
// get the stream from the original file
|
// get the stream from the original file
|
||||||
|
|
||||||
ZipInputStream zis = null;
|
ZipInputStream zis = null;
|
||||||
ZipOutputStream zos = null;
|
ZipOutputStream zos = null;
|
||||||
FileInputStream input = null;
|
FileInputStream input = null;
|
||||||
@@ -116,8 +116,8 @@ public final class ExportHelper {
|
|||||||
// pass
|
// pass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageDialog.openInformation(shell, "Android IDE Plug-in",
|
MessageDialog.openError(shell, "Android IDE Plug-in",
|
||||||
String.format("Failed to export %1$s: %2$s doesn't exist!",
|
String.format("Failed to export %1$s: %2$s doesn't exist!",
|
||||||
project.getName(), file.getPath()));
|
project.getName(), file.getPath()));
|
||||||
return;
|
return;
|
||||||
@@ -125,20 +125,20 @@ public final class ExportHelper {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
ZipEntry entry;
|
ZipEntry entry;
|
||||||
|
|
||||||
byte[] buffer = new byte[4096];
|
byte[] buffer = new byte[4096];
|
||||||
|
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
while ((entry = zis.getNextEntry()) != null) {
|
||||||
String name = entry.getName();
|
String name = entry.getName();
|
||||||
|
|
||||||
// do not take directories or anything inside the META-INF folder since
|
// do not take directories or anything inside the META-INF folder since
|
||||||
// we want to strip the signature.
|
// we want to strip the signature.
|
||||||
if (entry.isDirectory() || name.startsWith("META-INF/")) { //$NON-NL1$
|
if (entry.isDirectory() || name.startsWith("META-INF/")) { //$NON-NL1$
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZipEntry newEntry;
|
ZipEntry newEntry;
|
||||||
|
|
||||||
// Preserve the STORED method of the input entry.
|
// Preserve the STORED method of the input entry.
|
||||||
if (entry.getMethod() == JarEntry.STORED) {
|
if (entry.getMethod() == JarEntry.STORED) {
|
||||||
newEntry = new JarEntry(entry);
|
newEntry = new JarEntry(entry);
|
||||||
@@ -146,12 +146,12 @@ public final class ExportHelper {
|
|||||||
// Create a new entry so that the compressed len is recomputed.
|
// Create a new entry so that the compressed len is recomputed.
|
||||||
newEntry = new JarEntry(name);
|
newEntry = new JarEntry(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the entry to the jar archive
|
// add the entry to the jar archive
|
||||||
zos.putNextEntry(newEntry);
|
zos.putNextEntry(newEntry);
|
||||||
|
|
||||||
// read the content of the entry from the input stream, and write it into the archive.
|
// read the content of the entry from the input stream, and write it into the archive.
|
||||||
int count;
|
int count;
|
||||||
while ((count = zis.read(buffer)) != -1) {
|
while ((count = zis.read(buffer)) != -1) {
|
||||||
zos.write(buffer, 0, count);
|
zos.write(buffer, 0, count);
|
||||||
}
|
}
|
||||||
@@ -159,11 +159,10 @@ public final class ExportHelper {
|
|||||||
// close the entry for this file
|
// close the entry for this file
|
||||||
zos.closeEntry();
|
zos.closeEntry();
|
||||||
zis.closeEntry();
|
zis.closeEntry();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
MessageDialog.openInformation(shell, "Android IDE Plug-in",
|
MessageDialog.openError(shell, "Android IDE Plug-in",
|
||||||
String.format("Failed to export %1$s: %2$s",
|
String.format("Failed to export %1$s: %2$s",
|
||||||
project.getName(), e.getMessage()));
|
project.getName(), e.getMessage()));
|
||||||
} finally {
|
} finally {
|
||||||
@@ -178,9 +177,19 @@ public final class ExportHelper {
|
|||||||
// pass
|
// pass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is unsigned export. Let's tell the developers to run zip align
|
||||||
|
MessageDialog.openWarning(shell, "Android IDE Plug-in", String.format(
|
||||||
|
"An unsigned package of the application was saved at\n%1$s\n\n" +
|
||||||
|
"Before publishing the application you will need to:\n" +
|
||||||
|
"- Sign the application with your release key,\n" +
|
||||||
|
"- run zipalign on the signed package. ZipAlign is located in <SDK>/tools/\n\n" +
|
||||||
|
"Aligning applications allows Android to use application resources\n" +
|
||||||
|
"more efficiently.", saveLocation));
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MessageDialog.openInformation(shell, "Android IDE Plug-in",
|
MessageDialog.openError(shell, "Android IDE Plug-in",
|
||||||
String.format("Failed to export %1$s: Could not get project output location",
|
String.format("Failed to export %1$s: Could not get project output location",
|
||||||
project.getName()));
|
project.getName()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,19 +16,18 @@
|
|||||||
|
|
||||||
package com.android.ide.eclipse.adt.internal.wizards.export;
|
package com.android.ide.eclipse.adt.internal.wizards.export;
|
||||||
|
|
||||||
|
import com.android.ide.eclipse.adt.AdtConstants;
|
||||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||||
import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
|
import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
|
||||||
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
|
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
|
||||||
import com.android.jarutils.KeystoreHelper;
|
import com.android.jarutils.KeystoreHelper;
|
||||||
import com.android.jarutils.SignedJarBuilder;
|
import com.android.jarutils.SignedJarBuilder;
|
||||||
import com.android.jarutils.DebugKeyProvider.IKeyGenOutput;
|
import com.android.jarutils.DebugKeyProvider.IKeyGenOutput;
|
||||||
import com.android.jarutils.DebugKeyProvider.KeytoolException;
|
|
||||||
|
|
||||||
import org.eclipse.core.resources.IFolder;
|
import org.eclipse.core.resources.IFolder;
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.resources.IResource;
|
import org.eclipse.core.resources.IResource;
|
||||||
import org.eclipse.core.resources.IncrementalProjectBuilder;
|
import org.eclipse.core.resources.IncrementalProjectBuilder;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
|
||||||
import org.eclipse.core.runtime.IAdaptable;
|
import org.eclipse.core.runtime.IAdaptable;
|
||||||
import org.eclipse.core.runtime.IProgressMonitor;
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
import org.eclipse.jface.operation.IRunnableWithProgress;
|
import org.eclipse.jface.operation.IRunnableWithProgress;
|
||||||
@@ -43,15 +42,16 @@ import org.eclipse.ui.IExportWizard;
|
|||||||
import org.eclipse.ui.IWorkbench;
|
import org.eclipse.ui.IWorkbench;
|
||||||
import org.eclipse.ui.PlatformUI;
|
import org.eclipse.ui.PlatformUI;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.PrintStream;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.KeyStore.PrivateKeyEntry;
|
import java.security.KeyStore.PrivateKeyEntry;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
@@ -62,23 +62,23 @@ import java.util.Set;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export wizard to export an apk signed with a release key/certificate.
|
* Export wizard to export an apk signed with a release key/certificate.
|
||||||
*/
|
*/
|
||||||
public final class ExportWizard extends Wizard implements IExportWizard {
|
public final class ExportWizard extends Wizard implements IExportWizard {
|
||||||
|
|
||||||
private static final String PROJECT_LOGO_LARGE = "icons/android_large.png"; //$NON-NLS-1$
|
private static final String PROJECT_LOGO_LARGE = "icons/android_large.png"; //$NON-NLS-1$
|
||||||
|
|
||||||
private static final String PAGE_PROJECT_CHECK = "Page_ProjectCheck"; //$NON-NLS-1$
|
private static final String PAGE_PROJECT_CHECK = "Page_ProjectCheck"; //$NON-NLS-1$
|
||||||
private static final String PAGE_KEYSTORE_SELECTION = "Page_KeystoreSelection"; //$NON-NLS-1$
|
private static final String PAGE_KEYSTORE_SELECTION = "Page_KeystoreSelection"; //$NON-NLS-1$
|
||||||
private static final String PAGE_KEY_CREATION = "Page_KeyCreation"; //$NON-NLS-1$
|
private static final String PAGE_KEY_CREATION = "Page_KeyCreation"; //$NON-NLS-1$
|
||||||
private static final String PAGE_KEY_SELECTION = "Page_KeySelection"; //$NON-NLS-1$
|
private static final String PAGE_KEY_SELECTION = "Page_KeySelection"; //$NON-NLS-1$
|
||||||
private static final String PAGE_KEY_CHECK = "Page_KeyCheck"; //$NON-NLS-1$
|
private static final String PAGE_KEY_CHECK = "Page_KeyCheck"; //$NON-NLS-1$
|
||||||
|
|
||||||
static final String PROPERTY_KEYSTORE = "keystore"; //$NON-NLS-1$
|
static final String PROPERTY_KEYSTORE = "keystore"; //$NON-NLS-1$
|
||||||
static final String PROPERTY_ALIAS = "alias"; //$NON-NLS-1$
|
static final String PROPERTY_ALIAS = "alias"; //$NON-NLS-1$
|
||||||
static final String PROPERTY_DESTINATION = "destination"; //$NON-NLS-1$
|
static final String PROPERTY_DESTINATION = "destination"; //$NON-NLS-1$
|
||||||
static final String PROPERTY_FILENAME = "baseFilename"; //$NON-NLS-1$
|
static final String PROPERTY_FILENAME = "baseFilename"; //$NON-NLS-1$
|
||||||
|
|
||||||
static final int APK_FILE_SOURCE = 0;
|
static final int APK_FILE_SOURCE = 0;
|
||||||
static final int APK_FILE_DEST = 1;
|
static final int APK_FILE_DEST = 1;
|
||||||
static final int APK_COUNT = 2;
|
static final int APK_COUNT = 2;
|
||||||
@@ -87,7 +87,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
* Base page class for the ExportWizard page. This class add the {@link #onShow()} callback.
|
* Base page class for the ExportWizard page. This class add the {@link #onShow()} callback.
|
||||||
*/
|
*/
|
||||||
static abstract class ExportWizardPage extends WizardPage {
|
static abstract class ExportWizardPage extends WizardPage {
|
||||||
|
|
||||||
/** bit mask constant for project data change event */
|
/** bit mask constant for project data change event */
|
||||||
protected static final int DATA_PROJECT = 0x001;
|
protected static final int DATA_PROJECT = 0x001;
|
||||||
/** bit mask constant for keystore data change event */
|
/** bit mask constant for keystore data change event */
|
||||||
@@ -99,13 +99,13 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
public void verifyText(VerifyEvent e) {
|
public void verifyText(VerifyEvent e) {
|
||||||
// verify the characters are valid for password.
|
// verify the characters are valid for password.
|
||||||
int len = e.text.length();
|
int len = e.text.length();
|
||||||
|
|
||||||
// first limit to 127 characters max
|
// first limit to 127 characters max
|
||||||
if (len + ((Text)e.getSource()).getText().length() > 127) {
|
if (len + ((Text)e.getSource()).getText().length() > 127) {
|
||||||
e.doit = false;
|
e.doit = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now only take non control characters
|
// now only take non control characters
|
||||||
for (int i = 0 ; i < len ; i++) {
|
for (int i = 0 ; i < len ; i++) {
|
||||||
if (e.text.charAt(i) < 32) {
|
if (e.text.charAt(i) < 32) {
|
||||||
@@ -115,7 +115,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bit mask indicating what changed while the page was hidden.
|
* Bit mask indicating what changed while the page was hidden.
|
||||||
* @see #DATA_PROJECT
|
* @see #DATA_PROJECT
|
||||||
@@ -123,13 +123,13 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
* @see #DATA_KEY
|
* @see #DATA_KEY
|
||||||
*/
|
*/
|
||||||
protected int mProjectDataChanged = 0;
|
protected int mProjectDataChanged = 0;
|
||||||
|
|
||||||
ExportWizardPage(String name) {
|
ExportWizardPage(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract void onShow();
|
abstract void onShow();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setVisible(boolean visible) {
|
public void setVisible(boolean visible) {
|
||||||
super.setVisible(visible);
|
super.setVisible(visible);
|
||||||
@@ -138,23 +138,23 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
mProjectDataChanged = 0;
|
mProjectDataChanged = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final void projectDataChanged(int changeMask) {
|
final void projectDataChanged(int changeMask) {
|
||||||
mProjectDataChanged |= changeMask;
|
mProjectDataChanged |= changeMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls {@link #setErrorMessage(String)} and {@link #setPageComplete(boolean)} based on a
|
* Calls {@link #setErrorMessage(String)} and {@link #setPageComplete(boolean)} based on a
|
||||||
* {@link Throwable} object.
|
* {@link Throwable} object.
|
||||||
*/
|
*/
|
||||||
protected void onException(Throwable t) {
|
protected void onException(Throwable t) {
|
||||||
String message = getExceptionMessage(t);
|
String message = getExceptionMessage(t);
|
||||||
|
|
||||||
setErrorMessage(message);
|
setErrorMessage(message);
|
||||||
setPageComplete(false);
|
setPageComplete(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExportWizardPage mPages[] = new ExportWizardPage[5];
|
private ExportWizardPage mPages[] = new ExportWizardPage[5];
|
||||||
|
|
||||||
private IProject mProject;
|
private IProject mProject;
|
||||||
@@ -189,7 +189,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
setWindowTitle("Export Android Application");
|
setWindowTitle("Export Android Application");
|
||||||
setImageDescriptor();
|
setImageDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addPages() {
|
public void addPages() {
|
||||||
addPage(mPages[0] = new ProjectCheckPage(this, PAGE_PROJECT_CHECK));
|
addPage(mPages[0] = new ProjectCheckPage(this, PAGE_PROJECT_CHECK));
|
||||||
@@ -209,7 +209,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
mDestinationParentFolder.getAbsolutePath());
|
mDestinationParentFolder.getAbsolutePath());
|
||||||
ProjectHelper.saveStringProperty(mProject, PROPERTY_FILENAME,
|
ProjectHelper.saveStringProperty(mProject, PROPERTY_FILENAME,
|
||||||
mApkMap.get(null)[APK_FILE_DEST]);
|
mApkMap.get(null)[APK_FILE_DEST]);
|
||||||
|
|
||||||
// run the export in an UI runnable.
|
// run the export in an UI runnable.
|
||||||
IWorkbench workbench = PlatformUI.getWorkbench();
|
IWorkbench workbench = PlatformUI.getWorkbench();
|
||||||
final boolean[] result = new boolean[1];
|
final boolean[] result = new boolean[1];
|
||||||
@@ -234,10 +234,10 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result[0];
|
return result[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean doExport(IProgressMonitor monitor) {
|
private boolean doExport(IProgressMonitor monitor) {
|
||||||
try {
|
try {
|
||||||
// first we make sure the project is built
|
// first we make sure the project is built
|
||||||
@@ -262,13 +262,13 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
output.add(message);
|
output.add(message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (createdStore == false) {
|
if (createdStore == false) {
|
||||||
// keystore creation error!
|
// keystore creation error!
|
||||||
displayError(output.toArray(new String[output.size()]));
|
displayError(output.toArray(new String[output.size()]));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// keystore is created, now load the private key and certificate.
|
// keystore is created, now load the private key and certificate.
|
||||||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
FileInputStream fis = new FileInputStream(mKeystore);
|
FileInputStream fis = new FileInputStream(mKeystore);
|
||||||
@@ -276,7 +276,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
fis.close();
|
fis.close();
|
||||||
PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(
|
PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(
|
||||||
mKeyAlias, new KeyStore.PasswordProtection(mKeyPassword.toCharArray()));
|
mKeyAlias, new KeyStore.PasswordProtection(mKeyPassword.toCharArray()));
|
||||||
|
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
mPrivateKey = entry.getPrivateKey();
|
mPrivateKey = entry.getPrivateKey();
|
||||||
mCertificate = (X509Certificate)entry.getCertificate();
|
mCertificate = (X509Certificate)entry.getCertificate();
|
||||||
@@ -287,7 +287,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the private key/certificate again since it may have been created just above.
|
// check the private key/certificate again since it may have been created just above.
|
||||||
if (mPrivateKey != null && mCertificate != null) {
|
if (mPrivateKey != null && mCertificate != null) {
|
||||||
// get the output folder of the project to export.
|
// get the output folder of the project to export.
|
||||||
@@ -297,27 +297,50 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String outputOsPath = outputIFolder.getLocation().toOSString();
|
String outputOsPath = outputIFolder.getLocation().toOSString();
|
||||||
|
|
||||||
// now generate the packages.
|
// now generate the packages.
|
||||||
Set<Entry<String, String[]>> set = mApkMap.entrySet();
|
Set<Entry<String, String[]>> set = mApkMap.entrySet();
|
||||||
|
|
||||||
|
boolean runZipAlign = false;
|
||||||
|
String path = AdtPlugin.getOsAbsoluteZipAlign();
|
||||||
|
File zipalign = new File(path);
|
||||||
|
runZipAlign = zipalign.isFile();
|
||||||
|
|
||||||
for (Entry<String, String[]> entry : set) {
|
for (Entry<String, String[]> entry : set) {
|
||||||
String[] defaultApk = entry.getValue();
|
String[] defaultApk = entry.getValue();
|
||||||
String srcFilename = defaultApk[APK_FILE_SOURCE];
|
String srcFilename = defaultApk[APK_FILE_SOURCE];
|
||||||
String destFilename = defaultApk[APK_FILE_DEST];
|
String destFilename = defaultApk[APK_FILE_DEST];
|
||||||
|
File destFile;
|
||||||
|
if (runZipAlign) {
|
||||||
|
destFile = File.createTempFile("android", ".apk");
|
||||||
|
} else {
|
||||||
|
destFile = new File(mDestinationParentFolder, destFilename);
|
||||||
|
}
|
||||||
|
|
||||||
FileOutputStream fos = new FileOutputStream(
|
|
||||||
new File(mDestinationParentFolder, destFilename));
|
FileOutputStream fos = new FileOutputStream(destFile);
|
||||||
SignedJarBuilder builder = new SignedJarBuilder(fos, mPrivateKey, mCertificate);
|
SignedJarBuilder builder = new SignedJarBuilder(fos, mPrivateKey, mCertificate);
|
||||||
|
|
||||||
// get the input file.
|
// get the input file.
|
||||||
FileInputStream fis = new FileInputStream(new File(outputOsPath, srcFilename));
|
FileInputStream fis = new FileInputStream(new File(outputOsPath, srcFilename));
|
||||||
|
|
||||||
// add the content of the source file to the output file, and sign it at
|
// add the content of the source file to the output file, and sign it at
|
||||||
// the same time.
|
// the same time.
|
||||||
try {
|
try {
|
||||||
builder.writeZip(fis, null /* filter */);
|
builder.writeZip(fis, null /* filter */);
|
||||||
// close the builder: write the final signature files, and close the archive.
|
// close the builder: write the final signature files,
|
||||||
|
// and close the archive.
|
||||||
builder.close();
|
builder.close();
|
||||||
|
|
||||||
|
// now zipalign the result
|
||||||
|
if (runZipAlign) {
|
||||||
|
File realDestFile = new File(mDestinationParentFolder, destFilename);
|
||||||
|
String message = zipAlign(path, destFile, realDestFile);
|
||||||
|
if (message != null) {
|
||||||
|
displayError(message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
fis.close();
|
fis.close();
|
||||||
@@ -326,25 +349,26 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// export success. In case we didn't run ZipAlign we display a warning
|
||||||
|
if (runZipAlign == false) {
|
||||||
|
AdtPlugin.displayWarning("Export Wizard",
|
||||||
|
"The zipalign tool was not found in the SDK.\n\n" +
|
||||||
|
"Please update to the latest SDK and re-export your application\n" +
|
||||||
|
"or run zipalign manually.\n\n" +
|
||||||
|
"Aligning applications allows Android to use application resources\n" +
|
||||||
|
"more efficiently.");
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException e) {
|
} catch (Throwable t) {
|
||||||
displayError(e);
|
displayError(t);
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
displayError(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
displayError(e);
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
displayError(e);
|
|
||||||
} catch (KeytoolException e) {
|
|
||||||
displayError(e);
|
|
||||||
} catch (CoreException e) {
|
|
||||||
displayError(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canFinish() {
|
public boolean canFinish() {
|
||||||
// check if we have the apk to resign, the destination location, and either
|
// check if we have the apk to resign, the destination location, and either
|
||||||
@@ -356,7 +380,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
|| mKeystoreCreationMode || mKeyCreationMode) &&
|
|| mKeystoreCreationMode || mKeyCreationMode) &&
|
||||||
mDestinationParentFolder != null;
|
mDestinationParentFolder != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.eclipse.ui.IWorkbenchWizard#init(org.eclipse.ui.IWorkbench, org.eclipse.jface.viewers.IStructuredSelection)
|
* @see org.eclipse.ui.IWorkbenchWizard#init(org.eclipse.ui.IWorkbench, org.eclipse.jface.viewers.IStructuredSelection)
|
||||||
@@ -364,7 +388,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
public void init(IWorkbench workbench, IStructuredSelection selection) {
|
public void init(IWorkbench workbench, IStructuredSelection selection) {
|
||||||
// get the project from the selection
|
// get the project from the selection
|
||||||
Object selected = selection.getFirstElement();
|
Object selected = selection.getFirstElement();
|
||||||
|
|
||||||
if (selected instanceof IProject) {
|
if (selected instanceof IProject) {
|
||||||
mProject = (IProject)selected;
|
mProject = (IProject)selected;
|
||||||
} else if (selected instanceof IAdaptable) {
|
} else if (selected instanceof IAdaptable) {
|
||||||
@@ -374,19 +398,19 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportWizardPage getKeystoreSelectionPage() {
|
ExportWizardPage getKeystoreSelectionPage() {
|
||||||
return mKeystoreSelectionPage;
|
return mKeystoreSelectionPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportWizardPage getKeyCreationPage() {
|
ExportWizardPage getKeyCreationPage() {
|
||||||
return mKeyCreationPage;
|
return mKeyCreationPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportWizardPage getKeySelectionPage() {
|
ExportWizardPage getKeySelectionPage() {
|
||||||
return mKeySelectionPage;
|
return mKeySelectionPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportWizardPage getKeyCheckPage() {
|
ExportWizardPage getKeyCheckPage() {
|
||||||
return mKeyCheckPage;
|
return mKeyCheckPage;
|
||||||
}
|
}
|
||||||
@@ -398,39 +422,39 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
ImageDescriptor desc = AdtPlugin.getImageDescriptor(PROJECT_LOGO_LARGE);
|
ImageDescriptor desc = AdtPlugin.getImageDescriptor(PROJECT_LOGO_LARGE);
|
||||||
setDefaultPageImageDescriptor(desc);
|
setDefaultPageImageDescriptor(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
IProject getProject() {
|
IProject getProject() {
|
||||||
return mProject;
|
return mProject;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setProject(IProject project) {
|
void setProject(IProject project) {
|
||||||
mProject = project;
|
mProject = project;
|
||||||
|
|
||||||
updatePageOnChange(ExportWizardPage.DATA_PROJECT);
|
updatePageOnChange(ExportWizardPage.DATA_PROJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setKeystore(String path) {
|
void setKeystore(String path) {
|
||||||
mKeystore = path;
|
mKeystore = path;
|
||||||
mPrivateKey = null;
|
mPrivateKey = null;
|
||||||
mCertificate = null;
|
mCertificate = null;
|
||||||
|
|
||||||
updatePageOnChange(ExportWizardPage.DATA_KEYSTORE);
|
updatePageOnChange(ExportWizardPage.DATA_KEYSTORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getKeystore() {
|
String getKeystore() {
|
||||||
return mKeystore;
|
return mKeystore;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setKeystoreCreationMode(boolean createStore) {
|
void setKeystoreCreationMode(boolean createStore) {
|
||||||
mKeystoreCreationMode = createStore;
|
mKeystoreCreationMode = createStore;
|
||||||
updatePageOnChange(ExportWizardPage.DATA_KEYSTORE);
|
updatePageOnChange(ExportWizardPage.DATA_KEYSTORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean getKeystoreCreationMode() {
|
boolean getKeystoreCreationMode() {
|
||||||
return mKeystoreCreationMode;
|
return mKeystoreCreationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setKeystorePassword(String password) {
|
void setKeystorePassword(String password) {
|
||||||
mKeystorePassword = password;
|
mKeystorePassword = password;
|
||||||
mPrivateKey = null;
|
mPrivateKey = null;
|
||||||
@@ -438,7 +462,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
|
|
||||||
updatePageOnChange(ExportWizardPage.DATA_KEYSTORE);
|
updatePageOnChange(ExportWizardPage.DATA_KEYSTORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getKeystorePassword() {
|
String getKeystorePassword() {
|
||||||
return mKeystorePassword;
|
return mKeystorePassword;
|
||||||
}
|
}
|
||||||
@@ -447,15 +471,15 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
mKeyCreationMode = createKey;
|
mKeyCreationMode = createKey;
|
||||||
updatePageOnChange(ExportWizardPage.DATA_KEY);
|
updatePageOnChange(ExportWizardPage.DATA_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean getKeyCreationMode() {
|
boolean getKeyCreationMode() {
|
||||||
return mKeyCreationMode;
|
return mKeyCreationMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setExistingAliases(List<String> aliases) {
|
void setExistingAliases(List<String> aliases) {
|
||||||
mExistingAliases = aliases;
|
mExistingAliases = aliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> getExistingAliases() {
|
List<String> getExistingAliases() {
|
||||||
return mExistingAliases;
|
return mExistingAliases;
|
||||||
}
|
}
|
||||||
@@ -467,7 +491,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
|
|
||||||
updatePageOnChange(ExportWizardPage.DATA_KEY);
|
updatePageOnChange(ExportWizardPage.DATA_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getKeyAlias() {
|
String getKeyAlias() {
|
||||||
return mKeyAlias;
|
return mKeyAlias;
|
||||||
}
|
}
|
||||||
@@ -479,7 +503,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
|
|
||||||
updatePageOnChange(ExportWizardPage.DATA_KEY);
|
updatePageOnChange(ExportWizardPage.DATA_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getKeyPassword() {
|
String getKeyPassword() {
|
||||||
return mKeyPassword;
|
return mKeyPassword;
|
||||||
}
|
}
|
||||||
@@ -488,7 +512,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
mValidity = validity;
|
mValidity = validity;
|
||||||
updatePageOnChange(ExportWizardPage.DATA_KEY);
|
updatePageOnChange(ExportWizardPage.DATA_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getValidity() {
|
int getValidity() {
|
||||||
return mValidity;
|
return mValidity;
|
||||||
}
|
}
|
||||||
@@ -497,7 +521,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
mDName = dName;
|
mDName = dName;
|
||||||
updatePageOnChange(ExportWizardPage.DATA_KEY);
|
updatePageOnChange(ExportWizardPage.DATA_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getDName() {
|
String getDName() {
|
||||||
return mDName;
|
return mDName;
|
||||||
}
|
}
|
||||||
@@ -522,7 +546,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
page.projectDataChanged(changeMask);
|
page.projectDataChanged(changeMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayError(String... messages) {
|
private void displayError(String... messages) {
|
||||||
String message = null;
|
String message = null;
|
||||||
if (messages.length == 1) {
|
if (messages.length == 1) {
|
||||||
@@ -533,20 +557,125 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
sb.append(messages[i]);
|
sb.append(messages[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
message = sb.toString();
|
message = sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
AdtPlugin.displayError("Export Wizard", message);
|
AdtPlugin.displayError("Export Wizard", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayError(Exception e) {
|
private void displayError(Throwable t) {
|
||||||
String message = getExceptionMessage(e);
|
String message = getExceptionMessage(t);
|
||||||
displayError(message);
|
displayError(message);
|
||||||
|
|
||||||
AdtPlugin.log(e, "Export Wizard Error");
|
AdtPlugin.log(t, "Export Wizard Error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes zipalign
|
||||||
|
* @param zipAlignPath location of the zipalign too
|
||||||
|
* @param source file to zipalign
|
||||||
|
* @param destination where to write the resulting file
|
||||||
|
* @return null if success, the error otherwise
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private String zipAlign(String zipAlignPath, File source, File destination) throws IOException {
|
||||||
|
// command line: zipaling -f 4 tmp destination
|
||||||
|
String[] command = new String[5];
|
||||||
|
command[0] = zipAlignPath;
|
||||||
|
command[1] = "-f"; //$NON-NLS-1$
|
||||||
|
command[2] = "4"; //$NON-NLS-1$
|
||||||
|
command[3] = source.getAbsolutePath();
|
||||||
|
command[4] = destination.getAbsolutePath();
|
||||||
|
|
||||||
|
Process process = Runtime.getRuntime().exec(command);
|
||||||
|
ArrayList<String> output = new ArrayList<String>();
|
||||||
|
try {
|
||||||
|
if (grabProcessOutput(process, output) != 0) {
|
||||||
|
// build a single message from the array list
|
||||||
|
StringBuilder sb = new StringBuilder("Error while running zipalign:");
|
||||||
|
for (String msg : output) {
|
||||||
|
sb.append('\n');
|
||||||
|
sb.append(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// ?
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the stderr output of a process and return when the process is done.
|
||||||
|
* @param process The process to get the ouput from
|
||||||
|
* @param results The array to store the stderr output
|
||||||
|
* @return the process return code.
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
|
private final int grabProcessOutput(final Process process,
|
||||||
|
final ArrayList<String> results)
|
||||||
|
throws InterruptedException {
|
||||||
|
// Due to the limited buffer size on windows for the standard io (stderr, stdout), we
|
||||||
|
// *need* to read both stdout and stderr all the time. If we don't and a process output
|
||||||
|
// a large amount, this could deadlock the process.
|
||||||
|
|
||||||
|
// read the lines as they come. if null is returned, it's
|
||||||
|
// because the process finished
|
||||||
|
new Thread("") { //$NON-NLS-1$
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// create a buffer to read the stderr output
|
||||||
|
InputStreamReader is = new InputStreamReader(process.getErrorStream());
|
||||||
|
BufferedReader errReader = new BufferedReader(is);
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
String line = errReader.readLine();
|
||||||
|
if (line != null) {
|
||||||
|
results.add(line);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// do nothing.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
|
||||||
|
new Thread("") { //$NON-NLS-1$
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
InputStreamReader is = new InputStreamReader(process.getInputStream());
|
||||||
|
BufferedReader outReader = new BufferedReader(is);
|
||||||
|
|
||||||
|
IProject project = getProject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
String line = outReader.readLine();
|
||||||
|
if (line != null) {
|
||||||
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE,
|
||||||
|
project, line);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// do nothing.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}.start();
|
||||||
|
|
||||||
|
// get the return code from the process
|
||||||
|
return process.waitFor();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link Throwable#getMessage()}. If the {@link Throwable#getMessage()} returns
|
* Returns the {@link Throwable#getMessage()}. If the {@link Throwable#getMessage()} returns
|
||||||
* <code>null</code>, the method is called again on the cause of the Throwable object.
|
* <code>null</code>, the method is called again on the cause of the Throwable object.
|
||||||
@@ -556,15 +685,13 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
|||||||
static String getExceptionMessage(Throwable t) {
|
static String getExceptionMessage(Throwable t) {
|
||||||
String message = t.getMessage();
|
String message = t.getMessage();
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
Throwable cause = t.getCause();
|
// no error info? get the stack call to display it
|
||||||
if (cause != null) {
|
// At least that'll give us a better bug report.
|
||||||
return getExceptionMessage(cause);
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
}
|
t.printStackTrace(new PrintStream(baos));
|
||||||
|
message = baos.toString();
|
||||||
// no more cause and still no message. display the first exception.
|
|
||||||
return t.getClass().getCanonicalName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ public final class SdkConstants {
|
|||||||
public final static String FN_EMULATOR = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
public final static String FN_EMULATOR = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
||||||
"emulator.exe" : "emulator"; //$NON-NLS-1$ //$NON-NLS-2$
|
"emulator.exe" : "emulator"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
/** zipalign executable (with extension for the current OS) */
|
||||||
|
public final static String FN_ZIPALIGN = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
||||||
|
"zipalign.exe" : "zipalign"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
/* Folder Names for Android Projects . */
|
/* Folder Names for Android Projects . */
|
||||||
|
|
||||||
/** Resources folder name, i.e. "res". */
|
/** Resources folder name, i.e. "res". */
|
||||||
|
|||||||
Reference in New Issue
Block a user