diff options
64 files changed, 1481 insertions, 244 deletions
diff --git a/build/tools.atree b/build/tools.atree index f1d46d478..8fc262c1f 100644 --- a/build/tools.atree +++ b/build/tools.atree @@ -65,7 +65,8 @@ bin/lint tools/lint # sdk.git Ant templates for project build files sdk/templates/build.template tools/lib/build.template -sdk/files/proguard.cfg tools/lib/proguard.cfg +sdk/files/proguard-project.txt tools/lib/proguard-project.txt +sdk/files/proguard-android.txt tools/proguard/proguard-android.txt # Ant Build Rules sdk/files/ant tools/ant @@ -145,7 +146,9 @@ prebuilts/tools/common/proguard/proguard4.7/bin/retrace.sh tools/proguard/bi prebuilts/tools/common/proguard/proguard4.7/src/proguard/ant/task.properties tools/proguard/ant/task.properties # SDK Controller -sdk/apps/SdkController tools/apps/SdkController +#sdk/apps/SdkController tools/apps/SdkController +sdk/apps/SdkController/SdkControllerLib tools/apps/SdkController/SdkControllerLib +sdk/apps/SdkController/SdkControllerSensor tools/apps/SdkController/SdkControllerSensor # tools specific support jar framework/annotations.jar tools/support/annotations.jar diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java index 258493367..f6fe09f19 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java @@ -20,7 +20,9 @@ import com.android.AndroidConstants; import com.android.ide.common.log.ILogger; import com.android.ide.common.resources.ResourceFile; import com.android.ide.common.sdk.LoadStatus; +import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler.Solution; import com.android.ide.eclipse.adt.internal.VersionCheck; +import com.android.ide.eclipse.adt.internal.actions.SdkManagerAction; import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; import com.android.ide.eclipse.adt.internal.editors.IconFactory; import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor; @@ -42,6 +44,7 @@ import com.android.resources.ResourceFolderType; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; +import org.eclipse.core.commands.Command; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.resources.IProject; @@ -59,8 +62,10 @@ import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.util.IPropertyChangeListener; @@ -78,11 +83,14 @@ import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.browser.IWebBrowser; import org.eclipse.ui.browser.IWorkbenchBrowserSupport; +import org.eclipse.ui.commands.ICommandService; import org.eclipse.ui.console.ConsolePlugin; import org.eclipse.ui.console.IConsole; import org.eclipse.ui.console.IConsoleConstants; import org.eclipse.ui.console.MessageConsole; import org.eclipse.ui.console.MessageConsoleStream; +import org.eclipse.ui.dialogs.PreferencesUtil; +import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.ui.texteditor.AbstractTextEditor; @@ -162,15 +170,23 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger { * checkSdkLocationAndId. */ public static abstract class CheckSdkErrorHandler { + + public enum Solution { + NONE, + OPEN_SDK_MANAGER, + OPEN_ANDROID_PREFS, + OPEN_P2_UPDATE + } + /** Handle an error message during sdk location check. Returns whatever * checkSdkLocationAndId() should returns. */ - public abstract boolean handleError(String message); + public abstract boolean handleError(Solution solution, String message); /** Handle a warning message during sdk location check. Returns whatever * checkSdkLocationAndId() should returns. */ - public abstract boolean handleWarning(String message); + public abstract boolean handleWarning(Solution solution, String message); } /** @@ -1064,17 +1080,133 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger { } return checkSdkLocationAndId(sdkLocation, new CheckSdkErrorHandler() { + private String mTitle = "Android SDK Verification"; @Override - public boolean handleError(String message) { - AdtPlugin.displayError("Android SDK Verification", message); + public boolean handleError(Solution solution, String message) { + displayMessage(solution, message, MessageDialog.ERROR); return false; } @Override - public boolean handleWarning(String message) { - AdtPlugin.displayWarning("Android SDK Verification", message); + public boolean handleWarning(Solution solution, String message) { + displayMessage(solution, message, MessageDialog.WARNING); return true; } + + private void displayMessage( + final Solution solution, + final String message, + final int dialogImageType) { + final Display disp = getDisplay(); + disp.asyncExec(new Runnable() { + @Override + public void run() { + Shell shell = disp.getActiveShell(); + if (shell == null) { + return; + } + + String customLabel = null; + switch(solution) { + case OPEN_ANDROID_PREFS: + customLabel = "Open Preferences"; + break; + case OPEN_P2_UPDATE: + customLabel = "Check for Updates"; + break; + case OPEN_SDK_MANAGER: + customLabel = "Open SDK Manager"; + break; + } + + String btnLabels[] = new String[customLabel == null ? 1 : 2]; + btnLabels[0] = customLabel; + btnLabels[btnLabels.length - 1] = IDialogConstants.CLOSE_LABEL; + + MessageDialog dialog = new MessageDialog( + shell, // parent + mTitle, + null, // dialogTitleImage + message, + dialogImageType, + btnLabels, + btnLabels.length - 1); + int index = dialog.open(); + + if (customLabel != null && index == 0) { + switch(solution) { + case OPEN_ANDROID_PREFS: + openAndroidPrefs(); + break; + case OPEN_P2_UPDATE: + openP2Update(); + break; + case OPEN_SDK_MANAGER: + openSdkManager(); + break; + } + } + } + }); + } + + private void openSdkManager() { + // Windows only: open the standalone external SDK Manager since we know + // that ADT on Windows is bound to be locking some SDK folders. + if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) { + if (SdkManagerAction.openExternalSdkManager()) { + return; + } + } + + // Otherwise open the regular SDK Manager bundled within ADT + if (!SdkManagerAction.openAdtSdkManager()) { + // We failed because the SDK location is undefined. In this case + // let's open the preferences instead. + openAndroidPrefs(); + } + } + + private void openP2Update() { + Display disp = getDisplay(); + if (disp == null) { + return; + } + disp.asyncExec(new Runnable() { + @Override + public void run() { + String cmdId = "org.eclipse.equinox.p2.ui.sdk.update"; //$NON-NLS-1$ + IWorkbench wb = PlatformUI.getWorkbench(); + if (wb == null) { + return; + } + + ICommandService cs = (ICommandService) wb.getService(ICommandService.class); + IHandlerService is = (IHandlerService) wb.getService(IHandlerService.class); + if (cs == null || is == null) { + return; + } + + Command cmd = cs.getCommand(cmdId); + if (cmd != null && cmd.isDefined()) { + try { + is.executeCommand(cmdId, null/*event*/); + } catch (Exception ignore) { + AdtPlugin.log(ignore, "Failed to execute command %s", cmdId); + } + } + } + }); + } + + private void openAndroidPrefs() { + PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn( + getDisplay().getActiveShell(), + "com.android.ide.eclipse.preferences.main", //$NON-NLS-1$ preferencePageId + null, // displayedIds + null); // data + dialog.open(); + } }); } @@ -1093,6 +1225,7 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger { File osSdkFolder = new File(osSdkLocation); if (osSdkFolder.isDirectory() == false) { return errorHandler.handleError( + Solution.OPEN_ANDROID_PREFS, String.format(Messages.Could_Not_Find_Folder, osSdkLocation)); } @@ -1100,6 +1233,7 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger { File toolsFolder = new File(osTools); if (toolsFolder.isDirectory() == false) { return errorHandler.handleError( + Solution.OPEN_ANDROID_PREFS, String.format(Messages.Could_Not_Find_Folder_In_SDK, SdkConstants.FD_TOOLS, osSdkLocation)); } @@ -1113,13 +1247,17 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger { // check that we have both the tools component and the platform-tools component. String platformTools = osSdkLocation + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER; if (checkFolder(platformTools) == false) { - return errorHandler.handleWarning("SDK Platform Tools component is missing!\n" + + return errorHandler.handleWarning( + Solution.OPEN_SDK_MANAGER, + "SDK Platform Tools component is missing!\n" + "Please use the SDK Manager to install it."); } String tools = osSdkLocation + SdkConstants.OS_SDK_TOOLS_FOLDER; if (checkFolder(tools) == false) { - return errorHandler.handleError("SDK Tools component is missing!\n" + + return errorHandler.handleError( + Solution.OPEN_SDK_MANAGER, + "SDK Tools component is missing!\n" + "Please use the SDK Manager to install it."); } @@ -1131,7 +1269,9 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger { }; for (String file : filesToCheck) { if (checkFile(file) == false) { - return errorHandler.handleError(String.format(Messages.Could_Not_Find, file)); + return errorHandler.handleError( + Solution.OPEN_ANDROID_PREFS, + String.format(Messages.Could_Not_Find, file)); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java index 9055b2973..b468c5e2d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java @@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.internal; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler; +import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler.Solution; import com.android.ide.eclipse.adt.Messages; import com.android.sdklib.SdkConstants; import com.android.sdklib.repository.PkgProps; @@ -103,7 +104,9 @@ public final class VersionCheck { // Failed to get the min plugin version number? if (minMajorVersion == -1 || minMinorVersion == -1 || minMicroVersion ==-1) { - return errorHandler.handleWarning(Messages.VersionCheck_Plugin_Version_Failed); + return errorHandler.handleWarning( + Solution.OPEN_SDK_MANAGER, + Messages.VersionCheck_Plugin_Version_Failed); } // test the plugin number @@ -126,6 +129,7 @@ public final class VersionCheck { if (valid == false) { return errorHandler.handleError( + Solution.OPEN_P2_UPDATE, String.format(Messages.VersionCheck_Plugin_Too_Old, minMajorVersion, minMinorVersion, minMicroVersion, versionString)); } @@ -163,6 +167,7 @@ public final class VersionCheck { // this is a warning only as we need to parse the SDK to allow updating // of the tools! return errorHandler.handleWarning( + Solution.OPEN_SDK_MANAGER, String.format(Messages.VersionCheck_Tools_Too_Old, MIN_TOOLS_REV, toolsRevision)); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java index 970bc473c..f8a080a29 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java @@ -22,6 +22,7 @@ import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.sdklib.SdkConstants; import com.android.sdklib.util.GrabProcessOutput; import com.android.sdklib.util.GrabProcessOutput.IProcessOutput; +import com.android.sdklib.util.GrabProcessOutput.Wait; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; @@ -175,7 +176,7 @@ public class DexDumpAction implements IObjectActionDelegate { int err = GrabProcessOutput.grabProcessOutput( process, - true /*waitForReaders*/, + Wait.WAIT_FOR_READERS, new IProcessOutput() { @Override public void out(String line) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java index ddf180fa8..0ff50b55e 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java @@ -20,6 +20,11 @@ import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.build.DexWrapper;
import com.android.ide.eclipse.adt.internal.sdk.AdtConsoleSdkLog;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.sdklib.SdkConstants;
+import com.android.sdklib.io.FileOp;
+import com.android.sdklib.util.GrabProcessOutput;
+import com.android.sdklib.util.GrabProcessOutput.IProcessOutput;
+import com.android.sdklib.util.GrabProcessOutput.Wait;
import com.android.sdkuilib.repository.ISdkChangeListener;
import com.android.sdkuilib.repository.SdkUpdaterWindow;
import com.android.sdkuilib.repository.SdkUpdaterWindow.SdkInvocationContext;
@@ -31,6 +36,8 @@ import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import java.io.File;
+
/**
* Delegate for the toolbar/menu action "Android SDK Manager".
* It displays the Android SDK Manager.
@@ -49,93 +56,161 @@ public class SdkManagerAction implements IWorkbenchWindowActionDelegate, IObject @Override
public void run(IAction action) {
- final Sdk sdk = Sdk.getCurrent();
- if (sdk != null) {
+ if (!openAdtSdkManager()) {
+ AdtPlugin.displayError(
+ "Android SDK",
+ "Location of the Android SDK has not been setup in the preferences.");
+ }
+ }
- // Runs the updater window, directing only warning/errors logs to the ADT console
- // (normal log is just dropped, which is fine since the SDK Manager has its own
- // log window now.)
+ /**
+ * Opens the SDK Manager as an external application.
+ * This call is asynchronous, it doesn't wait for the manager to be closed.
+ *
+ * @return True if the application was found and executed. False if it could not
+ * be located or could not be launched.
+ */
+ public static boolean openExternalSdkManager() {
+ final Sdk sdk = Sdk.getCurrent();
+ if (sdk == null) {
+ return false;
+ }
- SdkUpdaterWindow window = new SdkUpdaterWindow(
- AdtPlugin.getDisplay().getActiveShell(),
- new AdtConsoleSdkLog() {
- @Override
- public void printf(String msgFormat, Object... args) {
- // Do not show non-error/warning log in Eclipse.
- };
- },
- sdk.getSdkLocation(),
- SdkInvocationContext.IDE);
-
- ISdkChangeListener listener = new ISdkChangeListener() {
- @Override
- public void onSdkLoaded() {
- // Ignore initial load of the SDK.
- }
+ File androidBat = FileOp.append(
+ sdk.getSdkLocation(),
+ SdkConstants.FD_TOOLS,
+ SdkConstants.androidCmdName());
- /**
- * Unload all we can from the SDK before new packages are installed.
- * Typically we need to get rid of references to dx from platform-tools
- * and to any platform resource data.
- * <p/>
- * {@inheritDoc}
- */
- @Override
- public void preInstallHook() {
-
- // TODO we need to unload as much of as SDK as possible. Otherwise
- // on Windows we end up with Eclipse locking some files and we can't
- // replace them.
- //
- // At this point, we know what the user wants to install so it would be
- // possible to pass in flags to know what needs to be unloaded. Typically
- // we need to:
- // - unload dex if platform-tools is going to be updated. There's a vague
- // attempt below at removing any references to dex and GCing. Seems
- // to do the trick.
- // - unload any target that is going to be updated since it may have
- // resource data used by a current layout editor (e.g. data/*.ttf
- // and various data/res/*.xml).
- //
- // Most important we need to make sure there isn't a build going on
- // and if there is one, either abort it or wait for it to complete and
- // then we want to make sure we don't get any attempt to use the SDK
- // before the postInstallHook is called.
-
- if (sdk != null) {
- sdk.unloadTargetData(true /*preventReload*/);
-
- DexWrapper dx = sdk.getDexWrapper();
- dx.unload();
- }
- }
+ if (!androidBat.exists()) {
+ return false;
+ }
- /**
- * Nothing to do. We'll reparse the SDK later in onSdkReload.
- * <p/>
- * {@inheritDoc}
- */
- @Override
- public void postInstallHook() {
- }
+ try {
+ final AdtConsoleSdkLog logger = new AdtConsoleSdkLog();
- /**
- * Reparse the SDK in case anything was add/removed.
- * <p/>
- * {@inheritDoc}
- */
- @Override
- public void onSdkReload() {
- AdtPlugin.getDefault().reparseSdk();
- }
+ String command[] = new String[] {
+ androidBat.getAbsolutePath(),
+ "sdk" //$NON-NLS-1$
};
+ Process process = Runtime.getRuntime().exec(command);
+ GrabProcessOutput.grabProcessOutput(
+ process,
+ Wait.ASYNC,
+ new IProcessOutput() {
+ @Override
+ public void out(String line) {
+ // Ignore stdout
+ }
- window.addListener(listener);
- window.open();
- } else {
- AdtPlugin.displayError("Android SDK",
- "Location of the Android SDK has not been setup in the preferences.");
+ @Override
+ public void err(String line) {
+ if (line != null) {
+ logger.printf("[SDK Manager] %s", line);
+ }
+ }
+ });
+ } catch (Exception ignore) {
}
+
+ return true;
+ }
+
+ /**
+ * Opens the SDK Manager bundled within ADT.
+ * The call is blocking and does not return till the SD Manager window is closed.
+ *
+ * @return True if the SDK location is known and the SDK Manager was started.
+ * False if the SDK location is not set and we can't open a SDK Manager to
+ * manage files in an unknown location.
+ */
+ public static boolean openAdtSdkManager() {
+ final Sdk sdk = Sdk.getCurrent();
+ if (sdk == null) {
+ return false;
+ }
+
+ // Runs the updater window, directing only warning/errors logs to the ADT console
+ // (normal log is just dropped, which is fine since the SDK Manager has its own
+ // log window now.)
+
+ SdkUpdaterWindow window = new SdkUpdaterWindow(
+ AdtPlugin.getDisplay().getActiveShell(),
+ new AdtConsoleSdkLog() {
+ @Override
+ public void printf(String msgFormat, Object... args) {
+ // Do not show non-error/warning log in Eclipse.
+ };
+ },
+ sdk.getSdkLocation(),
+ SdkInvocationContext.IDE);
+
+ ISdkChangeListener listener = new ISdkChangeListener() {
+ @Override
+ public void onSdkLoaded() {
+ // Ignore initial load of the SDK.
+ }
+
+ /**
+ * Unload all we can from the SDK before new packages are installed.
+ * Typically we need to get rid of references to dx from platform-tools
+ * and to any platform resource data.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public void preInstallHook() {
+
+ // TODO we need to unload as much of as SDK as possible. Otherwise
+ // on Windows we end up with Eclipse locking some files and we can't
+ // replace them.
+ //
+ // At this point, we know what the user wants to install so it would be
+ // possible to pass in flags to know what needs to be unloaded. Typically
+ // we need to:
+ // - unload dex if platform-tools is going to be updated. There's a vague
+ // attempt below at removing any references to dex and GCing. Seems
+ // to do the trick.
+ // - unload any target that is going to be updated since it may have
+ // resource data used by a current layout editor (e.g. data/*.ttf
+ // and various data/res/*.xml).
+ //
+ // Most important we need to make sure there isn't a build going on
+ // and if there is one, either abort it or wait for it to complete and
+ // then we want to make sure we don't get any attempt to use the SDK
+ // before the postInstallHook is called.
+
+ if (sdk != null) {
+ sdk.unloadTargetData(true /*preventReload*/);
+
+ DexWrapper dx = sdk.getDexWrapper();
+ dx.unload();
+ }
+ }
+
+ /**
+ * Nothing to do. We'll reparse the SDK later in onSdkReload.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public void postInstallHook() {
+ }
+
+ /**
+ * Reparse the SDK in case anything was add/removed.
+ * <p/>
+ * {@inheritDoc}
+ */
+ @Override
+ public void onSdkReload() {
+ AdtPlugin.getDefault().reparseSdk();
+ }
+ };
+
+ window.addListener(listener);
+ window.open();
+
+ return true;
}
@Override
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java index 3ae9f6439..7536c2fca 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java @@ -41,6 +41,7 @@ import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException; import com.android.sdklib.internal.build.SignedJarBuilder; import com.android.sdklib.util.GrabProcessOutput; import com.android.sdklib.util.GrabProcessOutput.IProcessOutput; +import com.android.sdklib.util.GrabProcessOutput.Wait; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; @@ -512,7 +513,7 @@ public class BuildHelper { return compiledPaths; } - public void runProguard(File proguardConfig, File inputJar, String[] jarFiles, + public void runProguard(List<File> proguardConfigs, File inputJar, String[] jarFiles, File obfuscatedJar, File logOutput) throws ProguardResultException, ProguardExecException, IOException { IAndroidTarget target = Sdk.getCurrent().getTarget(mProject); @@ -521,7 +522,10 @@ public class BuildHelper { List<String> command = new ArrayList<String>(); command.add(AdtPlugin.getOsAbsoluteProguard()); - command.add("@" + quotePath(proguardConfig.getAbsolutePath())); //$NON-NLS-1$ + for (File configFile : proguardConfigs) { + command.add("-include"); //$NON-NLS-1$ + command.add(quotePath(configFile.getAbsolutePath())); + } command.add("-injars"); //$NON-NLS-1$ StringBuilder sb = new StringBuilder(quotePath(inputJar.getAbsolutePath())); @@ -1196,7 +1200,7 @@ public class BuildHelper { return GrabProcessOutput.grabProcessOutput( process, - false /*waitForReaders*/, + Wait.WAIT_FOR_PROCESS, new IProcessOutput() { @SuppressWarnings("unused") diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AndroidPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AndroidPreferencePage.java index 426149e65..eff883b4b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AndroidPreferencePage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AndroidPreferencePage.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.preferences; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.ide.eclipse.adt.internal.sdk.Sdk.ITargetChangeListener; import com.android.sdklib.IAndroidTarget; @@ -140,13 +141,17 @@ public class AndroidPreferencePage extends FieldEditorPreferencePage implements boolean ok = AdtPlugin.getDefault().checkSdkLocationAndId(fileName, new AdtPlugin.CheckSdkErrorHandler() { @Override - public boolean handleError(String message) { + public boolean handleError( + CheckSdkErrorHandler.Solution solution, + String message) { setErrorMessage(message.replaceAll("\n", " ")); //$NON-NLS-1$ //$NON-NLS-2$ return false; // Apply/OK must be disabled } @Override - public boolean handleWarning(String message) { + public boolean handleWarning( + CheckSdkErrorHandler.Solution solution, + String message) { showMessage(message.replaceAll("\n", " ")); //$NON-NLS-1$ //$NON-NLS-2$ return true; // Apply/OK must be enabled } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java index 1e5171cb1..93fe43d68 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.project; +import static com.android.sdklib.internal.project.ProjectProperties.PROPERTY_SDK; + import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtUtils; @@ -25,6 +27,7 @@ import com.android.ide.eclipse.adt.internal.build.DexException; import com.android.ide.eclipse.adt.internal.build.NativeLibInJarException; import com.android.ide.eclipse.adt.internal.build.ProguardExecException; import com.android.ide.eclipse.adt.internal.build.ProguardResultException; +import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; import com.android.ide.eclipse.adt.internal.sdk.ProjectState; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.ide.eclipse.adt.io.IFileWrapper; @@ -58,6 +61,7 @@ import java.io.IOException; import java.io.OutputStream; import java.security.PrivateKey; import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; @@ -66,8 +70,10 @@ import java.util.jar.JarOutputStream; * Export helper to export release version of APKs. */ public final class ExportHelper { - - private final static String TEMP_PREFIX = "android_"; //$NON-NLS-1$ + private static final String HOME_PROPERTY = "user.home"; //$NON-NLS-1$ + private static final String HOME_PROPERTY_REF = "${" + HOME_PROPERTY + '}'; //$NON-NLS-1$ + private static final String SDK_PROPERTY_REF = "${" + PROPERTY_SDK + '}'; //$NON-NLS-1$ + private final static String TEMP_PREFIX = "android_"; //$NON-NLS-1$ /** * Exports a release version of the application created by the given project. @@ -75,7 +81,8 @@ public final class ExportHelper { * @param outputFile the file to write * @param key the key to used for signing. Can be null. * @param certificate the certificate used for signing. Can be null. - * @param monitor + * @param monitor progress monitor + * @throws CoreException if an error occurs */ public static void exportReleaseApk(IProject project, File outputFile, PrivateKey key, X509Certificate certificate, IProgressMonitor monitor) throws CoreException { @@ -151,13 +158,46 @@ public final class ExportHelper { ProjectProperties.PROPERTY_PROGUARD_CONFIG); boolean runProguard = false; - File proguardConfigFile = null; + List<File> proguardConfigFiles = null; if (proguardConfig != null && proguardConfig.length() > 0) { - proguardConfigFile = new File(proguardConfig); - if (proguardConfigFile.isAbsolute() == false) { - proguardConfigFile = new File(project.getLocation().toFile(), proguardConfig); + // Be tolerant with respect to file and path separators just like + // Ant is. Allow "/" in the property file to mean whatever the file + // separator character is: + if (File.separatorChar != '/' && proguardConfig.indexOf('/') != -1) { + proguardConfig = proguardConfig.replace('/', File.separatorChar); + } + // Also split path: no need to convert to File.pathSeparator because we'll + // be splitting the path ourselves right here, so just ensure that both + // ':' and ';' work: + if (proguardConfig.indexOf(';') != -1) { + proguardConfig = proguardConfig.replace(';', ':'); + } + String[] paths = proguardConfig.split(":"); //$NON-NLS-1$ + + for (String path : paths) { + if (path.startsWith(SDK_PROPERTY_REF)) { + path = AdtPrefs.getPrefs().getOsSdkFolder() + + path.substring(SDK_PROPERTY_REF.length()); + } else if (path.startsWith(HOME_PROPERTY_REF)) { + path = System.getProperty(HOME_PROPERTY) + + path.substring(HOME_PROPERTY_REF.length()); + } + File proguardConfigFile = new File(path); + if (proguardConfigFile.isAbsolute() == false) { + proguardConfigFile = new File(project.getLocation().toFile(), path); + } + if (proguardConfigFile.isFile()) { + if (proguardConfigFiles == null) { + proguardConfigFiles = new ArrayList<File>(); + } + proguardConfigFiles.add(proguardConfigFile); + runProguard = true; + } else { + throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, + "Invalid proguard configuration file path " + proguardConfigFile + + " does not exist or is not a regular file", null)); + } } - runProguard = proguardConfigFile.isFile(); } String[] dxInput; @@ -188,7 +228,7 @@ public final class ExportHelper { obfuscatedJar.deleteOnExit(); // run proguard - helper.runProguard(proguardConfigFile, inputJar, jarFiles, obfuscatedJar, + helper.runProguard(proguardConfigFiles, inputJar, jarFiles, obfuscatedJar, new File(project.getLocation().toFile(), SdkConstants.FD_PROGUARD)); // dx input is proguard's output diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/DynamicIdMap.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/DynamicIdMap.java new file mode 100644 index 000000000..702f8f62a --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/DynamicIdMap.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.adt.internal.resources.manager; + +import com.android.resources.ResourceType; +import com.android.sdklib.util.SparseArray; +import com.android.util.Pair; + +import java.util.HashMap; +import java.util.Map; + +public class DynamicIdMap { + + private final Map<Pair<ResourceType, String>, Integer> mDynamicIds = new HashMap<Pair<ResourceType, String>, Integer>(); + private final SparseArray<Pair<ResourceType, String>> mRevDynamicIds = new SparseArray<Pair<ResourceType, String>>(); + private int mDynamicSeed; + + public DynamicIdMap(int seed) { + mDynamicSeed = seed; + } + + public void reset(int seed) { + mDynamicIds.clear(); + mRevDynamicIds.clear(); + mDynamicSeed = seed; + } + + /** + * Returns a dynamic integer for the given resource type/name, creating it if it doesn't + * already exist. + * + * @param type the type of the resource + * @param name the name of the resource + * @return an integer. + */ + public Integer getId(ResourceType type, String name) { + return getId(Pair.of(type, name)); + } + + /** + * Returns a dynamic integer for the given resource type/name, creating it if it doesn't + * already exist. + * + * @param resource the type/name of the resource + * @return an integer. + */ + public Integer getId(Pair<ResourceType, String> resource) { + Integer value = mDynamicIds.get(resource); + if (value == null) { + value = Integer.valueOf(++mDynamicSeed); + mDynamicIds.put(resource, value); + mRevDynamicIds.put(value, resource); + } + + return value; + } + + public Pair<ResourceType, String> resolveId(int id) { + return mRevDynamicIds.get(id); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java index 780d72f20..e6e3acb18 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java @@ -32,7 +32,6 @@ import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import java.util.EnumMap; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -61,14 +60,7 @@ public class ProjectResources extends ResourceRepository { /** Map of (int[], name) for styleable resources coming from R.java */ private Map<IntArrayWrapper, String> mStyleableValueToNameMap; - /** - * This list is used by {@link #getResourceId(String, String)} when the resource - * query is an ID that doesn't exist (for example for ID automatically generated in - * layout files that are not saved yet). - */ - private final Map<String, Integer> mDynamicIds = new HashMap<String, Integer>(); - private final Map<Integer, String> mRevDynamicIds = new HashMap<Integer, String>(); - private int mDynamicSeed = DYNAMIC_ID_SEED_START; + private final DynamicIdMap mDynamicIdMap = new DynamicIdMap(DYNAMIC_ID_SEED_START); private final IProject mProject; @@ -182,9 +174,8 @@ public class ProjectResources extends ResourceRepository { } if (result == null) { - String name = mRevDynamicIds.get(id); - if (name != null) { - result = Pair.of(ResourceType.ID, name); + synchronized (mDynamicIdMap) { + result = mDynamicIdMap.resolveId(id); } } @@ -218,8 +209,10 @@ public class ProjectResources extends ResourceRepository { } } - if (result == null && ResourceType.ID == type) { - result = getDynamicId(name); + if (result == null) { + synchronized (mDynamicIdMap) { + result = mDynamicIdMap.getId(type, name); + } } return result; @@ -233,10 +226,8 @@ public class ProjectResources extends ResourceRepository { * change. */ public void resetDynamicIds() { - synchronized (mDynamicIds) { - mDynamicIds.clear(); - mRevDynamicIds.clear(); - mDynamicSeed = DYNAMIC_ID_SEED_START; + synchronized (mDynamicIdMap) { + mDynamicIdMap.reset(DYNAMIC_ID_SEED_START); } } @@ -246,28 +237,6 @@ public class ProjectResources extends ResourceRepository { } /** - * Returns a dynamic integer for the given resource name, creating it if it doesn't - * already exist. - * - * @param name the name of the resource - * @return an integer. - * - * @see #resetDynamicIds() - */ - private Integer getDynamicId(String name) { - synchronized (mDynamicIds) { - Integer value = mDynamicIds.get(name); - if (value == null) { - value = Integer.valueOf(++mDynamicSeed); - mDynamicIds.put(name, value); - mRevDynamicIds.put(value, name); - } - - return value; - } - } - - /** * Sets compiled resource information. * * @param resIdValueToNameMap a map of compiled resource id to resource name. @@ -283,5 +252,7 @@ public class ProjectResources extends ResourceRepository { mResourceValueMap = resourceValueMap; mResIdValueToNameMap = resIdValueToNameMap; mStyleableValueToNameMap = styleableValueMap; + + resetDynamicIds(); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java index eb4c1e908..ecc588f7c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java @@ -167,6 +167,19 @@ public final class ResourceManager { * as a place to stash errors encountered */ public void processDelta(IResourceDelta delta, IdeScanningContext context) { + doProcessDelta(delta, context); + + context.getRepository().postUpdateCleanUp(); + } + + /** + * Update the resource repository with a delta + * + * @param delta the resource changed delta to process. + * @param context a context object with state for the current update, such + * as a place to stash errors encountered + */ + private void doProcessDelta(IResourceDelta delta, IdeScanningContext context) { // Skip over deltas that don't fit our mask int mask = IResourceDelta.ADDED | IResourceDelta.REMOVED | IResourceDelta.CHANGED; int kind = delta.getKind(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/AdtStartup.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/AdtStartup.java index 2b3e2c272..96add7117 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/AdtStartup.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/AdtStartup.java @@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.welcome; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; import com.android.sdkstats.DdmsPreferenceStore; import com.android.sdkstats.SdkStatsService; @@ -83,12 +84,16 @@ public class AdtStartup implements IStartup { boolean ok = AdtPlugin.getDefault().checkSdkLocationAndId(osSdkPath, new AdtPlugin.CheckSdkErrorHandler() { @Override - public boolean handleError(String message) { + public boolean handleError( + CheckSdkErrorHandler.Solution solution, + String message) { return false; } @Override - public boolean handleWarning(String message) { + public boolean handleWarning( + CheckSdkErrorHandler.Solution solution, + String message) { return true; } }); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/WelcomeWizardPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/WelcomeWizardPage.java index d41843219..4e580fefb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/WelcomeWizardPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/WelcomeWizardPage.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.welcome; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.wizard.WizardPage; @@ -262,14 +263,18 @@ public class WelcomeWizardPage extends WizardPage implements ModifyListener, Sel AdtPlugin.getDefault().checkSdkLocationAndId(path, new AdtPlugin.CheckSdkErrorHandler() { @Override - public boolean handleError(String message) { + public boolean handleError( + CheckSdkErrorHandler.Solution solution, + String message) { message = message.replaceAll("\n", " "); //$NON-NLS-1$ //$NON-NLS-2$ errorReference.set(message); return false; // Apply/OK must be disabled } @Override - public boolean handleWarning(String message) { + public boolean handleWarning( + CheckSdkErrorHandler.Solution solution, + String message) { message = message.replaceAll("\n", " "); //$NON-NLS-1$ //$NON-NLS-2$ warningReference.set(message); return true; // Apply/OK must be enabled diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java index 4ce8230ec..8fcf90289 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java @@ -24,6 +24,7 @@ import com.android.sdklib.internal.build.DebugKeyProvider.IKeyGenOutput; import com.android.sdklib.internal.build.KeystoreHelper; import com.android.sdklib.util.GrabProcessOutput; import com.android.sdklib.util.GrabProcessOutput.IProcessOutput; +import com.android.sdklib.util.GrabProcessOutput.Wait; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; @@ -543,7 +544,7 @@ public final class ExportWizard extends Wizard implements IExportWizard { int status = GrabProcessOutput.grabProcessOutput( process, - true /*waitForReaders*/, + Wait.WAIT_FOR_READERS, new IProcessOutput() { @Override public void out(String line) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java index 97da3abd7..7424d6cc4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java @@ -606,7 +606,10 @@ public class NewProjectCreator { File libFolder = new File((String) parameters.get(PARAM_SDK_TOOLS_DIR), SdkConstants.FD_LIB); addLocalFile(project, - new File(libFolder, SdkConstants.FN_PROGUARD_CFG), + new File(libFolder, SdkConstants.FN_PROJECT_PROGUARD_FILE), + // Write ProGuard config files with the extension .pro which + // is what is used in the ProGuard documentation and samples + SdkConstants.FN_PROJECT_PROGUARD_FILE, monitor); // Set output location @@ -1080,13 +1083,14 @@ public class NewProjectCreator { /** * Adds a file to the root of the project * @param project the project to add the file to. + * @param destName the name to write the file as * @param source the file to add. It'll keep the same filename once copied into the project. * @throws FileNotFoundException * @throws CoreException */ - private void addLocalFile(IProject project, File source, IProgressMonitor monitor) - throws FileNotFoundException, CoreException { - IFile dest = project.getFile(source.getName()); + private void addLocalFile(IProject project, File source, String destName, + IProgressMonitor monitor) throws FileNotFoundException, CoreException { + IFile dest = project.getFile(destName); if (dest.exists() == false) { FileInputStream stream = new FileInputStream(source); dest.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java index d5bd8950e..ea78127a2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java @@ -15,6 +15,9 @@ */ package com.android.ide.eclipse.adt.internal.wizards.newproject; +import static com.android.sdklib.SdkConstants.FN_PROJECT_PROGUARD_FILE; +import static com.android.sdklib.SdkConstants.OS_SDK_TOOLS_LIB_FOLDER; + import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; @@ -26,6 +29,8 @@ import org.eclipse.jface.wizard.Wizard; import org.eclipse.ui.INewWizard; import org.eclipse.ui.IWorkbench; +import java.io.File; + /** * A "New Android Project" Wizard. @@ -105,6 +110,16 @@ public class NewProjectWizard extends Wizard implements INewWizard { @Override public boolean performFinish() { + File file = new File(AdtPlugin.getOsSdkFolder(), OS_SDK_TOOLS_LIB_FOLDER + File.separator + + FN_PROJECT_PROGUARD_FILE); + if (!file.exists()) { + AdtPlugin.displayError("Tools Out of Date?", + String.format("It looks like you do not have the latest version of the " + + "SDK Tools installed. Make sure you update via the SDK Manager " + + "first. (Could not find %1$s)", file.getPath())); + return false; + } + NewProjectCreator creator = new NewProjectCreator(mValues, getContainer()); if (!(creator.createAndroidProjects())) { return false; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java index 3db335300..6de65567f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java @@ -18,8 +18,11 @@ package com.android.ide.eclipse.adt.internal.wizards.newproject; import static com.android.ide.eclipse.adt.AdtUtils.capitalize; import static com.android.ide.eclipse.adt.AdtUtils.stripWhitespace; import static com.android.ide.eclipse.adt.internal.wizards.newproject.ApplicationInfoPage.ACTIVITY_NAME_SUFFIX; +import static com.android.sdklib.SdkConstants.FN_PROJECT_PROGUARD_FILE; +import static com.android.sdklib.SdkConstants.OS_SDK_TOOLS_LIB_FOLDER; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.VersionCheck; import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; import com.android.sdklib.SdkConstants; @@ -85,6 +88,15 @@ class ProjectNamePage extends WizardPage implements SelectionListener, ModifyLis private Button mBrowseButton; private Label mLocationLabel; private WorkingSetGroup mWorkingSetGroup; + /** + * Whether we've made sure the Tools are up to date (enough that all the + * resources required by the New Project wizard are present -- we don't + * necessarily check for newer versions than that here; that's done by + * {@link VersionCheck}, though that check doesn't <b>enforce</b> an update + * since it needs to allow the user to proceed to access the SDK manager + * etc.) + */ + private boolean mCheckedSdkUptodate; /** * Create the wizard. @@ -446,6 +458,20 @@ class ProjectNamePage extends WizardPage implements SelectionListener, ModifyLis } } + if (!mCheckedSdkUptodate) { + // Ensure that we have a recent enough version of the Tools that the right templates + // are available + File file = new File(AdtPlugin.getOsSdkFolder(), OS_SDK_TOOLS_LIB_FOLDER + + File.separator + FN_PROJECT_PROGUARD_FILE); + if (!file.exists()) { + status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, + String.format("You do not have the latest version of the " + + "SDK Tools installed: Please update. (Missing %1$s)", file.getPath())); + } else { + mCheckedSdkUptodate = true; + } + } + // -- update UI & enable finish if there's no error setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); if (status != null) { diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/icons/networkstats.png b/eclipse/plugins/com.android.ide.eclipse.ddms/icons/networkstats.png Binary files differnew file mode 100644 index 000000000..7018705f2 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/icons/networkstats.png diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.properties b/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.properties index 5a37fd5b3..6fd8e50e3 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.properties +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.properties @@ -9,6 +9,7 @@ view.name.Heap = Heap view.name.File_Explorer = File Explorer view.name.Emulator_Control = Emulator Control view.name.Allocation_Tracker = Allocation Tracker +view.name.Network_Stats = Network Statistics perspective.name.DDMS = DDMS page.name.DDMS = DDMS page.name.LogCat = LogCat diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml index 1255b6215..c1d43ae13 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/plugin.xml @@ -79,6 +79,14 @@ icon="icons/heap.png" id="com.android.ide.eclipse.ddms.views.AllocTrackerView" name="%view.name.Allocation_Tracker"/> + <view + category="com.android.ide.eclipse.ddms.views.category" + class="com.android.ide.eclipse.ddms.views.NetworkStatisticsView" + icon="icons/networkstats.png" + id="com.android.ide.eclipse.ddms.views.NetworkStatsView" + name="%view.name.Network_Stats" + restorable="true"> + </view> </extension> <extension point="org.eclipse.ui.perspectives"> diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/Perspective.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/Perspective.java index 4f3494c84..d86a52632 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/Perspective.java +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/Perspective.java @@ -22,6 +22,7 @@ import com.android.ide.eclipse.ddms.views.EmulatorControlView; import com.android.ide.eclipse.ddms.views.FileExplorerView; import com.android.ide.eclipse.ddms.views.HeapView; import com.android.ide.eclipse.ddms.views.LogCatView; +import com.android.ide.eclipse.ddms.views.NetworkStatisticsView; import com.android.ide.eclipse.ddms.views.ThreadView; import org.eclipse.ui.IFolderLayout; @@ -63,6 +64,7 @@ public class Perspective implements IPerspectiveFactory { folder.addView(ThreadView.ID); folder.addView(HeapView.ID); folder.addView(AllocTrackerView.ID); + folder.addView(NetworkStatisticsView.ID); folder.addView(FileExplorerView.ID); layout.addPerspectiveShortcut("org.eclipse.ui.resourcePerspective"); //$NON-NLS-1$ @@ -75,6 +77,7 @@ public class Perspective implements IPerspectiveFactory { layout.addShowViewShortcut(AllocTrackerView.ID); layout.addShowViewShortcut(LogCatView.ID); layout.addShowViewShortcut(ThreadView.ID); + layout.addShowViewShortcut(NetworkStatisticsView.ID); layout.addShowViewShortcut(IPageLayout.ID_RES_NAV); layout.addShowViewShortcut(IPageLayout.ID_BOOKMARKS); diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/NetworkStatisticsView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/NetworkStatisticsView.java new file mode 100644 index 000000000..f90189c6d --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/NetworkStatisticsView.java @@ -0,0 +1,47 @@ +/* + * 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.android.ide.eclipse.ddms.views; + +import com.android.ddmuilib.net.NetworkPanel; + +import org.eclipse.swt.widgets.Composite; + +public class NetworkStatisticsView extends TableView { + public static final String ID = "com.android.ide.eclipse.ddms.views.NetworkStatsView"; + + private NetworkPanel mPanel; + + public NetworkStatisticsView() { + } + + @Override + public void createPartControl(Composite parent) { + mPanel = new NetworkPanel(); + mPanel.createPanel(parent); + + setSelectionDependentPanel(mPanel); + + // listen to focus changes for table(s) of the panel. + setupTableFocusListener(mPanel, parent); + } + + @Override + public void setFocus() { + mPanel.setFocus(); + } + +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.gldebugger/plugin.xml index 66f7fa662..ff2799fcb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/plugin.xml @@ -33,7 +33,7 @@ </view>
<view
category="com.android.ide.eclipse.gltrace"
- class="com.android.ide.eclipse.gltrace.views.DetailsView"
+ class="com.android.ide.eclipse.gltrace.views.detail.DetailsView"
icon="icons/opengl.png"
id="com.android.ide.eclipse.gltrace.views.Details"
name="Details"
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java index bc41e335b..30bb1d532 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTracePerspective.java @@ -16,9 +16,9 @@ package com.android.ide.eclipse.gltrace; -import com.android.ide.eclipse.gltrace.views.DetailsView; import com.android.ide.eclipse.gltrace.views.FrameSummaryView; import com.android.ide.eclipse.gltrace.views.StateView; +import com.android.ide.eclipse.gltrace.views.detail.DetailsView; import org.eclipse.ui.IFolderLayout; import org.eclipse.ui.IPageLayout; diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java index ece472397..4d1da1fa8 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/editors/GLFunctionTraceViewer.java @@ -24,8 +24,8 @@ import com.android.ide.eclipse.gltrace.editors.GLCallGroups.GLCallNode; import com.android.ide.eclipse.gltrace.model.GLCall; import com.android.ide.eclipse.gltrace.model.GLFrame; import com.android.ide.eclipse.gltrace.model.GLTrace; -import com.android.ide.eclipse.gltrace.views.DetailsPage; import com.android.ide.eclipse.gltrace.views.FrameSummaryViewPage; +import com.android.ide.eclipse.gltrace.views.detail.DetailsPage; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.MessageDialog; diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLState.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLState.java index dfc922a6d..690fb7e87 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLState.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLState.java @@ -25,6 +25,9 @@ public class GLState { /** # of texture units modelled in the GL State. */ public static final int TEXTURE_UNIT_COUNT = 8; + /** # of vertex attributes */ + private static final int MAX_VERTEX_ATTRIBS = 8; + private static GLState sGLState = new GLState(); private IGLProperty createBufferBindings() { @@ -32,11 +35,11 @@ public class GLState { array = new GLIntegerProperty(GLStateType.ARRAY_BUFFER_BINDING, 0); eArray = new GLIntegerProperty(GLStateType.ELEMENT_ARRAY_BUFFER_BINDING, 0); + vArray = new GLIntegerProperty( GLStateType.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_PER_INDEX, 0); - IGLProperty vArray8 = new GLListProperty(GLStateType.VERTEX_ATTRIB_ARRAY_BUFFER_BINDINGS, - vArray, 8); + vArray, MAX_VERTEX_ATTRIBS); return new GLCompositeProperty( GLStateType.BUFFER_BINDINGS, @@ -67,14 +70,36 @@ public class GLState { return new GLListProperty( GLStateType.VERTEX_ATTRIB_ARRAY, perVertexAttribArrayState, - 8); + MAX_VERTEX_ATTRIBS); + } + + private IGLProperty createGenericVertexAttributeState() { + IGLProperty v0 = new GLFloatProperty(GLStateType.GENERIC_VERTEX_ATTRIB_V0, + Float.valueOf(0)); + IGLProperty v1 = new GLFloatProperty(GLStateType.GENERIC_VERTEX_ATTRIB_V1, + Float.valueOf(0)); + IGLProperty v2 = new GLFloatProperty(GLStateType.GENERIC_VERTEX_ATTRIB_V2, + Float.valueOf(0)); + IGLProperty v3 = new GLFloatProperty(GLStateType.GENERIC_VERTEX_ATTRIB_V3, + Float.valueOf(0)); + + IGLProperty perGenericVertexAttribState = new GLCompositeProperty( + GLStateType.GENERIC_VERTEX_ATTRIBUTE_DATA_COMPOSITE, + v0, v1, v2, v3); + + return new GLListProperty( + GLStateType.GENERIC_VERTEX_ATTRIBUTES, + perGenericVertexAttribState, + MAX_VERTEX_ATTRIBS); } private IGLProperty createVertexArrayData() { IGLProperty vertexAttribArrays = createVertexAttribArrays(); IGLProperty bufferBindings = createBufferBindings(); + IGLProperty genericAttribs = createGenericVertexAttributeState(); return new GLCompositeProperty(GLStateType.VERTEX_ARRAY_DATA, + genericAttribs, vertexAttribArrays, bufferBindings); } diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStateType.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStateType.java index 42016fa45..9d367be7c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStateType.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/GLStateType.java @@ -25,6 +25,13 @@ public enum GLStateType { GL_STATE_ES2("OpenGL ES 2.0 State"), VERTEX_ARRAY_DATA("Vertex Array Data"), + GENERIC_VERTEX_ATTRIBUTES("Generic Vertex Attributes"), + GENERIC_VERTEX_ATTRIBUTE_DATA_COMPOSITE("Generic Vertex Attribute Data"), + GENERIC_VERTEX_ATTRIB_V0("x"), + GENERIC_VERTEX_ATTRIB_V1("y"), + GENERIC_VERTEX_ATTRIB_V2("z"), + GENERIC_VERTEX_ATTRIB_V3("w"), + VERTEX_ATTRIB_ARRAY("Vertex Attrib Array Properties"), VERTEX_ATTRIB_ARRAY_COMPOSITE("Vertex Attrib Array #n Properties"), VERTEX_ATTRIB_ARRAY_ENABLED("Vertex Attrib Array Enable"), diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java index 3cc1004c1..0afd2e1fb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/state/transforms/StateTransformFactory.java @@ -41,14 +41,38 @@ public class StateTransformFactory { switch (msg.getFunction()) { case eglCreateContext: return transformsForEglCreateContext(msg); - case glVertexAttribPointer: - return transformsForGlVertexAttribPointer(msg); case glBindFramebuffer: return transformsForGlBindFramebuffer(msg); + + // vertex data + case glVertexAttribPointer: + return transformsForGlVertexAttribPointer(msg); + case glVertexAttrib1f: + case glVertexAttrib2f: + case glVertexAttrib3f: + case glVertexAttrib4f: + return transformsForGlVertexAttribxf(msg); + case glVertexAttrib1fv: + case glVertexAttrib2fv: + case glVertexAttrib3fv: + case glVertexAttrib4fv: + return transformsForGlVertexAttribxfv(msg); + case glEnableVertexAttribArray: + return transformsForGlEnableVertexAttribArray(msg); + case glDisableVertexAttribArray: + return transformsForGlDisableVertexAttribArray(msg); + + // VBO's + case glBindBuffer: + return transformsForGlBindBuffer(msg); + + // transformation state case glViewport: return transformsForGlViewport(msg); case glDepthRangef: return transformsForGlDepthRangef(msg); + + // rasterization case glLineWidth: return transformsForGlLineWidth(msg); case glCullFace: @@ -57,6 +81,8 @@ public class StateTransformFactory { return transformsForGlFrontFace(msg); case glPolygonOffset: return transformsForGlPolygonOffset(msg); + + // pixel operations case glScissor: return transformsForGlScissor(msg); case glStencilFunc: @@ -194,6 +220,124 @@ public class StateTransformFactory { return transforms; } + private static List<IStateTransform> transformsForGlVertexAttrib(int context, + int index, float v0, float v1, float v2, float v3) { + List<IStateTransform> transforms = new ArrayList<IStateTransform>(4); + transforms.add(new PropertyChangeTransform( + GLPropertyAccessor.makeAccessor(context, + GLStateType.VERTEX_ARRAY_DATA, + GLStateType.GENERIC_VERTEX_ATTRIBUTES, + Integer.valueOf(index), + GLStateType.GENERIC_VERTEX_ATTRIB_V0), + Float.valueOf(v0))); + transforms.add(new PropertyChangeTransform( + GLPropertyAccessor.makeAccessor(context, + GLStateType.VERTEX_ARRAY_DATA, + GLStateType.GENERIC_VERTEX_ATTRIBUTES, + Integer.valueOf(index), + GLStateType.GENERIC_VERTEX_ATTRIB_V1), + Float.valueOf(v1))); + transforms.add(new PropertyChangeTransform( + GLPropertyAccessor.makeAccessor(context, + GLStateType.VERTEX_ARRAY_DATA, + GLStateType.GENERIC_VERTEX_ATTRIBUTES, + Integer.valueOf(index), + GLStateType.GENERIC_VERTEX_ATTRIB_V2), + Float.valueOf(v2))); + transforms.add(new PropertyChangeTransform( + GLPropertyAccessor.makeAccessor(context, + GLStateType.VERTEX_ARRAY_DATA, + GLStateType.GENERIC_VERTEX_ATTRIBUTES, + Integer.valueOf(index), + GLStateType.GENERIC_VERTEX_ATTRIB_V3), + Float.valueOf(v3))); + return transforms; + } + + private static List<IStateTransform> transformsForGlVertexAttribxf(GLMessage msg) { + // void glVertexAttrib1f(GLuint index, GLfloat v0); + // void glVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1); + // void glVertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2); + // void glVertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); + + int index = msg.getArgs(0).getIntValue(0); + float v0 = msg.getArgs(1).getFloatValue(0); + float v1 = msg.getArgsCount() > 2 ? msg.getArgs(2).getFloatValue(0) : 0; + float v2 = msg.getArgsCount() > 3 ? msg.getArgs(3).getFloatValue(0) : 0; + float v3 = msg.getArgsCount() > 4 ? msg.getArgs(4).getFloatValue(0) : 0; + + return transformsForGlVertexAttrib(msg.getContextId(), index, v0, v1, v2, v3); + } + + private static List<IStateTransform> transformsForGlVertexAttribxfv(GLMessage msg) { + // void glVertexAttrib1fv(GLuint index, const GLfloat *v); + // void glVertexAttrib2fv(GLuint index, const GLfloat *v); + // void glVertexAttrib3fv(GLuint index, const GLfloat *v); + // void glVertexAttrib4fv(GLuint index, const GLfloat *v); + + int index = msg.getArgs(0).getIntValue(0); + float v[] = new float[4]; + + for (int i = 0; i < msg.getArgs(1).getFloatValueList().size(); i++) { + v[i] = msg.getArgs(1).getFloatValue(i); + } + + return transformsForGlVertexAttrib(msg.getContextId(), index, v[0], v[1], v[2], v[3]); + } + + private static List<IStateTransform> transformsForGlEnableVertexAttribArray(GLMessage msg) { + // void glEnableVertexAttribArray(GLuint index); + // void glDisableVertexAttribArray(GLuint index); + + int index = msg.getArgs(0).getIntValue(0); + IStateTransform transform = new PropertyChangeTransform( + GLPropertyAccessor.makeAccessor(msg.getContextId(), + GLStateType.VERTEX_ARRAY_DATA, + GLStateType.VERTEX_ATTRIB_ARRAY, + Integer.valueOf(index), + GLStateType.VERTEX_ATTRIB_ARRAY_ENABLED), + Boolean.TRUE); + return Collections.singletonList(transform); + } + + private static List<IStateTransform> transformsForGlDisableVertexAttribArray(GLMessage msg) { + // void glEnableVertexAttribArray(GLuint index); + // void glDisableVertexAttribArray(GLuint index); + + int index = msg.getArgs(0).getIntValue(0); + IStateTransform transform = new PropertyChangeTransform( + GLPropertyAccessor.makeAccessor(msg.getContextId(), + GLStateType.VERTEX_ARRAY_DATA, + GLStateType.VERTEX_ATTRIB_ARRAY, + Integer.valueOf(index), + GLStateType.VERTEX_ATTRIB_ARRAY_ENABLED), + Boolean.FALSE); + return Collections.singletonList(transform); + } + + private static List<IStateTransform> transformsForGlBindBuffer(GLMessage msg) { + // void glBindBuffer(GLenum target, GLuint buffer); + // target is one of GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER. + + GLEnum target = GLEnum.valueOf(msg.getArgs(0).getIntValue(0)); + int buffer = msg.getArgs(1).getIntValue(0); + GLStateType bufferType; + + if (target == GLEnum.GL_ARRAY_BUFFER) { + bufferType = GLStateType.ARRAY_BUFFER_BINDING; + } else { + bufferType = GLStateType.ELEMENT_ARRAY_BUFFER_BINDING; + } + + IStateTransform transform = new PropertyChangeTransform( + GLPropertyAccessor.makeAccessor(msg.getContextId(), + GLStateType.VERTEX_ARRAY_DATA, + GLStateType.BUFFER_BINDINGS, + bufferType), + Integer.valueOf(buffer)); + return Collections.singletonList(transform); + } + private static List<IStateTransform> transformsForGlBindFramebuffer(GLMessage msg) { // void glBindFramebuffer(GLenum target, GLuint framebuffer); int fb = msg.getArgs(1).getIntValue(0); diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/DetailsPage.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsPage.java index 88e7b05b7..6d6f00de5 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/DetailsPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsPage.java @@ -14,13 +14,14 @@ * limitations under the License. */ -package com.android.ide.eclipse.gltrace.views; +package com.android.ide.eclipse.gltrace.views.detail; import com.android.ide.eclipse.gltrace.editors.GLCallGroups.GLCallNode; import com.android.ide.eclipse.gltrace.editors.GLFunctionTraceViewer; import com.android.ide.eclipse.gltrace.model.GLCall; import com.android.ide.eclipse.gltrace.model.GLTrace; import com.android.ide.eclipse.gltrace.state.IGLProperty; +import com.android.ide.eclipse.gltrace.views.StateView; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.action.IToolBarManager; @@ -48,10 +49,11 @@ public class DetailsPage extends Page implements ISelectionListener { private StackLayout mStackLayout; private Composite mBlankComposite; - private List<IStateDetailsProvider> mStateDetailProviders = Arrays.asList( + private List<IDetailProvider> mDetailProviders = Arrays.asList( new ShaderSourceDetailsProvider(), new ShaderUniformDetailsProvider(), - new TextureImageDetailsProvider()); + new TextureImageDetailsProvider(), + new GlDrawCallDetailProvider()); public DetailsPage(GLTrace trace) { mTrace = trace; @@ -68,7 +70,7 @@ public class DetailsPage extends Page implements ISelectionListener { mToolBarManager = getSite().getActionBars().getToolBarManager(); - for (IStateDetailsProvider provider : mStateDetailProviders) { + for (IDetailProvider provider : mDetailProviders) { provider.createControl(mTopComposite); for (IContributionItem item: provider.getToolBarItems()) { @@ -79,7 +81,7 @@ public class DetailsPage extends Page implements ISelectionListener { setDetailsProvider(null); } - private void setDetailsProvider(IStateDetailsProvider provider) { + private void setDetailsProvider(IDetailProvider provider) { for (IContributionItem item: mToolBarManager.getItems()) { item.setVisible(false); } @@ -117,7 +119,7 @@ public class DetailsPage extends Page implements ISelectionListener { public void dispose() { getSite().getPage().removeSelectionListener(this); - for (IStateDetailsProvider provider : mStateDetailProviders) { + for (IDetailProvider provider : mDetailProviders) { provider.disposeControl(); } @@ -152,10 +154,15 @@ public class DetailsPage extends Page implements ISelectionListener { } private void stateVariableSelected(IGLProperty property) { - for (IStateDetailsProvider p : mStateDetailProviders) { - if (p.isApplicable(property)) { - p.updateControl(property); - setDetailsProvider(p); + for (IDetailProvider p : mDetailProviders) { + if (!(p instanceof IStateDetailProvider)) { + continue; + } + + IStateDetailProvider sp = (IStateDetailProvider) p; + if (sp.isApplicable(property)) { + sp.updateControl(property); + setDetailsProvider(sp); return; } } @@ -165,6 +172,21 @@ public class DetailsPage extends Page implements ISelectionListener { } private void callSelected(GLCall selectedCall) { + for (IDetailProvider p : mDetailProviders) { + if (!(p instanceof ICallDetailProvider)) { + continue; + } + + ICallDetailProvider cp = (ICallDetailProvider) p; + if (cp.isApplicable(selectedCall)) { + cp.updateControl(mTrace, selectedCall); + setDetailsProvider(cp); + return; + } + } + + setDetailsProvider(null); + return; } private GLCall getSelectedCall(GLFunctionTraceViewer part, ISelection selection) { diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/DetailsView.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsView.java index 015cf61ec..0a2d88e52 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/DetailsView.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/DetailsView.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package com.android.ide.eclipse.gltrace.views; +package com.android.ide.eclipse.gltrace.views.detail; import com.android.ide.eclipse.gltrace.editors.GLFunctionTraceViewer; +import com.android.ide.eclipse.gltrace.views.GLPageBookView; import org.eclipse.ui.IWorkbenchPart; diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/GlDrawCallDetailProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/GlDrawCallDetailProvider.java new file mode 100644 index 000000000..c3cabb09e --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/GlDrawCallDetailProvider.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.android.ide.eclipse.gltrace.views.detail; + +import com.android.ide.eclipse.gltrace.GLProtoBuf.GLMessage.Function; +import com.android.ide.eclipse.gltrace.model.GLCall; +import com.android.ide.eclipse.gltrace.model.GLTrace; +import com.android.ide.eclipse.gltrace.views.FitToCanvasAction; +import com.android.ide.eclipse.gltrace.widgets.ImageCanvas; + +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import java.util.Collections; +import java.util.List; + +public class GlDrawCallDetailProvider implements ICallDetailProvider { + private ImageCanvas mImageCanvas; + private FitToCanvasAction mFitToCanvasAction; + private List<IContributionItem> mToolBarItems; + + @Override + public boolean isApplicable(GLCall call) { + return (call.getFunction() == Function.glDrawArrays + || call.getFunction() == Function.glDrawElements) && call.hasFb(); + } + + @Override + public void createControl(Composite parent) { + mImageCanvas = new ImageCanvas(parent); + mImageCanvas.setFitToCanvas(false); + + mFitToCanvasAction = new FitToCanvasAction(false, mImageCanvas); + mToolBarItems = Collections.singletonList( + (IContributionItem) new ActionContributionItem(mFitToCanvasAction)); + } + + @Override + public void disposeControl() { + if (mImageCanvas != null) { + mImageCanvas.dispose(); + mImageCanvas = null; + } + } + + @Override + public Control getControl() { + return mImageCanvas; + } + + @Override + public void updateControl(GLTrace trace, GLCall call) { + mImageCanvas.setImage(trace.getImage(call)); + mImageCanvas.setFitToCanvas(true); + } + + @Override + public List<IContributionItem> getToolBarItems() { + return mToolBarItems; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ICallDetailProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ICallDetailProvider.java new file mode 100644 index 000000000..51770f35b --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ICallDetailProvider.java @@ -0,0 +1,31 @@ +/* + * 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.android.ide.eclipse.gltrace.views.detail; + +import com.android.ide.eclipse.gltrace.model.GLCall; +import com.android.ide.eclipse.gltrace.model.GLTrace; + +public interface ICallDetailProvider extends IDetailProvider { + /** Is this provider applicable for given {@link GLCall}? */ + boolean isApplicable(GLCall call); + + /** + * Update the detail view for given {@link GLCall} that is part of the given + * {@link GLTrace}. + */ + void updateControl(GLTrace trace, GLCall call); +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/IStateDetailsProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IDetailProvider.java index 7fe7c5609..1fc5174d3 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/IStateDetailsProvider.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IDetailProvider.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package com.android.ide.eclipse.gltrace.views; - -import com.android.ide.eclipse.gltrace.state.IGLProperty; +package com.android.ide.eclipse.gltrace.views.detail; import org.eclipse.jface.action.IContributionItem; import org.eclipse.swt.widgets.Composite; @@ -24,10 +22,7 @@ import org.eclipse.swt.widgets.Control; import java.util.List; -public interface IStateDetailsProvider { - /** Is this provider applicable for given GL state property? */ - boolean isApplicable(IGLProperty state); - +public interface IDetailProvider { /** Create the controls to display the details. */ void createControl(Composite parent); @@ -37,8 +32,6 @@ public interface IStateDetailsProvider { /** Obtain the top level control used by this detail provider. */ Control getControl(); - /** Update the detail view for given GL state property. */ - void updateControl(IGLProperty state); /** Obtain a list of tool bar items to be displayed when this provider is active. */ List<IContributionItem> getToolBarItems(); diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IStateDetailProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IStateDetailProvider.java new file mode 100644 index 000000000..4ad06beba --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/IStateDetailProvider.java @@ -0,0 +1,27 @@ +/* + * 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.android.ide.eclipse.gltrace.views.detail; + +import com.android.ide.eclipse.gltrace.state.IGLProperty; + +public interface IStateDetailProvider extends IDetailProvider { + /** Is this provider applicable for given GL state property? */ + boolean isApplicable(IGLProperty state); + + /** Update the detail view for given GL state property. */ + void updateControl(IGLProperty state); +} diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/ShaderSourceDetailsProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderSourceDetailsProvider.java index bad3042d3..a3ee5780c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/ShaderSourceDetailsProvider.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderSourceDetailsProvider.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.ide.eclipse.gltrace.views; +package com.android.ide.eclipse.gltrace.views.detail; import com.android.ide.eclipse.gltrace.state.GLCompositeProperty; import com.android.ide.eclipse.gltrace.state.GLStateType; @@ -30,7 +30,7 @@ import org.eclipse.swt.widgets.Text; import java.util.Collections; import java.util.List; -public class ShaderSourceDetailsProvider implements IStateDetailsProvider { +public class ShaderSourceDetailsProvider implements IStateDetailProvider { private Text mTextControl; @Override diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/ShaderUniformDetailsProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderUniformDetailsProvider.java index 4111b7747..f156c0009 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/ShaderUniformDetailsProvider.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/ShaderUniformDetailsProvider.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.ide.eclipse.gltrace.views; +package com.android.ide.eclipse.gltrace.views.detail; import com.android.ide.eclipse.gldebugger.GLEnum; import com.android.ide.eclipse.gltrace.state.GLCompositeProperty; @@ -31,7 +31,7 @@ import org.eclipse.swt.widgets.Text; import java.util.Collections; import java.util.List; -public class ShaderUniformDetailsProvider implements IStateDetailsProvider { +public class ShaderUniformDetailsProvider implements IStateDetailProvider { private Text mTextControl; private static final Joiner JOINER = Joiner.on(", "); diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/TextureImageDetailsProvider.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/TextureImageDetailsProvider.java index 2b0034b0b..0c17d4c2c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/TextureImageDetailsProvider.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/views/detail/TextureImageDetailsProvider.java @@ -14,12 +14,13 @@ * limitations under the License. */ -package com.android.ide.eclipse.gltrace.views; +package com.android.ide.eclipse.gltrace.views.detail; import com.android.ide.eclipse.gltrace.state.GLCompositeProperty; import com.android.ide.eclipse.gltrace.state.GLStateType; import com.android.ide.eclipse.gltrace.state.GLStringProperty; import com.android.ide.eclipse.gltrace.state.IGLProperty; +import com.android.ide.eclipse.gltrace.views.FitToCanvasAction; import com.android.ide.eclipse.gltrace.widgets.ImageCanvas; import org.eclipse.jface.action.ActionContributionItem; @@ -32,7 +33,7 @@ import org.eclipse.swt.widgets.Display; import java.util.Collections; import java.util.List; -public class TextureImageDetailsProvider implements IStateDetailsProvider { +public class TextureImageDetailsProvider implements IStateDetailProvider { private ImageCanvas mImageCanvas; private FitToCanvasAction mFitToCanvasAction; private List<IContributionItem> mToolBarItems; diff --git a/files/ant/build.xml b/files/ant/build.xml index 622d5584e..e47c3fe53 100644 --- a/files/ant/build.xml +++ b/files/ant/build.xml @@ -766,13 +766,24 @@ </firstmatchmapper> </pathconvert> + <!-- Turn the path property ${proguard.config} from an A:B:C property + into a series of includes: -include A -include B -include C + suitable for processing by the ProGuard task. Note - this does + not include the leading '-include "' or the closing '"'; those + are added under the <proguard> call below. + --> + <path id="proguard.configpath"> + <pathelement path="${proguard.config}"/> + </path> + <pathconvert pathsep='" -include "' property="proguard.configcmd" refid="proguard.configpath"/> + <mkdir dir="${obfuscate.absolute.dir}" /> <delete file="${preobfuscate.jar.file}"/> <delete file="${obfuscated.jar.file}"/> <jar basedir="${out.classes.absolute.dir}" destfile="${preobfuscate.jar.file}" /> <proguard> - @${proguard.config} + -include "${proguard.configcmd}" -injars ${project.jars} -outjars "${obfuscated.jar.file}" -libraryjars ${android.libraryjars} diff --git a/files/proguard-android.txt b/files/proguard-android.txt new file mode 100644 index 000000000..b3d2fe156 --- /dev/null +++ b/files/proguard-android.txt @@ -0,0 +1,77 @@ +# This is a configuration file for ProGuard. +# http://proguard.sourceforge.net/index.html#manual/usage.html + +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-verbose + +# Optimization is turned off by default. Dex does not like code run +# through the ProGuard optimize and preverify steps (and performs some +# of these optimizations on its own). +-dontoptimize +-dontpreverify + +# If you want to enable optimization, you should include the +# following: +# -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* +# -optimizationpasses 5 +# -allowaccessmodification +# +# Note that you cannot just include these flags in your own +# configuration file; if you are including this file, optimization +# will be turned off. You'll need to either edit this file, or +# duplicate the contents of this file and remove the include of this +# file from your project's proguard.config path property. + +-keepattributes *Annotation* +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgent +-keep public class * extends android.preference.Preference +-keep public class com.android.vending.licensing.ILicensingService + +# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native +-keepclasseswithmembernames class * { + native <methods>; +} + +-keep public class * extends android.view.View { + public <init>(android.content.Context); + public <init>(android.content.Context, android.util.AttributeSet); + public <init>(android.content.Context, android.util.AttributeSet, int); + public void set*(...); +} + +-keepclasseswithmembers class * { + public <init>(android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public <init>(android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + +-keepclassmembers class **.R$* { + public static <fields>; +} + +# The support library contains references to newer platform versions. +# Don't warn about those in case this app is linking against an older +# platform version. We know about them, and they are safe. +-dontwarn android.support.** diff --git a/files/proguard-project.txt b/files/proguard-project.txt new file mode 100644 index 000000000..f2fe1559a --- /dev/null +++ b/files/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/ide_common/src/com/android/ide/common/resources/ResourceRepository.java b/ide_common/src/com/android/ide/common/resources/ResourceRepository.java index d78f1d102..87d729d2e 100644 --- a/ide_common/src/com/android/ide/common/resources/ResourceRepository.java +++ b/ide_common/src/com/android/ide/common/resources/ResourceRepository.java @@ -598,9 +598,9 @@ public abstract class ResourceRepository { /** - * Called after a resource change event, when the resource delta has been processed. + * Cleans up the repository of resource items that have no source file anymore. */ - protected void postUpdate() { + public void postUpdateCleanUp() { // Since removed files/folders remove source files from existing ResourceItem, loop through // all resource items and remove the ones that have no source files. diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java index 4ebc9ed70..3f32727ac 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java @@ -21,7 +21,8 @@ import static com.android.tools.lint.detector.api.LintConstants.ATTR_IGNORE; import static com.android.tools.lint.detector.api.LintConstants.DOT_CLASS; import static com.android.tools.lint.detector.api.LintConstants.DOT_JAR; import static com.android.tools.lint.detector.api.LintConstants.DOT_JAVA; -import static com.android.tools.lint.detector.api.LintConstants.PROGUARD_CFG; +import static com.android.tools.lint.detector.api.LintConstants.OLD_PROGUARD_FILE; +import static com.android.tools.lint.detector.api.LintConstants.PROGUARD_FILE; import static com.android.tools.lint.detector.api.LintConstants.RES_FOLDER; import static com.android.tools.lint.detector.api.LintConstants.SUPPRESS_ALL; import static com.android.tools.lint.detector.api.LintConstants.SUPPRESS_LINT; @@ -46,6 +47,8 @@ import com.android.tools.lint.detector.api.Scope; import com.android.tools.lint.detector.api.Severity; import com.android.tools.lint.detector.api.XmlContext; import com.google.common.annotations.Beta; +import com.google.common.base.CharMatcher; +import com.google.common.base.Splitter; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.google.common.io.ByteStreams; @@ -215,7 +218,7 @@ public class LintDriver { mScope.add(Scope.MANIFEST); } else if (name.endsWith(".xml")) { mScope.add(Scope.RESOURCE_FILE); - } else if (name.equals(PROGUARD_CFG)) { + } else if (name.equals(PROGUARD_FILE) || name.equals(OLD_PROGUARD_FILE)) { mScope.add(Scope.PROGUARD_FILE); } else if (name.equals(RES_FOLDER) || file.getParent().equals(RES_FOLDER)) { @@ -225,6 +228,8 @@ public class LintDriver { mScope.add(Scope.JAVA_FILE); } else if (name.endsWith(DOT_CLASS)) { mScope.add(Scope.CLASS_FILE); + } else if (name.equals(OLD_PROGUARD_FILE) || name.equals(PROGUARD_FILE)) { + mScope.add(Scope.PROGUARD_FILE); } } } else { @@ -740,18 +745,50 @@ public class LintDriver { } if (project == main && mScope.contains(Scope.PROGUARD_FILE)) { - List<Detector> detectors = mScopeDetectors.get(Scope.PROGUARD_FILE); - if (detectors != null) { - File file = new File(project.getDir(), PROGUARD_CFG); + checkProGuard(project, main); + } + } + + private void checkProGuard(Project project, Project main) { + List<Detector> detectors = mScopeDetectors.get(Scope.PROGUARD_FILE); + if (detectors != null) { + Project p = main != null ? main : project; + List<File> files = new ArrayList<File>(); + String paths = p.getProguardPath(); + if (paths != null) { + Splitter splitter = Splitter.on(CharMatcher.anyOf(":;")); //$NON-NLS-1$ + for (String path : splitter.split(paths)) { + if (path.contains("${")) { //$NON-NLS-1$ + // Don't analyze the global/user proguard files + continue; + } + File file = new File(path); + if (!file.isAbsolute()) { + file = new File(project.getDir(), path); + } + if (file.exists()) { + files.add(file); + } + } + } + if (files.isEmpty()) { + File file = new File(project.getDir(), OLD_PROGUARD_FILE); if (file.exists()) { - Context context = new Context(this, project, main, file); - fireEvent(EventType.SCANNING_FILE, context); - for (Detector detector : detectors) { - if (detector.appliesTo(context, file)) { - detector.beforeCheckFile(context); - detector.run(context); - detector.afterCheckFile(context); - } + files.add(file); + } + file = new File(project.getDir(), PROGUARD_FILE); + if (file.exists()) { + files.add(file); + } + } + for (File file : files) { + Context context = new Context(this, project, main, file); + fireEvent(EventType.SCANNING_FILE, context); + for (Detector detector : detectors) { + if (detector.appliesTo(context, file)) { + detector.beforeCheckFile(context); + detector.run(context); + detector.afterCheckFile(context); } } } diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java index cb47f9282..678865274 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java @@ -242,7 +242,9 @@ public class LintConstants { // Filenames and folder names public static final String ANDROID_MANIFEST_XML = "AndroidManifest.xml"; //$NON-NLS-1$ - public static final String PROGUARD_CFG = "proguard.cfg"; //$NON-NLS-1$ + public static final String OLD_PROGUARD_FILE = "proguard.cfg"; //$NON-NLS-1$ + public static final String PROGUARD_FILE = "proguard-project.txt"; //$NON-NLS-1$ + public static final String RES_FOLDER = "res"; //$NON-NLS-1$ public static final String DOT_XML = ".xml"; //$NON-NLS-1$ public static final String DOT_GIF = ".gif"; //$NON-NLS-1$ @@ -283,6 +285,7 @@ public class LintConstants { // Project properties public static final String ANDROID_LIBRARY = "android.library"; //$NON-NLS-1$ + public static final String PROGUARD_CONFIG = "proguard.config"; //$NON-NLS-1$ public static final String ANDROID_LIBRARY_REFERENCE_FORMAT = "android.library.reference.%1$d";//$NON-NLS-1$ public static final String PROJECT_PROPERTIES = "project.properties";//$NON-NLS-1$ diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java index 910ee2f9e..d0de34c3e 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java @@ -23,6 +23,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ANDROID_URI; import static com.android.tools.lint.detector.api.LintConstants.ATTR_MIN_SDK_VERSION; import static com.android.tools.lint.detector.api.LintConstants.ATTR_PACKAGE; import static com.android.tools.lint.detector.api.LintConstants.ATTR_TARGET_SDK_VERSION; +import static com.android.tools.lint.detector.api.LintConstants.PROGUARD_CONFIG; import static com.android.tools.lint.detector.api.LintConstants.PROJECT_PROPERTIES; import static com.android.tools.lint.detector.api.LintConstants.TAG_USES_SDK; import static com.android.tools.lint.detector.api.LintConstants.VALUE_TRUE; @@ -71,6 +72,7 @@ public class Project { private int mTargetSdk = -1; private boolean mLibrary; private String mName; + private String mProguardPath; /** The SDK info, if any */ private SdkInfo mSdkInfo; @@ -121,6 +123,7 @@ public class Project { properties.load(is); String value = properties.getProperty(ANDROID_LIBRARY); mLibrary = VALUE_TRUE.equals(value); + mProguardPath = properties.getProperty(PROGUARD_CONFIG); for (int i = 1; i < 1000; i++) { String key = String.format(ANDROID_LIBRARY_REFERENCE_FORMAT, i); @@ -545,6 +548,17 @@ public class Project { } /** + * Returns the proguard path configured for this project, or null if ProGuard is + * not configured. + * + * @return the proguard path, or null + */ + @Nullable + public String getProguardPath() { + return mProguardPath; + } + + /** * Returns the name of the project * * @return the name of the project, never null diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java index 258a267a1..3af53ade1 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java @@ -53,7 +53,7 @@ public class BuiltinIssueRegistry extends IssueRegistry { private static final List<Issue> sIssues; static { - final int initialCapacity = 81; + final int initialCapacity = 82; List<Issue> issues = new ArrayList<Issue>(initialCapacity); issues.add(AccessibilityDetector.ISSUE); @@ -89,7 +89,8 @@ public class BuiltinIssueRegistry extends IssueRegistry { issues.add(TranslationDetector.MISSING); issues.add(HardcodedValuesDetector.ISSUE); issues.add(Utf8Detector.ISSUE); - issues.add(ProguardDetector.ISSUE); + issues.add(ProguardDetector.WRONGKEEP); + issues.add(ProguardDetector.SPLITCONFIG); issues.add(PxUsageDetector.ISSUE); issues.add(TextFieldDetector.ISSUE); issues.add(TextViewDetector.ISSUE); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ColorUsageDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ColorUsageDetector.java index f380784a9..07a1f03a2 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ColorUsageDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ColorUsageDetector.java @@ -49,7 +49,7 @@ public class ColorUsageDetector extends Detector implements Detector.JavaScanner "an RGB triple, not the actual color resource id. You must call " + "getResources().getColor(resource) to resolve the actual color value first.", - Category.PERFORMANCE, + Category.CORRECTNESS, 7, Severity.ERROR, ColorUsageDetector.class, diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ProguardDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ProguardDetector.java index 95de73948..c062507e1 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ProguardDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ProguardDetector.java @@ -16,6 +16,9 @@ package com.android.tools.lint.checks; +import static com.android.tools.lint.detector.api.LintConstants.PROGUARD_CONFIG; +import static com.android.tools.lint.detector.api.LintConstants.PROJECT_PROPERTIES; + import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -34,10 +37,10 @@ import java.util.EnumSet; public class ProguardDetector extends Detector { /** The main issue discovered by this detector */ - public static final Issue ISSUE = Issue.create( + public static final Issue WRONGKEEP = Issue.create( "Proguard", //$NON-NLS-1$ - "Looks for problems in proguard.cfg files", - "Using -keepclasseswithmembernames in a proguard.cfg file is not " + + "Looks for problems in proguard config files", + "Using -keepclasseswithmembernames in a proguard config file is not " + "correct; it can cause some symbols to be renamed which should not be.\n" + "Earlier versions of ADT used to create proguard.cfg files with the " + "wrong format. Instead of -keepclasseswithmembernames use " + @@ -51,25 +54,105 @@ public class ProguardDetector extends Detector { EnumSet.of(Scope.PROGUARD_FILE)).setMoreInfo( "http://http://code.google.com/p/android/issues/detail?id=16384"); //$NON-NLS-1$ + /** Finds ProGuard files that contain non-project specific configuration + * locally and suggests replacing it with an include path */ + public static final Issue SPLITCONFIG = Issue.create( + "ProguardSplit", //$NON-NLS-1$ + "Checks for old proguard.cfg files that contain generic Android rules", + + "Earlier versions of the Android tools bundled a single \"proguard.cfg\" file " + + "containing a ProGuard configuration file suitable for Android shrinking and " + + "obfuscation. However, that version was copied into new projects, which " + + "means that it does not continue to get updated as we improve the default " + + "ProGuard rules for Android.\n" + + "\n" + + "In the new version of the tools, we have split the ProGuard configuration " + + "into two halves:\n" + + "* A simple configuration file containing only project-specific flags, in " + + "your project\n" + + "* A generic configuration file containing the recommended set of ProGuard " + + "options for Android projects. This generic file lives in the SDK install " + + "directory which means that it gets updated along with the tools.\n" + + "\n" + + "In order for this to work, the proguard.config property in the " + + "project.properties file now refers to a path, so you can reference both " + + "the generic file as well as your own (and any additional files too).\n" + + "\n" + + "To migrate your project to the new setup, create a new proguard-project.txt file " + + "in your project containing any project specific ProGuard flags as well as " + + "any customizations you have made, then update your project.properties file " + + "to contain:\n" + + "proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt", + + Category.CORRECTNESS, + 3, + Severity.WARNING, + ProguardDetector.class, + EnumSet.of(Scope.PROGUARD_FILE)); + @Override public void run(Context context) { String contents = context.getContents(); if (contents != null) { - int index = contents.indexOf( - // Old pattern: - "-keepclasseswithmembernames class * {\n" + //$NON-NLS-1$ - " public <init>(android."); //$NON-NLS-1$ - if (index != -1) { - context.report(ISSUE, - Location.create(context.file, contents, index, index), - "Obsolete proguard file; use -keepclasseswithmembers instead of -keepclasseswithmembernames", null); + if (context.isEnabled(WRONGKEEP)) { + int index = contents.indexOf( + // Old pattern: + "-keepclasseswithmembernames class * {\n" + //$NON-NLS-1$ + " public <init>(android."); //$NON-NLS-1$ + if (index != -1) { + context.report(WRONGKEEP, + Location.create(context.file, contents, index, index), + "Obsolete ProGuard file; use -keepclasseswithmembers instead of " + + "-keepclasseswithmembernames", null); + } + } + if (context.isEnabled(SPLITCONFIG)) { + int index = contents.indexOf("-keep public class * extends android.app.Activity"); + if (index != -1) { + // Only complain if project.properties actually references this file; + // no need to bother the users who got a default proguard.cfg file + // when they created their projects but haven't actually hooked it up + // to shrinking & obfuscation. + File propertyFile = new File(context.file.getParentFile(), PROJECT_PROPERTIES); + if (!propertyFile.exists()) { + return; + } + String properties = context.getClient().readFile(propertyFile); + int i = properties.indexOf(PROGUARD_CONFIG); + if (i == -1) { + return; + } + // Make sure the entry isn't just commented out, such as + // # To enable ProGuard to shrink and obfuscate your code, uncomment this: + // #proguard.config=proguard.cfg + for (; i >= 0; i--) { + char c = properties.charAt(i); + if (c == '#') { + return; + } + if (c == '\n') { + break; + } + } + if (properties.contains(PROGUARD_CONFIG)) { + context.report(SPLITCONFIG, + Location.create(context.file, contents, index, index), + String.format( + "Local ProGuard configuration contains general Android " + + "configuration: Inherit these settings instead? " + + "Modify project.properties to define " + + "proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:%1$s" + + " and then keep only project-specific configuration here", + context.file.getName()), null); + } + } } } } @Override public boolean appliesTo(Context context, File file) { - return file.getName().equals("proguard.cfg"); //$NON-NLS-1$ + return true; } @Override diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ProguardDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ProguardDetectorTest.java index 019effdd6..f3d872b21 100644 --- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ProguardDetectorTest.java +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ProguardDetectorTest.java @@ -27,8 +27,60 @@ public class ProguardDetectorTest extends AbstractCheckTest { public void testProguard() throws Exception { assertEquals( - "proguard.cfg:21: Error: Obsolete proguard file; use -keepclasseswithmembers " + + "proguard.cfg:21: Error: Obsolete ProGuard file; use -keepclasseswithmembers " + "instead of -keepclasseswithmembernames", lintFiles("proguard.cfg")); } + + public void testProguardNewPath() throws Exception { + assertEquals( + "proguard-project.txt:21: Error: Obsolete ProGuard file; use " + + "-keepclasseswithmembers instead of -keepclasseswithmembernames", + lintFiles("proguard.cfg=>proguard-project.txt")); + } + + public void testProguardRandomName() throws Exception { + assertEquals( + "myfile.txt:21: Error: Obsolete ProGuard file; use -keepclasseswithmembers " + + "instead of -keepclasseswithmembernames\n" + + "myfile.txt:8: Warning: Local ProGuard configuration contains general " + + "Android configuration: Inherit these settings instead? Modify " + + "project.properties to define proguard.config=${sdk.dir}/tools/proguard/" + + "proguard-android.txt:myfile.txt and then keep only project-specific " + + "configuration here", + lintProject( + "proguard.cfg=>myfile.txt", + "proguard.properties=>project.properties")); + } + + public void testSilent() throws Exception { + assertEquals( + "No warnings.", + + lintFiles( + "proguard.pro=>proguard.cfg", + "project.properties1=>project.properties")); + } + + public void testSilent2() throws Exception { + assertEquals( + "No warnings.", + + lintFiles( + "proguard.pro=>proguard.cfg", + "project.properties3=>project.properties")); + } + + public void testSplit() throws Exception { + assertEquals( + "proguard.cfg:14: Warning: Local ProGuard configuration contains general " + + "Android configuration: Inherit these settings instead? Modify " + + "project.properties to define " + + "proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard.cfg " + + "and then keep only project-specific configuration here", + + lintFiles( + "proguard.pro=>proguard.cfg", + "project.properties2=>project.properties")); + } } diff --git a/files/proguard.cfg b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/proguard.pro index 53f41fea9..53f41fea9 100644 --- a/files/proguard.cfg +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/proguard.pro diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/proguard.properties b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/proguard.properties new file mode 100644 index 000000000..989c3c753 --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/proguard.properties @@ -0,0 +1,2 @@ +target=android-14 +proguard.config=${sdk.dir}/foo.cfg:${user.home}/bar.pro;myfile.txt diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties1 b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties1 new file mode 100644 index 000000000..2b783dd94 --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties1 @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this: +#proguard.config=proguard.cfg + +# Project target. +target=android-3 diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties2 b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties2 new file mode 100644 index 000000000..d9a28ecbd --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties2 @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this: +proguard.config=proguard.cfg + +# Project target. +target=android-3 diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties3 b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties3 new file mode 100644 index 000000000..3cb9d31cf --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties3 @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-3 diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties4 b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties4 new file mode 100644 index 000000000..fca931138 --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/project.properties4 @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this: +proguard.config=${sdk.dir}/tools/proguard/android-defaults.pro:proguard.pro + +# Project target. +target=android-3 diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java index 4f3ed9fe4..e21e14f23 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java @@ -166,8 +166,10 @@ public final class SdkConstants { */ public final static String FN_GDBSERVER = "gdbserver"; //$NON-NLS-1$ - /** default proguard config file */ - public final static String FN_PROGUARD_CFG = "proguard.cfg"; //$NON-NLS-1$ + /** global Android proguard config file */ + public final static String FN_ANDROID_PROGUARD_FILE = "proguard-android.txt"; //$NON-NLS-1$ + /** default proguard config file with new file extension (for project specific stuff) */ + public final static String FN_PROJECT_PROGUARD_FILE = "proguard-project.txt"; //$NON-NLS-1$ /* Folder Names for Android Projects . */ @@ -385,7 +387,6 @@ public final class SdkConstants { /** SDK property: default skin */ public final static String PROP_SDK_DEFAULT_SKIN = "sdk.skin.default"; //$NON-NLS-1$ - /* Android Class Constants */ public final static String CLASS_ACTIVITY = "android.app.Activity"; //$NON-NLS-1$ public final static String CLASS_APPLICATION = "android.app.Application"; //$NON-NLS-1$ diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java index 436f2e8a3..db3cc33c4 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java @@ -28,6 +28,7 @@ import com.android.sdklib.internal.avd.AvdInfo.AvdStatus; import com.android.sdklib.internal.project.ProjectProperties; import com.android.sdklib.util.GrabProcessOutput; import com.android.sdklib.util.GrabProcessOutput.IProcessOutput; +import com.android.sdklib.util.GrabProcessOutput.Wait; import com.android.util.Pair; import java.io.File; @@ -1398,7 +1399,7 @@ public class AvdManager { int status = GrabProcessOutput.grabProcessOutput( process, - true /*waitForReaders*/, + Wait.WAIT_FOR_READERS, new IProcessOutput() { @Override public void out(String line) { diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/KeystoreHelper.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/KeystoreHelper.java index 06f53513c..af5b401f0 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/KeystoreHelper.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/KeystoreHelper.java @@ -20,6 +20,7 @@ import com.android.sdklib.internal.build.DebugKeyProvider.IKeyGenOutput; import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException; import com.android.sdklib.util.GrabProcessOutput; import com.android.sdklib.util.GrabProcessOutput.IProcessOutput; +import com.android.sdklib.util.GrabProcessOutput.Wait; import java.io.File; import java.io.IOException; @@ -107,7 +108,7 @@ public final class KeystoreHelper { Process process = Runtime.getRuntime().exec(commandArray); result = GrabProcessOutput.grabProcessOutput( process, - true /*waitForReaders*/, + Wait.WAIT_FOR_READERS, new IProcessOutput() { @Override public void out(String line) { diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java index c3d7993c0..721d165c9 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java @@ -369,8 +369,8 @@ public class ProjectCreator { keywords); // install the proguard config file. - installTemplate(SdkConstants.FN_PROGUARD_CFG, - new File(projectFolder, SdkConstants.FN_PROGUARD_CFG), + installTemplate(SdkConstants.FN_PROJECT_PROGUARD_FILE, + new File(projectFolder, SdkConstants.FN_PROJECT_PROGUARD_FILE), null /*keywords*/); } catch (Exception e) { mLog.error(e, null); @@ -751,8 +751,10 @@ public class ProjectCreator { if (hasProguard == false) { try { - installTemplate(SdkConstants.FN_PROGUARD_CFG, - new File(projectFolder, SdkConstants.FN_PROGUARD_CFG), + installTemplate(SdkConstants.FN_PROJECT_PROGUARD_FILE, + // Write ProGuard config files with the extension .pro which + // is what is used in the ProGuard documentation and samples + new File(projectFolder, SdkConstants.FN_PROJECT_PROGUARD_FILE), null /*placeholderMap*/); } catch (ProjectCreateException e) { mLog.error(e, null); diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java index 3a73befd2..2bb6b7198 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java @@ -16,6 +16,11 @@ package com.android.sdklib.internal.project; +import static com.android.sdklib.SdkConstants.FD_PROGUARD; +import static com.android.sdklib.SdkConstants.FD_TOOLS; +import static com.android.sdklib.SdkConstants.FN_ANDROID_PROGUARD_FILE; +import static com.android.sdklib.SdkConstants.FN_PROJECT_PROGUARD_FILE; + import com.android.io.FolderWrapper; import com.android.io.IAbstractFile; import com.android.io.IAbstractFolder; @@ -24,6 +29,7 @@ import com.android.sdklib.ISdkLog; import com.android.sdklib.SdkConstants; import java.io.BufferedReader; +import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; @@ -163,7 +169,7 @@ public class ProjectProperties { "# This file is automatically generated by Android Tools.\n" + "# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n" + "#\n" + - "# This file must *NOT* be checked in Version Control Systems,\n" + + "# This file must *NOT* be checked into Version Control Systems,\n" + "# as it contains information specific to your local configuration.\n" + "\n"; @@ -174,16 +180,22 @@ public class ProjectProperties { "#\n" + "# This file must be checked in Version Control Systems.\n" + "#\n" + - "# To customize properties used by the Ant build system use,\n" + + "# To customize properties used by the Ant build system edit\n" + "# \"ant.properties\", and override values to adapt the script to your\n" + "# project structure.\n" + + "#\n" + + "# To enable ProGuard to shrink and obfuscate your code, uncomment this " + + "(available properties: sdk.dir, user.home):\n" + + "#" + PROPERTY_PROGUARD_CONFIG + "=${" + PROPERTY_SDK +"}" + File.separator + + FD_TOOLS + File.separator + FD_PROGUARD + File.separator + + FN_ANDROID_PROGUARD_FILE + ':' + FN_PROJECT_PROGUARD_FILE +'\n' + "\n"; private final static String BUILD_HEADER = // 1-------10--------20--------30--------40--------50--------60--------70--------80 "# This file is used to override default values used by the Ant build system.\n" + "#\n" + - "# This file must be checked in Version Control Systems, as it is\n" + + "# This file must be checked into Version Control Systems, as it is\n" + "# integral to the build system of your project.\n" + "\n" + "# This file is only used by the Ant script.\n" + diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java index 9e50430b9..2e2396ff4 100755 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java @@ -25,6 +25,7 @@ import com.android.sdklib.io.IFileOp; import com.android.sdklib.repository.RepoConstants;
import com.android.sdklib.util.GrabProcessOutput;
import com.android.sdklib.util.GrabProcessOutput.IProcessOutput;
+import com.android.sdklib.util.GrabProcessOutput.Wait;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
@@ -598,7 +599,7 @@ public class ArchiveInstaller { Process process = Runtime.getRuntime().exec(command);
int retCode = GrabProcessOutput.grabProcessOutput(
process,
- true /*waitForReaders*/,
+ Wait.WAIT_FOR_READERS,
new IProcessOutput() {
@Override
public void out(String line) {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java index ffd561f27..3ddacb471 100755 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java @@ -25,6 +25,7 @@ import com.android.sdklib.internal.repository.Archive.Os; import com.android.sdklib.repository.SdkRepoConstants;
import com.android.sdklib.util.GrabProcessOutput;
import com.android.sdklib.util.GrabProcessOutput.IProcessOutput;
+import com.android.sdklib.util.GrabProcessOutput.Wait;
import org.w3c.dom.Node;
@@ -276,7 +277,7 @@ public class ToolPackage extends Package implements IMinPlatformToolsDependency final String tag = scriptName;
status = GrabProcessOutput.grabProcessOutput(
proc,
- false /*waitForReaders*/,
+ Wait.WAIT_FOR_PROCESS,
new IProcessOutput() {
@Override
public void out(String line) {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/-sdk-addon-4.xsd b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/-sdk-addon-4.xsd index 9289e1c88..ef92bde2a 100755 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/-sdk-addon-4.xsd +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/-sdk-addon-4.xsd @@ -124,7 +124,12 @@ <!-- An optional element indicating the package is obsolete. The string content is however currently not defined and ignored. --> - <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + + <!-- An optional element indicating the package is a beta/preview. + When present, it indicates the release-candidate number. + When the element is absent, it indicates this is a released package. --> + <xsd:element name="beta-rc" type="xsd:positiveInteger" minOccurs="0" /> <!-- Optional information on the layoutlib packaged in this platform. --> <xsd:element name="layoutlib" type="sdk:layoutlibType" minOccurs="0" /> @@ -218,9 +223,15 @@ <!-- The minimal API level required by this package. Optional. If present, must be an int > 0. --> <xsd:element name="min-api-level" type="xsd:positiveInteger" minOccurs="0" /> + <!-- An optional element indicating the package is obsolete. The string content is however currently not defined and ignored. --> - <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + + <!-- An optional element indicating the package is a beta/preview. + When present, it indicates the release-candidate number. + When the element is absent, it indicates this is a released package. --> + <xsd:element name="beta-rc" type="xsd:positiveInteger" minOccurs="0" /> <!-- A list of project files contributed by this package. Optional. --> <xsd:element name="project-files" type="sdk:projectFilesType" minOccurs="0" /> diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/-sdk-repository-6.xsd b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/-sdk-repository-6.xsd index 149f8c591..d4cc1cb11 100755 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/-sdk-repository-6.xsd +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/-sdk-repository-6.xsd @@ -134,6 +134,11 @@ <!-- An optional element indicating the package is obsolete. The string content is however currently not defined and ignored. --> <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + + <!-- An optional element indicating the package is a beta/preview. + When present, it indicates the release-candidate number. + When the element is absent, it indicates this is a released package. --> + <xsd:element name="beta-rc" type="xsd:positiveInteger" minOccurs="0" /> </xsd:all> </xsd:complexType> @@ -194,6 +199,15 @@ <!-- A list of file archives for this package. --> <xsd:element name="archives" type="sdk:archivesType" /> + + <!-- An optional element indicating the package is obsolete. + The string content is however currently not defined and ignored. --> + <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + + <!-- An optional element indicating the package is a beta/preview. + When present, it indicates the release-candidate number. + When the element is absent, it indicates this is a released package. --> + <xsd:element name="beta-rc" type="xsd:positiveInteger" minOccurs="0" /> </xsd:all> </xsd:complexType> @@ -245,6 +259,15 @@ <!-- A list of file archives for this package. --> <xsd:element name="archives" type="sdk:archivesType" /> + + <!-- An optional element indicating the package is obsolete. + The string content is however currently not defined and ignored. --> + <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + + <!-- An optional element indicating the package is a beta/preview. + When present, it indicates the release-candidate number. + When the element is absent, it indicates this is a released package. --> + <xsd:element name="beta-rc" type="xsd:positiveInteger" minOccurs="0" /> </xsd:all> </xsd:complexType> @@ -272,13 +295,19 @@ <xsd:element name="release-url" type="xsd:token" minOccurs="0" /> <!-- A list of file archives for this package. --> <xsd:element name="archives" type="sdk:archivesType" /> - <!-- An optional element indicating the package is obsolete. - The string content is however currently not defined and ignored. --> - <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> <!-- The minimal revision of platform-tools required by this package. Mandatory. Must be an int > 0. --> <xsd:element name="min-platform-tools-rev" type="xsd:positiveInteger" /> + + <!-- An optional element indicating the package is obsolete. + The string content is however currently not defined and ignored. --> + <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + + <!-- An optional element indicating the package is a beta/preview. + When present, it indicates the release-candidate number. + When the element is absent, it indicates this is a released package. --> + <xsd:element name="beta-rc" type="xsd:positiveInteger" minOccurs="0" /> </xsd:all> </xsd:complexType> @@ -310,6 +339,11 @@ <!-- An optional element indicating the package is obsolete. The string content is however currently not defined and ignored. --> <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + + <!-- An optional element indicating the package is a beta/preview. + When present, it indicates the release-candidate number. + When the element is absent, it indicates this is a released package. --> + <xsd:element name="beta-rc" type="xsd:positiveInteger" minOccurs="0" /> </xsd:all> </xsd:complexType> @@ -343,9 +377,15 @@ <!-- A list of file archives for this package. --> <xsd:element name="archives" type="sdk:archivesType" /> + <!-- An optional element indicating the package is obsolete. The string content is however currently not defined and ignored. --> <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + + <!-- An optional element indicating the package is a beta/preview. + When present, it indicates the release-candidate number. + When the element is absent, it indicates this is a released package. --> + <xsd:element name="beta-rc" type="xsd:positiveInteger" minOccurs="0" /> </xsd:all> </xsd:complexType> @@ -382,9 +422,15 @@ Optional. If present, must be an int > 0. --> <xsd:element name="min-tools-rev" type="xsd:positiveInteger" minOccurs="0" /> + <!-- An optional element indicating the package is obsolete. The string content is however currently not defined and ignored. --> <xsd:element name="obsolete" type="xsd:string" minOccurs="0" /> + + <!-- An optional element indicating the package is a beta/preview. + When present, it indicates the release-candidate number. + When the element is absent, it indicates this is a released package. --> + <xsd:element name="beta-rc" type="xsd:positiveInteger" minOccurs="0" /> </xsd:all> </xsd:complexType> diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/util/GrabProcessOutput.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/util/GrabProcessOutput.java index b4701537c..2935493f8 100755 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/util/GrabProcessOutput.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/util/GrabProcessOutput.java @@ -25,6 +25,35 @@ import java.io.InputStreamReader; public class GrabProcessOutput { + public enum Wait { + /** + * Doesn't wait for the exec to complete. + * This still monitors the output but does not wait for the process to finish. + * In this mode the process return code is unknown and always 0. + */ + ASYNC, + /** + * This waits for the process to finish. + * In this mode, {@link GrabProcessOutput#grabProcessOutput} returns the + * error code from the process. + * In some rare cases and depending on the OS, the process might not have + * finished dumping data into stdout/stderr. + * <p/> + * Use this when you don't particularly care for the output but instead + * care for the return code of the executed process. + */ + WAIT_FOR_PROCESS, + /** + * This waits for the process to finish <em>and</em> for the stdout/stderr + * threads to complete. + * In this mode, {@link GrabProcessOutput#grabProcessOutput} returns the + * error code from the process. + * <p/> + * Use this one when capturing all the output from the process is important. + */ + WAIT_FOR_READERS, + } + public interface IProcessOutput { /** * Processes an stdout message line. @@ -46,13 +75,13 @@ public class GrabProcessOutput { * @param output Optional object to capture stdout/stderr. * Note that on Windows capturing the output is not optional. If output is null * the stdout/stderr will be captured and discarded. - * @param waitForReaders True to wait for the reader threads to finish. + * @param waitMode Whether to wait for the process and/or the readers to finish. * @return the process return code. * @throws InterruptedException if {@link Process#waitFor()} was interrupted. */ public static int grabProcessOutput( @NonNull final Process process, - boolean waitForReaders, + Wait waitMode, @Nullable final IProcessOutput output) throws InterruptedException { // read the lines as they come. if null is returned, it's // because the process finished @@ -104,10 +133,14 @@ public class GrabProcessOutput { threadErr.start(); threadOut.start(); + if (waitMode == Wait.ASYNC) { + return 0; + } + // it looks like on windows process#waitFor() can return // before the thread have filled the arrays, so we wait for both threads and the // process itself. - if (waitForReaders) { + if (waitMode == Wait.WAIT_FOR_READERS) { try { threadErr.join(); } catch (InterruptedException e) { |