Skip to content
This repository has been archived by the owner on Oct 27, 2022. It is now read-only.

Commit

Permalink
BUG JBIDE-16213 - Prohibit deployments to AVDs and devices that do not
Browse files Browse the repository at this point in the history
support the minimum SDK version

Enhances the AVD info parsed so that we also have the API level as part
of the AVD information. This introduces the AndroidAVD.java class. Makes
changes to the AndroidLaunchDelegate so that minimum AVD is checked and
a proper exception is thrown. There is also a change on how the default
AVD is selected to account for API levels.

Also modifies the launch configuration UI to check the API level for the
selected AVD
  • Loading branch information
gorkem committed Feb 5, 2014
1 parent 3b911ed commit eaf9618
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 24 deletions.
Expand Up @@ -10,7 +10,8 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.resources;bundle-version="[3.8.1,4.0.0)",
org.eclipse.debug.core;bundle-version="[3.7.0,4.0.0)",
org.jboss.tools.aerogear.hybrid.cordova;bundle-version="2.7.0",
org.apache.commons.io;bundle-version="[2.0.0,2.1.0)"
org.apache.commons.io;bundle-version="[2.0.0,2.1.0)",
org.eclipse.osgi.util
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Export-Package: org.jboss.tools.aerogear.hybrid.android.core,
Expand Down
Expand Up @@ -12,6 +12,9 @@

