Move from arbitrary resource filters to fix ones
Resource filters are used when generating additional APK containing only specific resources. The previous UI allowed for any type of filters, but we are moving to a simpler way with fixed filters. The first one is the density. Selecting the filter will generate 4 APKs per application: default (all resources), hdpi (only hdpi/nodpi and default resources), mdpi, ldpi.
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package com.android.ant;
|
package com.android.ant;
|
||||||
|
|
||||||
import com.android.sdklib.internal.project.ApkConfigurationHelper;
|
import com.android.sdklib.internal.project.ApkConfigurationHelper;
|
||||||
|
import com.android.sdklib.internal.project.ApkSettings;
|
||||||
import com.android.sdklib.internal.project.ProjectProperties;
|
import com.android.sdklib.internal.project.ProjectProperties;
|
||||||
import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
|
import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
|
||||||
|
|
||||||
@@ -28,7 +29,6 @@ import org.apache.tools.ant.types.Path;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,14 +133,17 @@ public final class AaptExecLoopTask extends Task {
|
|||||||
ProjectProperties properties = ProjectProperties.load(baseDir.getAbsolutePath(),
|
ProjectProperties properties = ProjectProperties.load(baseDir.getAbsolutePath(),
|
||||||
PropertyType.DEFAULT);
|
PropertyType.DEFAULT);
|
||||||
|
|
||||||
Map<String, String> apkConfigs = ApkConfigurationHelper.getConfigs(properties);
|
|
||||||
if (apkConfigs.size() > 0) {
|
ApkSettings apkSettings = ApkConfigurationHelper.getSettings(properties);
|
||||||
Set<Entry<String, String>> entrySet = apkConfigs.entrySet();
|
if (apkSettings != null) {
|
||||||
for (Entry<String, String> entry : entrySet) {
|
Map<String, String> apkFilters = apkSettings.getResourceFilters();
|
||||||
|
if (apkFilters.size() > 0) {
|
||||||
|
for (Entry<String, String> entry : apkFilters.entrySet()) {
|
||||||
createPackage(entry.getKey(), entry.getValue());
|
createPackage(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a resource package.
|
* Creates a resource package.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.android.apkbuilder.ApkBuilder.ApkCreationException;
|
|||||||
import com.android.apkbuilder.internal.ApkBuilderImpl;
|
import com.android.apkbuilder.internal.ApkBuilderImpl;
|
||||||
import com.android.apkbuilder.internal.ApkBuilderImpl.ApkFile;
|
import com.android.apkbuilder.internal.ApkBuilderImpl.ApkFile;
|
||||||
import com.android.sdklib.internal.project.ApkConfigurationHelper;
|
import com.android.sdklib.internal.project.ApkConfigurationHelper;
|
||||||
|
import com.android.sdklib.internal.project.ApkSettings;
|
||||||
import com.android.sdklib.internal.project.ProjectProperties;
|
import com.android.sdklib.internal.project.ProjectProperties;
|
||||||
import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
|
import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
|
||||||
|
|
||||||
@@ -35,7 +36,6 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
public class ApkBuilderTask extends Task {
|
public class ApkBuilderTask extends Task {
|
||||||
@@ -214,13 +214,15 @@ public class ApkBuilderTask extends Task {
|
|||||||
ProjectProperties properties = ProjectProperties.load(baseDir.getAbsolutePath(),
|
ProjectProperties properties = ProjectProperties.load(baseDir.getAbsolutePath(),
|
||||||
PropertyType.DEFAULT);
|
PropertyType.DEFAULT);
|
||||||
|
|
||||||
Map<String, String> apkConfigs = ApkConfigurationHelper.getConfigs(properties);
|
ApkSettings apkSettings = ApkConfigurationHelper.getSettings(properties);
|
||||||
if (apkConfigs.size() > 0) {
|
if (apkSettings != null) {
|
||||||
Set<Entry<String, String>> entrySet = apkConfigs.entrySet();
|
Map<String, String> apkFilters = apkSettings.getResourceFilters();
|
||||||
for (Entry<String, String> entry : entrySet) {
|
if (apkFilters.size() > 0) {
|
||||||
|
for (Entry<String, String> entry : apkFilters.entrySet()) {
|
||||||
createApk(apkBuilder, entry.getKey(), entry.getValue(), path);
|
createApk(apkBuilder, entry.getKey(), entry.getValue(), path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// finally sets the path in the project with a reference
|
// finally sets the path in the project with a reference
|
||||||
antProject.addReference(REF_APK_PATH, path);
|
antProject.addReference(REF_APK_PATH, path);
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import com.android.jarutils.SignedJarBuilder.IZipEntryFilter;
|
|||||||
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdklib.SdkConstants;
|
import com.android.sdklib.SdkConstants;
|
||||||
|
import com.android.sdklib.internal.project.ApkSettings;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IContainer;
|
import org.eclipse.core.resources.IContainer;
|
||||||
import org.eclipse.core.resources.IFile;
|
import org.eclipse.core.resources.IFile;
|
||||||
@@ -303,11 +304,15 @@ public class ApkBuilder extends BaseBuilder {
|
|||||||
return referencedProjects;
|
return referencedProjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the extra configs for the project.
|
// get the APK configs for the project.
|
||||||
// The map contains (name, filter) where 'name' is a name to be used in the apk filename,
|
ApkSettings apkSettings = Sdk.getCurrent().getApkSettings(project);
|
||||||
// and filter is the resource filter to be used in the aapt -c parameters to restrict
|
Set<Entry<String, String>> apkfilters = null;
|
||||||
// which resource configurations to package in the apk.
|
if (apkSettings != null) {
|
||||||
Map<String, String> configs = Sdk.getCurrent().getProjectApkConfigs(project);
|
Map<String, String> filterMap = apkSettings.getResourceFilters();
|
||||||
|
if (filterMap != null && filterMap.size() > 0) {
|
||||||
|
apkfilters = filterMap.entrySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// do some extra check, in case the output files are not present. This
|
// do some extra check, in case the output files are not present. This
|
||||||
// will force to recreate them.
|
// will force to recreate them.
|
||||||
@@ -320,19 +325,20 @@ public class ApkBuilder extends BaseBuilder {
|
|||||||
mPackageResources = true;
|
mPackageResources = true;
|
||||||
mBuildFinalPackage = true;
|
mBuildFinalPackage = true;
|
||||||
} else {
|
} else {
|
||||||
// if the full package is present, we check the filtered resource packages as well
|
// if the full package is present, we check the filtered resource packages
|
||||||
if (configs != null) {
|
// as well
|
||||||
Set<Entry<String, String>> entrySet = configs.entrySet();
|
if (apkfilters != null) {
|
||||||
|
for (Entry<String, String> entry : apkfilters) {
|
||||||
for (Entry<String, String> entry : entrySet) {
|
|
||||||
String filename = String.format(AndroidConstants.FN_RESOURCES_S_AP_,
|
String filename = String.format(AndroidConstants.FN_RESOURCES_S_AP_,
|
||||||
entry.getKey());
|
entry.getKey());
|
||||||
|
|
||||||
tmp = outputFolder.findMember(filename);
|
tmp = outputFolder.findMember(filename);
|
||||||
if (tmp == null || (tmp instanceof IFile &&
|
if (tmp == null || (tmp instanceof IFile &&
|
||||||
tmp.exists() == false)) {
|
tmp.exists() == false)) {
|
||||||
String msg = String.format(Messages.s_Missing_Repackaging, filename);
|
String msg = String.format(Messages.s_Missing_Repackaging,
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
|
filename);
|
||||||
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE,
|
||||||
|
project, msg);
|
||||||
mPackageResources = true;
|
mPackageResources = true;
|
||||||
mBuildFinalPackage = true;
|
mBuildFinalPackage = true;
|
||||||
break;
|
break;
|
||||||
@@ -360,11 +366,9 @@ public class ApkBuilder extends BaseBuilder {
|
|||||||
String msg = String.format(Messages.s_Missing_Repackaging, finalPackageName);
|
String msg = String.format(Messages.s_Missing_Repackaging, finalPackageName);
|
||||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
|
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
|
||||||
mBuildFinalPackage = true;
|
mBuildFinalPackage = true;
|
||||||
} else if (configs != null) {
|
} else if (apkfilters != null) {
|
||||||
// if the full apk is present, we check the filtered apk as well
|
// if the full apk is present, we check the filtered apk as well
|
||||||
Set<Entry<String, String>> entrySet = configs.entrySet();
|
for (Entry<String, String> entry : apkfilters) {
|
||||||
|
|
||||||
for (Entry<String, String> entry : entrySet) {
|
|
||||||
String filename = ProjectHelper.getApkFilename(project, entry.getKey());
|
String filename = ProjectHelper.getApkFilename(project, entry.getKey());
|
||||||
|
|
||||||
tmp = outputFolder.findMember(filename);
|
tmp = outputFolder.findMember(filename);
|
||||||
@@ -411,9 +415,8 @@ public class ApkBuilder extends BaseBuilder {
|
|||||||
// notified.
|
// notified.
|
||||||
finalPackage.delete();
|
finalPackage.delete();
|
||||||
|
|
||||||
if (configs != null) {
|
if (apkfilters != null) {
|
||||||
Set<Entry<String, String>> entrySet = configs.entrySet();
|
for (Entry<String, String> entry : apkfilters) {
|
||||||
for (Entry<String, String> entry : entrySet) {
|
|
||||||
String packageFilepath = osBinPath + File.separator +
|
String packageFilepath = osBinPath + File.separator +
|
||||||
ProjectHelper.getApkFilename(project, entry.getKey());
|
ProjectHelper.getApkFilename(project, entry.getKey());
|
||||||
|
|
||||||
@@ -477,9 +480,8 @@ public class ApkBuilder extends BaseBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now do the same thing for all the configured resource packages.
|
// now do the same thing for all the configured resource packages.
|
||||||
if (configs != null) {
|
if (apkfilters != null) {
|
||||||
Set<Entry<String, String>> entrySet = configs.entrySet();
|
for (Entry<String, String> entry : apkfilters) {
|
||||||
for (Entry<String, String> entry : entrySet) {
|
|
||||||
String outPathFormat = osBinPath + File.separator +
|
String outPathFormat = osBinPath + File.separator +
|
||||||
AndroidConstants.FN_RESOURCES_S_AP_;
|
AndroidConstants.FN_RESOURCES_S_AP_;
|
||||||
String outPath = String.format(outPathFormat, entry.getKey());
|
String outPath = String.format(outPathFormat, entry.getKey());
|
||||||
@@ -527,12 +529,11 @@ public class ApkBuilder extends BaseBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now do the same thing for all the configured resource packages.
|
// now do the same thing for all the configured resource packages.
|
||||||
if (configs != null) {
|
if (apkfilters != null) {
|
||||||
String resPathFormat = osBinPath + File.separator +
|
String resPathFormat = osBinPath + File.separator +
|
||||||
AndroidConstants.FN_RESOURCES_S_AP_;
|
AndroidConstants.FN_RESOURCES_S_AP_;
|
||||||
|
|
||||||
Set<Entry<String, String>> entrySet = configs.entrySet();
|
for (Entry<String, String> entry : apkfilters) {
|
||||||
for (Entry<String, String> entry : entrySet) {
|
|
||||||
// make the filename for the resource package.
|
// make the filename for the resource package.
|
||||||
String resPath = String.format(resPathFormat, entry.getKey());
|
String resPath = String.format(resPathFormat, entry.getKey());
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ package com.android.ide.eclipse.adt.internal.properties;
|
|||||||
|
|
||||||
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
||||||
import com.android.sdklib.IAndroidTarget;
|
import com.android.sdklib.IAndroidTarget;
|
||||||
import com.android.sdkuilib.internal.widgets.ApkConfigWidget;
|
import com.android.sdklib.internal.project.ApkSettings;
|
||||||
import com.android.sdkuilib.internal.widgets.SdkTargetSelector;
|
import com.android.sdkuilib.internal.widgets.SdkTargetSelector;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
@@ -27,14 +27,14 @@ import org.eclipse.swt.events.SelectionAdapter;
|
|||||||
import org.eclipse.swt.events.SelectionEvent;
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
|
import org.eclipse.swt.widgets.Button;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Control;
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
import org.eclipse.swt.widgets.Group;
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
import org.eclipse.ui.IWorkbenchPropertyPage;
|
import org.eclipse.ui.IWorkbenchPropertyPage;
|
||||||
import org.eclipse.ui.dialogs.PropertyPage;
|
import org.eclipse.ui.dialogs.PropertyPage;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property page for "Android" project.
|
* Property page for "Android" project.
|
||||||
* This is accessible from the Package Explorer when right clicking a project and choosing
|
* This is accessible from the Package Explorer when right clicking a project and choosing
|
||||||
@@ -45,7 +45,7 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
|
|||||||
|
|
||||||
private IProject mProject;
|
private IProject mProject;
|
||||||
private SdkTargetSelector mSelector;
|
private SdkTargetSelector mSelector;
|
||||||
private ApkConfigWidget mApkConfigWidget;
|
private Button mSplitByDensity;
|
||||||
|
|
||||||
public AndroidPropertyPage() {
|
public AndroidPropertyPage() {
|
||||||
// pass
|
// pass
|
||||||
@@ -72,13 +72,13 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
|
|||||||
|
|
||||||
mSelector = new SdkTargetSelector(top, targets);
|
mSelector = new SdkTargetSelector(top, targets);
|
||||||
|
|
||||||
l = new Label(top, SWT.SEPARATOR | SWT.HORIZONTAL);
|
Group g = new Group(top, SWT.NONE);
|
||||||
l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
g.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||||
|
g.setLayout(new GridLayout(1, false));
|
||||||
|
g.setText("APK Generation");
|
||||||
|
|
||||||
l = new Label(top, SWT.NONE);
|
mSplitByDensity = new Button(g, SWT.CHECK);
|
||||||
l.setText("Project APK Configurations");
|
mSplitByDensity.setText("One APK per density");
|
||||||
|
|
||||||
mApkConfigWidget = new ApkConfigWidget(top);
|
|
||||||
|
|
||||||
// fill the ui
|
// fill the ui
|
||||||
Sdk currentSdk = Sdk.getCurrent();
|
Sdk currentSdk = Sdk.getCurrent();
|
||||||
@@ -89,9 +89,9 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
|
|||||||
mSelector.setSelection(target);
|
mSelector.setSelection(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the apk configurations
|
// get the project settings
|
||||||
Map<String, String> configs = currentSdk.getProjectApkConfigs(mProject);
|
ApkSettings settings = currentSdk.getApkSettings(mProject);
|
||||||
mApkConfigWidget.fillTable(configs);
|
mSplitByDensity.setSelection(settings.isSplitByDpi());
|
||||||
}
|
}
|
||||||
|
|
||||||
mSelector.setSelectionListener(new SelectionAdapter() {
|
mSelector.setSelectionListener(new SelectionAdapter() {
|
||||||
@@ -114,8 +114,10 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
|
|||||||
public boolean performOk() {
|
public boolean performOk() {
|
||||||
Sdk currentSdk = Sdk.getCurrent();
|
Sdk currentSdk = Sdk.getCurrent();
|
||||||
if (currentSdk != null) {
|
if (currentSdk != null) {
|
||||||
currentSdk.setProject(mProject, mSelector.getSelected(),
|
ApkSettings apkSettings = new ApkSettings();
|
||||||
mApkConfigWidget.getApkConfigs());
|
apkSettings.setSplitByDensity(mSplitByDensity.getSelection());
|
||||||
|
|
||||||
|
currentSdk.setProject(mProject, mSelector.getSelected(), apkSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import com.android.sdklib.SdkConstants;
|
|||||||
import com.android.sdklib.SdkManager;
|
import com.android.sdklib.SdkManager;
|
||||||
import com.android.sdklib.internal.avd.AvdManager;
|
import com.android.sdklib.internal.avd.AvdManager;
|
||||||
import com.android.sdklib.internal.project.ApkConfigurationHelper;
|
import com.android.sdklib.internal.project.ApkConfigurationHelper;
|
||||||
|
import com.android.sdklib.internal.project.ApkSettings;
|
||||||
import com.android.sdklib.internal.project.ProjectProperties;
|
import com.android.sdklib.internal.project.ProjectProperties;
|
||||||
import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
|
import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
|
||||||
|
|
||||||
@@ -68,8 +69,8 @@ public class Sdk implements IProjectListener {
|
|||||||
new HashMap<IProject, IAndroidTarget>();
|
new HashMap<IProject, IAndroidTarget>();
|
||||||
private final HashMap<IAndroidTarget, AndroidTargetData> mTargetDataMap =
|
private final HashMap<IAndroidTarget, AndroidTargetData> mTargetDataMap =
|
||||||
new HashMap<IAndroidTarget, AndroidTargetData>();
|
new HashMap<IAndroidTarget, AndroidTargetData>();
|
||||||
private final HashMap<IProject, Map<String, String>> mProjectApkConfigMap =
|
private final HashMap<IProject, ApkSettings> mApkSettingsMap =
|
||||||
new HashMap<IProject, Map<String, String>>();
|
new HashMap<IProject, ApkSettings>();
|
||||||
private final String mDocBaseUrl;
|
private final String mDocBaseUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -193,11 +194,9 @@ public class Sdk implements IProjectListener {
|
|||||||
* apk configurations should not be updated.
|
* apk configurations should not be updated.
|
||||||
*/
|
*/
|
||||||
public void setProject(IProject project, IAndroidTarget target,
|
public void setProject(IProject project, IAndroidTarget target,
|
||||||
Map<String, String> apkConfigMap) {
|
ApkSettings settings) {
|
||||||
synchronized (AdtPlugin.getDefault().getSdkLockObject()) {
|
synchronized (AdtPlugin.getDefault().getSdkLockObject()) {
|
||||||
boolean resolveProject = false;
|
boolean resolveProject = false;
|
||||||
boolean compileProject = false;
|
|
||||||
boolean cleanProject = false;
|
|
||||||
|
|
||||||
ProjectProperties properties = ProjectProperties.load(
|
ProjectProperties properties = ProjectProperties.load(
|
||||||
project.getLocation().toOSString(), PropertyType.DEFAULT);
|
project.getLocation().toOSString(), PropertyType.DEFAULT);
|
||||||
@@ -222,15 +221,17 @@ public class Sdk implements IProjectListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apkConfigMap != null) {
|
// if there's no settings, force default values (to reset possibly changed
|
||||||
// save the apk configs in the project persistent property
|
// values in a previous call.
|
||||||
cleanProject = ApkConfigurationHelper.setConfigs(properties, apkConfigMap);
|
if (settings == null) {
|
||||||
|
settings = new ApkSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the project settings into the project persistent property
|
||||||
|
ApkConfigurationHelper.setProperties(properties, settings);
|
||||||
|
|
||||||
// put it in a local map for easy access.
|
// put it in a local map for easy access.
|
||||||
mProjectApkConfigMap.put(project, apkConfigMap);
|
mApkSettingsMap.put(project, settings);
|
||||||
|
|
||||||
compileProject = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we are done with the modification. Save the property file.
|
// we are done with the modification. Save the property file.
|
||||||
try {
|
try {
|
||||||
@@ -242,17 +243,14 @@ public class Sdk implements IProjectListener {
|
|||||||
|
|
||||||
if (resolveProject) {
|
if (resolveProject) {
|
||||||
// force a resolve of the project by updating the classpath container.
|
// force a resolve of the project by updating the classpath container.
|
||||||
|
// This will also force a recompile.
|
||||||
IJavaProject javaProject = JavaCore.create(project);
|
IJavaProject javaProject = JavaCore.create(project);
|
||||||
AndroidClasspathContainerInitializer.updateProjects(
|
AndroidClasspathContainerInitializer.updateProjects(
|
||||||
new IJavaProject[] { javaProject });
|
new IJavaProject[] { javaProject });
|
||||||
} else if (compileProject) {
|
} else {
|
||||||
// If there was removed configs, we clean instead of build
|
// always do a full clean/build.
|
||||||
// (to remove the obsolete ap_ and apk file from removed configs).
|
|
||||||
try {
|
try {
|
||||||
project.build(cleanProject ?
|
project.build(IncrementalProjectBuilder.CLEAN_BUILD, null);
|
||||||
IncrementalProjectBuilder.CLEAN_BUILD :
|
|
||||||
IncrementalProjectBuilder.FULL_BUILD,
|
|
||||||
null);
|
|
||||||
} catch (CoreException e) {
|
} catch (CoreException e) {
|
||||||
// failed to build? force resolve instead.
|
// failed to build? force resolve instead.
|
||||||
IJavaProject javaProject = JavaCore.create(project);
|
IJavaProject javaProject = JavaCore.create(project);
|
||||||
@@ -316,10 +314,10 @@ public class Sdk implements IProjectListener {
|
|||||||
|
|
||||||
if (sdkStorage != null) {
|
if (sdkStorage != null) {
|
||||||
synchronized (AdtPlugin.getDefault().getSdkLockObject()) {
|
synchronized (AdtPlugin.getDefault().getSdkLockObject()) {
|
||||||
Map<String, String> configMap = ApkConfigurationHelper.getConfigs(properties);
|
ApkSettings settings = ApkConfigurationHelper.getSettings(properties);
|
||||||
|
|
||||||
if (configMap != null) {
|
if (settings != null) {
|
||||||
sdkStorage.mProjectApkConfigMap.put(project, configMap);
|
sdkStorage.mApkSettingsMap.put(project, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -392,13 +390,11 @@ public class Sdk implements IProjectListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the configuration map for a given project.
|
* Returns the APK settings for a given project.
|
||||||
* <p/>The Map key are name to be used in the apk filename, while the values are comma separated
|
|
||||||
* config values. The config value can be passed directly to aapt through the -c option.
|
|
||||||
*/
|
*/
|
||||||
public Map<String, String> getProjectApkConfigs(IProject project) {
|
public ApkSettings getApkSettings(IProject project) {
|
||||||
synchronized (AdtPlugin.getDefault().getSdkLockObject()) {
|
synchronized (AdtPlugin.getDefault().getSdkLockObject()) {
|
||||||
return mProjectApkConfigMap.get(project);
|
return mApkSettingsMap.get(project);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +501,7 @@ public class Sdk implements IProjectListener {
|
|||||||
|
|
||||||
// now remove the project for the maps.
|
// now remove the project for the maps.
|
||||||
mProjectTargetMap.remove(project);
|
mProjectTargetMap.remove(project);
|
||||||
mProjectApkConfigMap.remove(project);
|
mApkSettingsMap.remove(project);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.android.ide.eclipse.adt.internal.wizards.export;
|
|||||||
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
|
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
|
||||||
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
|
||||||
import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage;
|
import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage;
|
||||||
|
import com.android.sdklib.internal.project.ApkSettings;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
@@ -68,10 +69,10 @@ final class KeyCheckPage extends ExportWizardPage {
|
|||||||
private Text mDestination;
|
private Text mDestination;
|
||||||
private boolean mFatalSigningError;
|
private boolean mFatalSigningError;
|
||||||
private FormText mDetailText;
|
private FormText mDetailText;
|
||||||
/** The Apk Config map for the current project */
|
|
||||||
private Map<String, String> mApkConfig;
|
|
||||||
private ScrolledComposite mScrolledComposite;
|
private ScrolledComposite mScrolledComposite;
|
||||||
|
|
||||||
|
private ApkSettings mApkSettings;
|
||||||
|
|
||||||
private String mKeyDetails;
|
private String mKeyDetails;
|
||||||
private String mDestinationDetails;
|
private String mDestinationDetails;
|
||||||
|
|
||||||
@@ -149,7 +150,7 @@ final class KeyCheckPage extends ExportWizardPage {
|
|||||||
if ((mProjectDataChanged & DATA_PROJECT) != 0) {
|
if ((mProjectDataChanged & DATA_PROJECT) != 0) {
|
||||||
// reset the destination from the content of the project
|
// reset the destination from the content of the project
|
||||||
IProject project = mWizard.getProject();
|
IProject project = mWizard.getProject();
|
||||||
mApkConfig = Sdk.getCurrent().getProjectApkConfigs(project);
|
mApkSettings = Sdk.getCurrent().getApkSettings(project);
|
||||||
|
|
||||||
String destination = ProjectHelper.loadStringProperty(project,
|
String destination = ProjectHelper.loadStringProperty(project,
|
||||||
ExportWizard.PROPERTY_DESTINATION);
|
ExportWizard.PROPERTY_DESTINATION);
|
||||||
@@ -391,7 +392,6 @@ final class KeyCheckPage extends ExportWizardPage {
|
|||||||
mDetailText.getParent().layout();
|
mDetailText.getParent().layout();
|
||||||
|
|
||||||
updateScrolling();
|
updateScrolling();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -415,21 +415,24 @@ final class KeyCheckPage extends ExportWizardPage {
|
|||||||
map.put(null, apkArray);
|
map.put(null, apkArray);
|
||||||
|
|
||||||
// add the APKs for each APK configuration.
|
// add the APKs for each APK configuration.
|
||||||
if (mApkConfig != null && mApkConfig.size() > 0) {
|
if (mApkSettings != null) {
|
||||||
// remove the extension.
|
Map<String, String> apkFilters = mApkSettings.getResourceFilters();
|
||||||
|
if (apkFilters.size() > 0) {
|
||||||
|
// remove the extension from the user-chosen filename
|
||||||
int index = filename.lastIndexOf('.');
|
int index = filename.lastIndexOf('.');
|
||||||
String base = filename.substring(0, index);
|
String base = filename.substring(0, index);
|
||||||
String extension = filename.substring(index);
|
String extension = filename.substring(index);
|
||||||
|
|
||||||
Set<Entry<String, String>> set = mApkConfig.entrySet();
|
for (Entry<String, String> entry : apkFilters.entrySet()) {
|
||||||
for (Entry<String, String> entry : set) {
|
|
||||||
apkArray = new String[ExportWizard.APK_COUNT];
|
apkArray = new String[ExportWizard.APK_COUNT];
|
||||||
apkArray[ExportWizard.APK_FILE_SOURCE] = ProjectHelper.getApkFilename(
|
apkArray[ExportWizard.APK_FILE_SOURCE] = ProjectHelper.getApkFilename(
|
||||||
mWizard.getProject(), entry.getKey());
|
mWizard.getProject(), entry.getKey());
|
||||||
apkArray[ExportWizard.APK_FILE_DEST] = base + "-" + entry.getKey() + extension;
|
apkArray[ExportWizard.APK_FILE_DEST] = base + "-" + //$NON-NLS-1$
|
||||||
|
entry.getKey() + extension;
|
||||||
map.put(entry.getKey(), apkArray);
|
map.put(entry.getKey(), apkArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,91 +16,33 @@
|
|||||||
|
|
||||||
package com.android.sdklib.internal.project;
|
package com.android.sdklib.internal.project;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to read and write Apk Configuration into a {@link ProjectProperties} file.
|
* Helper class to read and write Apk Configuration into a {@link ProjectProperties} file.
|
||||||
*/
|
*/
|
||||||
public class ApkConfigurationHelper {
|
public class ApkConfigurationHelper {
|
||||||
/** Prefix for property names for config definition. This prevents having config named
|
|
||||||
* after other valid properties such as "target". */
|
|
||||||
final static String CONFIG_PREFIX = "apk-config-";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the Apk Configurations from a {@link ProjectProperties} file and returns them as a map.
|
* Reads the project settings from a {@link ProjectProperties} file and returns them as a
|
||||||
* <p/>If there are no defined configurations, the returned map will be empty.
|
* {@link ApkSettings} object.
|
||||||
* @return a map of apk configurations. The map contains (name, filter) where name is
|
|
||||||
* the name of the configuration (a-zA-Z0-9 only), and filter is the comma separated list of
|
|
||||||
* resource configuration to include in the apk (see aapt -c)
|
|
||||||
*/
|
*/
|
||||||
public static Map<String, String> getConfigs(ProjectProperties properties) {
|
public static ApkSettings getSettings(ProjectProperties properties) {
|
||||||
HashMap<String, String> configMap = new HashMap<String, String>();
|
ApkSettings apkSettings = new ApkSettings();
|
||||||
|
|
||||||
// get the list of configs.
|
boolean splitByDensity = Boolean.parseBoolean(properties.getProperty(
|
||||||
String configList = properties.getProperty(ProjectProperties.PROPERTY_APK_CONFIGS);
|
ProjectProperties.PROPERTY_SPLIT_BY_DENSITY));
|
||||||
if (configList != null) {
|
apkSettings.setSplitByDensity(splitByDensity);
|
||||||
// this is a comma separated list
|
|
||||||
String[] configs = configList.split(","); //$NON-NLS-1$
|
|
||||||
|
|
||||||
// read the value of each config and store it in a map
|
|
||||||
for (String config : configs) {
|
|
||||||
config = config.trim();
|
|
||||||
String configValue = properties.getProperty(CONFIG_PREFIX + config);
|
|
||||||
if (configValue != null) {
|
|
||||||
configMap.put(config, configValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return configMap;
|
return apkSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the Apk Configurations from a given map into a {@link ProjectProperties}.
|
* Sets the content of a {@link ApkSettings} into a {@link ProjectProperties}.
|
||||||
* @param properties the {@link ProjectProperties} in which to store the apk configurations.
|
* @param properties the {@link ProjectProperties} in which to store the settings.
|
||||||
* @param configMap a map of apk configurations. The map contains (name, filter) where name is
|
* @param settings the project settings to store.
|
||||||
* the name of the configuration (a-zA-Z0-9 only), and filter is the comma separated list of
|
|
||||||
* resource configuration to include in the apk (see aapt -c)
|
|
||||||
* @return true if the {@link ProjectProperties} contained Apk Configuration that were not
|
|
||||||
* present in the map.
|
|
||||||
*/
|
*/
|
||||||
public static boolean setConfigs(ProjectProperties properties, Map<String, String> configMap) {
|
public static void setProperties(ProjectProperties properties, ApkSettings settings) {
|
||||||
// load the current configs, in order to remove the value properties for each of them
|
properties.setProperty(ProjectProperties.PROPERTY_SPLIT_BY_DENSITY,
|
||||||
// in case a config was removed.
|
Boolean.toString(settings.isSplitByDpi()));
|
||||||
|
|
||||||
// get the list of configs.
|
|
||||||
String configList = properties.getProperty(ProjectProperties.PROPERTY_APK_CONFIGS);
|
|
||||||
|
|
||||||
boolean hasRemovedConfig = false;
|
|
||||||
|
|
||||||
if (configList != null) {
|
|
||||||
// this is a comma separated list
|
|
||||||
String[] configs = configList.split(","); //$NON-NLS-1$
|
|
||||||
|
|
||||||
for (String config : configs) {
|
|
||||||
config = config.trim();
|
|
||||||
if (configMap.containsKey(config) == false) {
|
|
||||||
hasRemovedConfig = true;
|
|
||||||
properties.removeProperty(CONFIG_PREFIX + config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now add the properties.
|
|
||||||
Set<Entry<String, String>> entrySet = configMap.entrySet();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (Entry<String, String> entry : entrySet) {
|
|
||||||
if (sb.length() > 0) {
|
|
||||||
sb.append(",");
|
|
||||||
}
|
|
||||||
sb.append(entry.getKey());
|
|
||||||
properties.setProperty(CONFIG_PREFIX + entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
properties.setProperty(ProjectProperties.PROPERTY_APK_CONFIGS, sb.toString());
|
|
||||||
|
|
||||||
return hasRemovedConfig;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 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.sdklib.internal.project;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings for multiple APK generation.
|
||||||
|
*/
|
||||||
|
public class ApkSettings {
|
||||||
|
private boolean mSplitByDpi = false;
|
||||||
|
|
||||||
|
public ApkSettings() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a map of configuration filters to be used by the -c option of aapt.
|
||||||
|
* <p/>The map stores (key, value) pairs where the keys is a filename modifier and the value
|
||||||
|
* is the parameter to pass to aapt through the -c option.
|
||||||
|
* @return a map, always. It can however be empty.
|
||||||
|
*/
|
||||||
|
public Map<String, String> getResourceFilters() {
|
||||||
|
Map<String, String> map = new HashMap<String, String>();
|
||||||
|
if (mSplitByDpi) {
|
||||||
|
map.put("hdpi", "hdpi,nodpi");
|
||||||
|
map.put("mdpi", "mdpi,nodpi");
|
||||||
|
map.put("ldpi", "ldpi,nodpi");
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether APKs should be generate for each dpi level.
|
||||||
|
*/
|
||||||
|
public boolean isSplitByDpi() {
|
||||||
|
return mSplitByDpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSplitByDensity(boolean split) {
|
||||||
|
mSplitByDpi = split;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,14 +35,17 @@ import java.util.Map.Entry;
|
|||||||
public final class ProjectProperties {
|
public final class ProjectProperties {
|
||||||
/** The property name for the project target */
|
/** The property name for the project target */
|
||||||
public final static String PROPERTY_TARGET = "target";
|
public final static String PROPERTY_TARGET = "target";
|
||||||
public final static String PROPERTY_APK_CONFIGS = "apk.configurations";
|
|
||||||
public final static String PROPERTY_SDK = "sdk.dir";
|
public final static String PROPERTY_SDK = "sdk.dir";
|
||||||
// LEGACY - compatibility with 1.6 and before
|
// LEGACY - compatibility with 1.6 and before
|
||||||
public final static String PROPERTY_SDK_LEGACY = "sdk-location";
|
public final static String PROPERTY_SDK_LEGACY = "sdk-location";
|
||||||
|
|
||||||
public final static String PROPERTY_APP_PACKAGE = "application.package";
|
public final static String PROPERTY_APP_PACKAGE = "application.package";
|
||||||
// LEGACY - compatibility with 1.6 and before
|
// LEGACY - compatibility with 1.6 and before
|
||||||
public final static String PROPERTY_APP_PACKAGE_LEGACY = "application-package";
|
public final static String PROPERTY_APP_PACKAGE_LEGACY = "application-package";
|
||||||
|
|
||||||
|
public final static String PROPERTY_SPLIT_BY_DENSITY = "split.density";
|
||||||
|
|
||||||
public static enum PropertyType {
|
public static enum PropertyType {
|
||||||
BUILD("build.properties", BUILD_HEADER),
|
BUILD("build.properties", BUILD_HEADER),
|
||||||
DEFAULT("default.properties", DEFAULT_HEADER),
|
DEFAULT("default.properties", DEFAULT_HEADER),
|
||||||
@@ -107,17 +110,8 @@ public final class ProjectProperties {
|
|||||||
// 1-------10--------20--------30--------40--------50--------60--------70--------80
|
// 1-------10--------20--------30--------40--------50--------60--------70--------80
|
||||||
COMMENT_MAP.put(PROPERTY_TARGET,
|
COMMENT_MAP.put(PROPERTY_TARGET,
|
||||||
"# Project target.\n");
|
"# Project target.\n");
|
||||||
COMMENT_MAP.put(PROPERTY_APK_CONFIGS,
|
COMMENT_MAP.put(PROPERTY_SPLIT_BY_DENSITY,
|
||||||
"# apk configurations. This property allows creation of APK files with limited\n" +
|
"# Indicates whether an apk should be generated for each density.\n");
|
||||||
"# resources. For example, if your application contains many locales and\n" +
|
|
||||||
"# you wish to release multiple smaller apks instead of a large one, you can\n" +
|
|
||||||
"# define configuration to create apks with limited language sets.\n" +
|
|
||||||
"# Format is a comma separated list of configuration names. For each\n" +
|
|
||||||
"# configuration, a property will declare the resource configurations to\n" +
|
|
||||||
"# include. Example:\n" +
|
|
||||||
"# " + PROPERTY_APK_CONFIGS +"=european,northamerica\n" +
|
|
||||||
"# " + ApkConfigurationHelper.CONFIG_PREFIX + "european=en,fr,it,de,es\n" +
|
|
||||||
"# " + ApkConfigurationHelper.CONFIG_PREFIX + "northamerica=en,es\n");
|
|
||||||
COMMENT_MAP.put(PROPERTY_SDK,
|
COMMENT_MAP.put(PROPERTY_SDK,
|
||||||
"# location of the SDK. This is only used by Ant\n" +
|
"# location of the SDK. This is only used by Ant\n" +
|
||||||
"# For customization when using a Version Control System, please read the\n" +
|
"# For customization when using a Version Control System, please read the\n" +
|
||||||
|
|||||||
@@ -1,177 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 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.sdkuilib.internal.widgets;
|
|
||||||
|
|
||||||
import org.eclipse.jface.dialogs.Dialog;
|
|
||||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
|
||||||
import org.eclipse.jface.window.Window;
|
|
||||||
import org.eclipse.swt.SWT;
|
|
||||||
import org.eclipse.swt.events.ModifyEvent;
|
|
||||||
import org.eclipse.swt.events.ModifyListener;
|
|
||||||
import org.eclipse.swt.events.VerifyEvent;
|
|
||||||
import org.eclipse.swt.events.VerifyListener;
|
|
||||||
import org.eclipse.swt.layout.GridData;
|
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
|
||||||
import org.eclipse.swt.widgets.Button;
|
|
||||||
import org.eclipse.swt.widgets.Composite;
|
|
||||||
import org.eclipse.swt.widgets.Control;
|
|
||||||
import org.eclipse.swt.widgets.Label;
|
|
||||||
import org.eclipse.swt.widgets.Shell;
|
|
||||||
import org.eclipse.swt.widgets.Text;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit dialog to create/edit APK configuration. The dialog displays 2 text fields for the config
|
|
||||||
* name and its filter.
|
|
||||||
*/
|
|
||||||
class ApkConfigEditDialog extends Dialog implements ModifyListener, VerifyListener {
|
|
||||||
|
|
||||||
private String mName;
|
|
||||||
private String mFilter;
|
|
||||||
private Text mNameField;
|
|
||||||
private Text mFilterField;
|
|
||||||
private Button mOkButton;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an edit dialog with optional initial values for the name and filter.
|
|
||||||
* @param name optional value for the name. Can be null.
|
|
||||||
* @param filter optional value for the filter. Can be null.
|
|
||||||
* @param parentShell the parent shell.
|
|
||||||
*/
|
|
||||||
protected ApkConfigEditDialog(String name, String filter, Shell parentShell) {
|
|
||||||
super(parentShell);
|
|
||||||
mName = name;
|
|
||||||
mFilter = filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the config. This is only valid if the user clicked OK and {@link #open()}
|
|
||||||
* returned {@link Window#OK}
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the filter for the config. This is only valid if the user clicked OK and
|
|
||||||
* {@link #open()} returned {@link Window#OK}
|
|
||||||
*/
|
|
||||||
public String getFilter() {
|
|
||||||
return mFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Control createContents(Composite parent) {
|
|
||||||
Control control = super.createContents(parent);
|
|
||||||
|
|
||||||
mOkButton = getButton(IDialogConstants.OK_ID);
|
|
||||||
validateButtons();
|
|
||||||
|
|
||||||
return control;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Control createDialogArea(Composite parent) {
|
|
||||||
Composite composite = new Composite(parent, SWT.NONE);
|
|
||||||
GridLayout layout;
|
|
||||||
composite.setLayout(layout = new GridLayout(2, false));
|
|
||||||
layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
|
|
||||||
layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
|
|
||||||
layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
|
|
||||||
layout.horizontalSpacing = convertHorizontalDLUsToPixels(
|
|
||||||
IDialogConstants.HORIZONTAL_SPACING);
|
|
||||||
|
|
||||||
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
|
|
||||||
|
|
||||||
Label l = new Label(composite, SWT.NONE);
|
|
||||||
l.setText("Name");
|
|
||||||
|
|
||||||
mNameField = new Text(composite, SWT.BORDER);
|
|
||||||
mNameField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
|
||||||
mNameField.addVerifyListener(this);
|
|
||||||
if (mName != null) {
|
|
||||||
mNameField.setText(mName);
|
|
||||||
}
|
|
||||||
mNameField.addModifyListener(this);
|
|
||||||
|
|
||||||
l = new Label(composite, SWT.NONE);
|
|
||||||
l.setText("Filter");
|
|
||||||
|
|
||||||
mFilterField = new Text(composite, SWT.BORDER);
|
|
||||||
mFilterField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
|
||||||
if (mFilter != null) {
|
|
||||||
mFilterField.setText(mFilter);
|
|
||||||
}
|
|
||||||
mFilterField.addVerifyListener(this);
|
|
||||||
mFilterField.addModifyListener(this);
|
|
||||||
|
|
||||||
applyDialogFont(composite);
|
|
||||||
return composite;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the OK button based on the content of the 2 text fields.
|
|
||||||
*/
|
|
||||||
private void validateButtons() {
|
|
||||||
mOkButton.setEnabled(mNameField.getText().trim().length() > 0 &&
|
|
||||||
mFilterField.getText().trim().length() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void okPressed() {
|
|
||||||
mName = mNameField.getText();
|
|
||||||
mFilter = mFilterField.getText().trim();
|
|
||||||
super.okPressed();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for text modification in the 2 text fields.
|
|
||||||
*/
|
|
||||||
public void modifyText(ModifyEvent e) {
|
|
||||||
validateButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback to ensure the content of the text field are proper.
|
|
||||||
*/
|
|
||||||
public void verifyText(VerifyEvent e) {
|
|
||||||
Text source = ((Text)e.getSource());
|
|
||||||
if (source == mNameField) {
|
|
||||||
// check for a-zA-Z0-9.
|
|
||||||
final String text = e.text;
|
|
||||||
final int len = text.length();
|
|
||||||
for (int i = 0 ; i < len; i++) {
|
|
||||||
char letter = text.charAt(i);
|
|
||||||
if (letter > 255 || Character.isLetterOrDigit(letter) == false) {
|
|
||||||
e.doit = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (source == mFilterField) {
|
|
||||||
// we can't validate the content as its typed, but we can at least ensure the characters
|
|
||||||
// are valid. Same as mNameFiled + the comma.
|
|
||||||
final String text = e.text;
|
|
||||||
final int len = text.length();
|
|
||||||
for (int i = 0 ; i < len; i++) {
|
|
||||||
char letter = text.charAt(i);
|
|
||||||
if (letter > 255 || (Character.isLetterOrDigit(letter) == false && letter != ',')) {
|
|
||||||
e.doit = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 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.sdkuilib.internal.widgets;
|
|
||||||
|
|
||||||
import org.eclipse.jface.dialogs.Dialog;
|
|
||||||
import org.eclipse.jface.dialogs.MessageDialog;
|
|
||||||
import org.eclipse.swt.SWT;
|
|
||||||
import org.eclipse.swt.events.ControlAdapter;
|
|
||||||
import org.eclipse.swt.events.ControlEvent;
|
|
||||||
import org.eclipse.swt.events.SelectionAdapter;
|
|
||||||
import org.eclipse.swt.events.SelectionEvent;
|
|
||||||
import org.eclipse.swt.graphics.Rectangle;
|
|
||||||
import org.eclipse.swt.layout.GridData;
|
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
|
||||||
import org.eclipse.swt.widgets.Button;
|
|
||||||
import org.eclipse.swt.widgets.Composite;
|
|
||||||
import org.eclipse.swt.widgets.Table;
|
|
||||||
import org.eclipse.swt.widgets.TableColumn;
|
|
||||||
import org.eclipse.swt.widgets.TableItem;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The APK Configuration widget is a table that is added to the given parent composite.
|
|
||||||
* <p/>
|
|
||||||
* To use, create it using {@link #ApkConfigWidget(Composite)} then
|
|
||||||
* call {@link #fillTable(Map)} to set the initial list of configurations.
|
|
||||||
*/
|
|
||||||
public class ApkConfigWidget {
|
|
||||||
private final static int INDEX_NAME = 0;
|
|
||||||
private final static int INDEX_FILTER = 1;
|
|
||||||
|
|
||||||
private Table mApkConfigTable;
|
|
||||||
private Button mEditButton;
|
|
||||||
private Button mDelButton;
|
|
||||||
|
|
||||||
public ApkConfigWidget(final Composite parent) {
|
|
||||||
final Composite apkConfigComp = new Composite(parent, SWT.NONE);
|
|
||||||
apkConfigComp.setLayoutData(new GridData(GridData.FILL_BOTH));
|
|
||||||
apkConfigComp.setLayout(new GridLayout(2, false));
|
|
||||||
|
|
||||||
mApkConfigTable = new Table(apkConfigComp, SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER);
|
|
||||||
mApkConfigTable.setHeaderVisible(true);
|
|
||||||
mApkConfigTable.setLinesVisible(true);
|
|
||||||
|
|
||||||
GridData data = new GridData();
|
|
||||||
data.grabExcessVerticalSpace = true;
|
|
||||||
data.grabExcessHorizontalSpace = true;
|
|
||||||
data.horizontalAlignment = GridData.FILL;
|
|
||||||
data.verticalAlignment = GridData.FILL;
|
|
||||||
mApkConfigTable.setLayoutData(data);
|
|
||||||
|
|
||||||
// create the table columns
|
|
||||||
final TableColumn column0 = new TableColumn(mApkConfigTable, SWT.NONE);
|
|
||||||
column0.setText("Name");
|
|
||||||
column0.setWidth(100);
|
|
||||||
final TableColumn column1 = new TableColumn(mApkConfigTable, SWT.NONE);
|
|
||||||
column1.setText("Configuration");
|
|
||||||
column1.setWidth(100);
|
|
||||||
|
|
||||||
Composite buttonComp = new Composite(apkConfigComp, SWT.NONE);
|
|
||||||
buttonComp.setLayoutData(new GridData(GridData.FILL_VERTICAL));
|
|
||||||
GridLayout gl;
|
|
||||||
buttonComp.setLayout(gl = new GridLayout(1, false));
|
|
||||||
gl.marginHeight = gl.marginWidth = 0;
|
|
||||||
|
|
||||||
Button newButton = new Button(buttonComp, SWT.PUSH | SWT.FLAT);
|
|
||||||
newButton.setText("New...");
|
|
||||||
newButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
|
||||||
|
|
||||||
mEditButton = new Button(buttonComp, SWT.PUSH | SWT.FLAT);
|
|
||||||
mEditButton.setText("Edit...");
|
|
||||||
mEditButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
|
||||||
|
|
||||||
mDelButton = new Button(buttonComp, SWT.PUSH | SWT.FLAT);
|
|
||||||
mDelButton.setText("Delete");
|
|
||||||
mDelButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
|
||||||
|
|
||||||
newButton.addSelectionListener(new SelectionAdapter() {
|
|
||||||
@Override
|
|
||||||
public void widgetSelected(SelectionEvent e) {
|
|
||||||
ApkConfigEditDialog dlg = new ApkConfigEditDialog(null /*name*/, null /*filter*/,
|
|
||||||
apkConfigComp.getShell());
|
|
||||||
if (dlg.open() == Dialog.OK) {
|
|
||||||
TableItem item = new TableItem(mApkConfigTable, SWT.NONE);
|
|
||||||
item.setText(INDEX_NAME, dlg.getName());
|
|
||||||
item.setText(INDEX_FILTER, dlg.getFilter());
|
|
||||||
|
|
||||||
onSelectionChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mEditButton.addSelectionListener(new SelectionAdapter() {
|
|
||||||
@Override
|
|
||||||
public void widgetSelected(SelectionEvent e) {
|
|
||||||
// get the current selection (single mode so we don't care about any item beyond
|
|
||||||
// index 0).
|
|
||||||
TableItem[] items = mApkConfigTable.getSelection();
|
|
||||||
if (items.length != 0) {
|
|
||||||
ApkConfigEditDialog dlg = new ApkConfigEditDialog(
|
|
||||||
items[0].getText(INDEX_NAME), items[0].getText(INDEX_FILTER),
|
|
||||||
apkConfigComp.getShell());
|
|
||||||
if (dlg.open() == Dialog.OK) {
|
|
||||||
items[0].setText(INDEX_NAME, dlg.getName());
|
|
||||||
items[0].setText(INDEX_FILTER, dlg.getFilter());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mDelButton.addSelectionListener(new SelectionAdapter() {
|
|
||||||
@Override
|
|
||||||
public void widgetSelected(SelectionEvent e) {
|
|
||||||
// get the current selection (single mode so we don't care about any item beyond
|
|
||||||
// index 0).
|
|
||||||
int[] indices = mApkConfigTable.getSelectionIndices();
|
|
||||||
if (indices.length != 0) {
|
|
||||||
TableItem item = mApkConfigTable.getItem(indices[0]);
|
|
||||||
if (MessageDialog.openQuestion(parent.getShell(),
|
|
||||||
"Apk Configuration deletion",
|
|
||||||
String.format(
|
|
||||||
"Are you sure you want to delete configuration '%1$s'?",
|
|
||||||
item.getText(INDEX_NAME)))) {
|
|
||||||
// delete the item.
|
|
||||||
mApkConfigTable.remove(indices[0]);
|
|
||||||
|
|
||||||
onSelectionChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add a listener to resize the column to the full width of the table
|
|
||||||
mApkConfigTable.addControlListener(new ControlAdapter() {
|
|
||||||
@Override
|
|
||||||
public void controlResized(ControlEvent e) {
|
|
||||||
Rectangle r = mApkConfigTable.getClientArea();
|
|
||||||
column0.setWidth(r.width * 30 / 100); // 30%
|
|
||||||
column1.setWidth(r.width * 70 / 100); // 70%
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// add a selection listener on the table, to enable/disable buttons.
|
|
||||||
mApkConfigTable.addSelectionListener(new SelectionAdapter() {
|
|
||||||
@Override
|
|
||||||
public void widgetSelected(SelectionEvent e) {
|
|
||||||
onSelectionChanged();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fillTable(Map<String, String> apkConfigMap) {
|
|
||||||
// get the names in a list so that we can sort them.
|
|
||||||
if (apkConfigMap != null) {
|
|
||||||
Set<String> keys = apkConfigMap.keySet();
|
|
||||||
String[] keyArray = keys.toArray(new String[keys.size()]);
|
|
||||||
Arrays.sort(keyArray);
|
|
||||||
|
|
||||||
for (String key : keyArray) {
|
|
||||||
TableItem item = new TableItem(mApkConfigTable, SWT.NONE);
|
|
||||||
item.setText(INDEX_NAME, key);
|
|
||||||
item.setText(INDEX_FILTER, apkConfigMap.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onSelectionChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getApkConfigs() {
|
|
||||||
// go through all the items from the table and fill a new map
|
|
||||||
HashMap<String, String> map = new HashMap<String, String>();
|
|
||||||
|
|
||||||
TableItem[] items = mApkConfigTable.getItems();
|
|
||||||
for (TableItem item : items) {
|
|
||||||
map.put(item.getText(INDEX_NAME), item.getText(INDEX_FILTER));
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles table selection changes.
|
|
||||||
*/
|
|
||||||
private void onSelectionChanged() {
|
|
||||||
if (mApkConfigTable.getSelectionCount() > 0) {
|
|
||||||
mEditButton.setEnabled(true);
|
|
||||||
mDelButton.setEnabled(true);
|
|
||||||
} else {
|
|
||||||
mEditButton.setEnabled(false);
|
|
||||||
mDelButton.setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user