public interface AndroidConstants {

public static final int REQUIRED_MIN_API_LEVEL = 17;


public static final String DIR_ASSETS = "assets";
public static final String DIR_LIBS = "libs";
public static final String DIR_RES = "res";
Expand All @@ -27,5 +30,7 @@ public interface AndroidConstants {
public static final String PREF_ANDROID_SDK_LOCATION = "Android_SDK_Loc";

public static final int STATUS_CODE_ANDROID_SDK_NOT_DEFINED= 200;
public static final int STATUS_CODE_ANDROID_AVD_NOT_DEFINED= 210;
public static final int STATUS_CODE_ANDROID_AVD_MIN_API_LEVEL= 220;

}
@@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright (c) 2013,2014 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.aerogear.hybrid.android.core.adt;


public class AndroidAVD {

private String name;
private int apiLevel;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getApiLevel() {
return apiLevel;
}
public void setApiLevel(int apiLevel) {
this.apiLevel = apiLevel;
}

}
Expand Up @@ -23,11 +23,14 @@
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.model.ILaunchConfigurationDelegate2;
import org.eclipse.osgi.util.NLS;
import org.jboss.tools.aerogear.hybrid.android.core.AndroidConstants;
import org.jboss.tools.aerogear.hybrid.android.core.AndroidCore;
import org.jboss.tools.aerogear.hybrid.core.HybridProject;
import org.jboss.tools.aerogear.hybrid.core.HybridProjectLaunchConfigConstants;
import org.jboss.tools.aerogear.hybrid.core.config.Widget;
import org.jboss.tools.aerogear.hybrid.core.config.WidgetModel;
import org.jboss.tools.aerogear.hybrid.core.internal.util.HybridMobileStatus;

public class AndroidLaunchDelegate implements ILaunchConfigurationDelegate2 {

Expand Down Expand Up @@ -126,14 +129,7 @@ public boolean preLaunchCheck(ILaunchConfiguration configuration,
if ( emulator == null ){
// No emulators lets start an emulator.
// Check if we have an AVD
List<String> avds = sdk.listAVDs();
if (avds == null || avds.isEmpty()){
throw new CoreException(new Status(IStatus.ERROR, AndroidCore.PLUGIN_ID, "No Android AVDs are available"));
}
String avdName = configuration.getAttribute(AndroidLaunchConstants.ATTR_AVD_NAME, (String)null);
if(avdName == null || !avds.contains(avdName)){
avdName = avds.get(0);
}
String avdName = selectAVD(configuration, sdk);
if(monitor.isCanceled()){
return false;
}
Expand All @@ -152,6 +148,37 @@ public boolean preLaunchCheck(ILaunchConfiguration configuration,
return true;
}

private String selectAVD(ILaunchConfiguration configuration, AndroidSDKManager sdk) throws CoreException{
List<AndroidAVD> avds = sdk.listAVDs();
if (avds == null || avds.isEmpty()){
throw new CoreException(new HybridMobileStatus(IStatus.ERROR, AndroidCore.PLUGIN_ID, AndroidConstants.STATUS_CODE_ANDROID_AVD_NOT_DEFINED,
"No Android AVDs are available",null));
}
String avdName = configuration.getAttribute(AndroidLaunchConstants.ATTR_AVD_NAME, (String)null);
for (AndroidAVD androidAVD : avds) {
if(avdName == null ){
if(androidAVD.getApiLevel() >= AndroidConstants.REQUIRED_MIN_API_LEVEL){
avdName = androidAVD.getName();
break;
}
}
else if(androidAVD.getName().equals(avdName)){
if(androidAVD.getApiLevel() < AndroidConstants.REQUIRED_MIN_API_LEVEL){
throw new CoreException(new HybridMobileStatus(IStatus.ERROR, AndroidCore.PLUGIN_ID, AndroidConstants.STATUS_CODE_ANDROID_AVD_MIN_API_LEVEL,
NLS.bind("Selected Android AVD {0} does not satisfy the satisfy the minimum API level({1})",
new String[]{avdName, Integer.toString(AndroidConstants.REQUIRED_MIN_API_LEVEL)}),null));

}
}

}
if(avdName == null ){
throw new CoreException(new HybridMobileStatus(IStatus.ERROR, AndroidCore.PLUGIN_ID, AndroidConstants.STATUS_CODE_ANDROID_AVD_NOT_DEFINED,
NLS.bind("None of the defined Android AVDs satisfy the minimum API level({0})",AndroidConstants.REQUIRED_MIN_API_LEVEL),null));
}
return avdName;
}

private AndroidDevice getEmulator() throws CoreException{
AndroidSDKManager sdk = AndroidSDKManager.getManager();
List<AndroidDevice> devices = sdk.listDevices();
Expand Down
Expand Up @@ -19,13 +19,13 @@
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.jboss.tools.aerogear.hybrid.android.core.AndroidConstants;
import org.jboss.tools.aerogear.hybrid.android.core.AndroidCore;
import org.jboss.tools.aerogear.hybrid.core.platform.PlatformConstants;

public class AndroidProjectUtils {

private static final int REQUIRED_MIN_API_LEVEL = 17;



public static File getPlatformWWWDirectory(File projectDirectory) {
Assert.isNotNull(projectDirectory);
Expand All @@ -51,14 +51,14 @@ public static AndroidSDK selectBestValidTarget() throws CoreException {
}
AndroidSDK target = null;
for (AndroidSDK androidSDK : targets) {
if(androidSDK.getApiLevel() >= REQUIRED_MIN_API_LEVEL &&
if(androidSDK.getApiLevel() >= AndroidConstants.REQUIRED_MIN_API_LEVEL &&
(target == null || androidSDK.getApiLevel() > target.getApiLevel())){
target = androidSDK;
}
}
if( target == null ){
throw new CoreException(new Status(IStatus.ERROR, AndroidCore.PLUGIN_ID,
"Please install Android API " +REQUIRED_MIN_API_LEVEL +" or later. Use the Android SDK Manager to install or upgrade any missing SDKs to tools."));
"Please install Android API " +AndroidConstants.REQUIRED_MIN_API_LEVEL +" or later. Use the Android SDK Manager to install or upgrade any missing SDKs to tools."));
}
return target;
}
Expand Down
Expand Up @@ -40,5 +40,21 @@ public void setApiLevel(int apiLevel) {
this.apiLevel = apiLevel;
}

@Override
public boolean equals(Object obj) {
if( obj == null ) return false;
if( obj == this ) return true;
if( obj instanceof AndroidSDK) {
AndroidSDK that = (AndroidSDK)obj;
return that.getId().equals(this.getId());
}
return false;
}

@Override
public int hashCode() {
return this.getId().hashCode();
}


}
Expand Up @@ -101,25 +101,39 @@ else if("offline".equals(values[1].trim())){

private static class AVDListParser implements IStreamListener{
private static final String PREFIX_NAME = "Name:";
private static final String PREFIX_TARGET = "Target:";
private static final String MARKER_LEVEL = "level";
private StringBuffer buffer = new StringBuffer();
@Override
public void streamAppended(String text, IStreamMonitor monitor) {
buffer.append(text);
}

public List<String> getAVDList(){
public List<AndroidAVD> getAVDList(){
if (buffer == null || buffer.length() < 1)
return null;

StringReader reader = new StringReader(buffer.toString());
BufferedReader read = new BufferedReader(reader);
String line =null;
ArrayList<String> list = new ArrayList<String>();
ArrayList<AndroidAVD> list = new ArrayList<AndroidAVD>();
try{
AndroidAVD currentAVD = null;
while ((line = read.readLine()) != null) {

int idx = line.indexOf(PREFIX_NAME);
if(idx > -1){
list.add(line.substring(idx+PREFIX_NAME.length()).trim());
currentAVD = new AndroidAVD();
currentAVD.setName(line.substring(idx+PREFIX_NAME.length()).trim());
continue;
}
idx = line.indexOf(PREFIX_TARGET);
if(idx>-1 && currentAVD != null){
int startIndex = line.indexOf(MARKER_LEVEL) + MARKER_LEVEL.length();
int endIndex = line.indexOf(')');
currentAVD.setApiLevel((Integer.parseInt(line.substring(startIndex, endIndex).trim())));
list.add(currentAVD);
currentAVD = null;
}
}
}
Expand Down Expand Up @@ -172,7 +186,7 @@ public List<AndroidSDK> getSDKList() {
sdkList.add(sdk);
int vIndex = pair[1].indexOf("or");
sdk.setId(pair[1].substring(vIndex + "or".length())
.replace("\"", ""));
.replace("\"", "").trim());
} else if ("Type".equalsIgnoreCase(pair[0])) {
Assert.isNotNull(sdk);
sdk.setType(pair[1].trim());
Expand Down Expand Up @@ -324,7 +338,7 @@ public void killADBServer() throws CoreException{
processUtility.execSync(getADBCommand()+" kill-server",null, null, null, new NullProgressMonitor(), null, null);
}

public List<String> listAVDs() throws CoreException{
public List<AndroidAVD> listAVDs() throws CoreException{
ExternalProcessUtility processUtility = new ExternalProcessUtility();
AVDListParser parser = new AVDListParser();
processUtility.execSync(getAndroidCommand()+" list avd", null, parser, parser,
Expand Down
Expand Up @@ -37,6 +37,8 @@
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.jboss.tools.aerogear.hybrid.android.core.AndroidConstants;
import org.jboss.tools.aerogear.hybrid.android.core.adt.AndroidAVD;
import org.jboss.tools.aerogear.hybrid.android.core.adt.AndroidSDKManager;
import org.jboss.tools.aerogear.hybrid.core.HybridCore;
import org.jboss.tools.aerogear.hybrid.core.HybridProject;
Expand All @@ -47,6 +49,7 @@ public class AndroidSimOptionsTab extends AbstractLaunchConfigurationTab {
private Text logFilterTxt;
private Listener dirtyListener;
private Combo AVDCombo;
private List<AndroidAVD> avds;

private class DirtyListener implements Listener{
@Override
Expand Down Expand Up @@ -106,10 +109,11 @@ public void widgetSelected(SelectionEvent e) {
lblVirtualDeviceavd.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
lblVirtualDeviceavd.setText("Virtual Device (AVD):");

AVDCombo = new Combo(grpEmulator, SWT.NONE);
AVDCombo = new Combo(grpEmulator, SWT.READ_ONLY);
AVDCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
AVDCombo.add("", 0);
AVDCombo.addListener(SWT.Selection, dirtyListener);



Label lblLogFilter = new Label(grpEmulator, SWT.NONE);
Expand All @@ -121,9 +125,9 @@ public void widgetSelected(SelectionEvent e) {
logFilterTxt.addListener(SWT.Modify, dirtyListener);
try {
AndroidSDKManager sdk = AndroidSDKManager.getManager();
List<String> avds = sdk.listAVDs();
for (String string : avds) {
AVDCombo.add(string);
avds = sdk.listAVDs();
for (AndroidAVD avd : avds) {
AVDCombo.add(avd.getName());
}
} catch (CoreException e1) {
AVDCombo.removeAll();// let it fallback to default
Expand Down Expand Up @@ -177,9 +181,10 @@ public void initializeFrom(ILaunchConfiguration configuration) {
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
configuration.setAttribute(HybridProjectLaunchConfigConstants.ATTR_BUILD_SCOPE, textProject.getText());
String avd = AVDCombo.getText();
if (avd != null && !avd.isEmpty()){
configuration.setAttribute(ATTR_AVD_NAME, avd);
if(avd != null && avd.isEmpty()){
avd = null;
}
configuration.setAttribute(ATTR_AVD_NAME, avd);
configuration.setAttribute(ATTR_LOGCAT_FILTER, logFilterTxt.getText());
}

Expand All @@ -191,6 +196,18 @@ public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {

@Override
public boolean isValid(ILaunchConfiguration launchConfig) {
setMessage(null);
setErrorMessage(null);
String avd = AVDCombo.getText();
if(avd != null && !avd.isEmpty()){
for (AndroidAVD androidAVD : avds) {
if(androidAVD.getName().equals(avd)
&& androidAVD.getApiLevel() < AndroidConstants.REQUIRED_MIN_API_LEVEL){
setErrorMessage("Selected AVD does not satisfy the minimum required API level. Please select a different one");
return false;
}
}
}
if(SDKLocationHelper.isSDKLocationDefined())
return super.isValid(launchConfig);
return false;
Expand Down

0 comments on commit eaf9618

Please sign in to comment.