1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.motorola.studio.android.model; 17 18 import java.io.File; 19 import java.util.ArrayList; 20 import java.util.List; 21 import java.util.regex.Matcher; 22 import java.util.regex.Pattern; 23 24 import org.eclipse.core.resources.IProject; 25 import org.eclipse.core.resources.IResource; 26 import org.eclipse.core.resources.IWorkspace; 27 import org.eclipse.core.resources.ResourcesPlugin; 28 import org.eclipse.core.runtime.IProgressMonitor; 29 import org.eclipse.core.runtime.IStatus; 30 import org.eclipse.core.runtime.Path; 31 import org.eclipse.core.runtime.Platform; 32 import org.eclipse.core.runtime.Status; 33 import org.eclipse.jdt.core.JavaConventions; 34 import org.eclipse.jface.wizard.IWizardContainer; 35 import org.eclipse.osgi.util.NLS; 36 37 import com.android.sdklib.IAndroidTarget; 38 import com.motorola.studio.android.AndroidPlugin; 39 import com.motorola.studio.android.adt.Sample; 40 import com.motorola.studio.android.adt.SdkUtils; 41 import com.motorola.studio.android.common.IAndroidConstants; 42 import com.motorola.studio.android.common.exception.AndroidException; 43 import com.motorola.studio.android.common.utilities.AndroidStatus; 44 import com.motorola.studio.android.common.utilities.EclipseUtils; 45 import com.motorola.studio.android.i18n.AndroidNLS; 46 47 /** 48 * Class that implements the model for the new project wizard 49 */ 50 public class AndroidProject implements IWizardModel 51 { 52 private static final IWorkspace WORKSPACE = ResourcesPlugin.getWorkspace(); 53 54 private static final String SDK_VERSION = "1.5"; //$NON-NLS-1$ 55 56 private static final String BIN_FOLDER = "bin"; //$NON-NLS-1$ 57 58 private static final String CLASS_EXTENSION = ".class"; //$NON-NLS-1$ 59 60 private static final String R_DRAWABLE_CLASS = "R$drawable" + CLASS_EXTENSION; //$NON-NLS-1$ 61 62 private static final String SETTINGS_FOLDER = ".settings"; //$NON-NLS-1$ 63 64 private static final String SETTINGS_FILE = "org.eclipse.core.resources.prefs"; //$NON-NLS-1$ 65 66 public static final String ANDROID_NATURE = "com.android.ide.eclipse.adt.AndroidNature"; //$NON-NLS-1$ 67 68 private static final int MAX_PATH_LENGTH = 255; 69 70 /** 71 * Represents the Type of new Projects 72 */ 73 public static enum SourceTypes 74 { 75 SAMPLE, EXISTING, NEW, WIDGET 76 }; 77 78 /* 79 * (non-Javadoc) 80 * 81 * @see java.lang.Object#finalize() 82 */ 83 @Override 84 public void finalize() throws Throwable 85 { 86 if (listener != null) 87 { 88 AndroidPlugin.getDefault().removeSDKLoaderListener(listener); 89 } 90 super.finalize(); 91 } 92 93 private SourceTypes sourceType = SourceTypes.NEW; 94 95 private Sample sample = null; 96 97 private String location = null; 98 99 private boolean useDefaultLocation = true; 100 101 private boolean addNativeSupport = false; 102 103 private boolean needToObfuscate = false; 104 105 /** 106 * Return the Type of the new Project 107 * 108 * @return 109 */ 110 public SourceTypes getSourceType() 111 { 112 return sourceType; 113 } 114 115 /** 116 * Change the Type of the new Project 117 * 118 * @param sourceType 119 */ 120 public void setSourceType(SourceTypes sourceType) 121 { 122 this.sourceType = sourceType; 123 } 124 125 /** 126 * Check if adding native support 127 * 128 * @return 129 */ 130 public boolean isAddingNativeSupport() 131 { 132 return addNativeSupport; 133 } 134 135 /** 136 * Set add native support property 137 * 138 * @param hasNativeSupport 139 */ 140 public void setAddNativeSupport(boolean addNativeSupport) 141 { 142 this.addNativeSupport = addNativeSupport; 143 } 144 145 public void setNeedToObfuscate(boolean needToObfuscate) 146 { 147 this.needToObfuscate = needToObfuscate; 148 } 149 150 public boolean needToObfuscate() 151 { 152 return needToObfuscate; 153 } 154 155 /** 156 * Returns the Project location. 157 * 158 * @see #isUsingDefaultLocation() 159 * @return 160 */ 161 public String getLocation() 162 { 163 return location; 164 } 165 166 /** 167 * Return the sample to use 168 * 169 * @see #getSourceType() 170 * @return 171 */ 172 public Sample getSample() 173 { 174 return sample; 175 } 176 177 /** 178 * Change the used sample 179 * 180 * @see #getSourceType() 181 * @param sample 182 */ 183 public void setSample(Sample sample) 184 { 185 this.sample = sample; 186 } 187 188 /** 189 * Change the Project Location 190 * 191 * @param location 192 */ 193 public void setLocation(String location) 194 { 195 this.location = location; 196 } 197 198 /** 199 * Check if using the default location 200 * 201 * @return 202 */ 203 public boolean isUsingDefaultLocation() 204 { 205 return useDefaultLocation; 206 } 207 208 /** 209 * Set use default location property 210 * 211 * @param useDefaultLocation 212 */ 213 public void setUseDefaultLocation(boolean useDefaultLocation) 214 { 215 this.useDefaultLocation = useDefaultLocation; 216 } 217 218 private String minSdkVersion = null; 219 220 private String name = ""; //$NON-NLS-1$ 221 222 private String activityName = ""; //$NON-NLS-1$ 223 224 private String packageName = ""; //$NON-NLS-1$ 225 226 private IAndroidTarget sdkTarget = null; 227 228 private List<String> sourceFolders = null; 229 230 private boolean usingDefaultPackage = true; 231 232 private final String PACKAGE_ROOT = "com."; //$NON-NLS-1$ 233 234 private Runnable listener = null; 235 236 private String appName; 237 238 /** 239 * Check if using the defaul package name 240 * 241 * @return 242 */ 243 public boolean isUsingDefaultPackage() 244 { 245 return usingDefaultPackage; 246 } 247 248 /** 249 * Set if using the Default package name 250 * 251 * @param usingDefaultPackage 252 */ 253 public void setUsingDefaultPackage(boolean usingDefaultPackage) 254 { 255 this.usingDefaultPackage = usingDefaultPackage; 256 } 257 258 /** 259 * Creates a new AndroidProject 260 */ 261 public AndroidProject() 262 { 263 // initialize SDK Targets 264 if (SdkUtils.getCurrentSdk() == null) 265 { 266 // this listener will be called when a SDK is configured 267 listener = new Runnable() 268 { 269 270 public void run() 271 { 272 IAndroidTarget[] targets = SdkUtils.getAllTargets(); 273 if ((targets != null) && (targets.length > 0)) 274 { 275 int maxApiVersion = -1; 276 for (IAndroidTarget aTarget : targets) 277 { 278 int apiVersion = aTarget.getVersion().getApiLevel(); 279 if (maxApiVersion < apiVersion) 280 { 281 sdkTarget = aTarget; 282 maxApiVersion = apiVersion; 283 } 284 } 285 // set the API string as the min SDK version - this is the way ADT does 286 minSdkVersion = sdkTarget.getVersion().getApiString(); 287 } 288 AndroidPlugin.getDefault().removeSDKLoaderListener(listener); 289 listener = null; 290 } 291 292 }; 293 AndroidPlugin.getDefault().addSDKLoaderListener(listener); 294 } 295 else 296 { 297 IAndroidTarget[] targets = SdkUtils.getAllTargets(); 298 if ((targets != null) && (targets.length > 0)) 299 { 300 int maxApiVersion = -1; 301 for (IAndroidTarget aTarget : targets) 302 { 303 int apiVersion = aTarget.getVersion().getApiLevel(); 304 if (maxApiVersion < apiVersion) 305 { 306 sdkTarget = aTarget; 307 maxApiVersion = apiVersion; 308 } 309 } 310 // set the API string as the min SDK version - this is the way ADT does 311 minSdkVersion = sdkTarget.getVersion().getApiString(); 312 } 313 } 314 315 sourceFolders = new ArrayList(3); 316 sourceFolders.add(IAndroidConstants.FD_SOURCES); 317 sourceFolders.add(IAndroidConstants.FD_GEN_SOURCES); 318 } 319 320 /** 321 * Return the Default Package Name. 322 * 323 * @return 324 */ 325 private String getDefaultPackageName() 326 { 327 return PACKAGE_ROOT + name2package(name); 328 } 329 330 /** 331 * Return the default name for activities. 332 * 333 * @return 334 */ 335 public String getDefaultActivityName() 336 { 337 String activityName = name; 338 activityName = activityName.replaceAll("^[0-9]+", "_"); //$NON-NLS-1$ //$NON-NLS-2$ 339 activityName = activityName.replaceAll("[\\.]+", "_"); //$NON-NLS-1$ //$NON-NLS-2$ 340 return activityName; 341 } 342 343 /** 344 * Returns a valid package name from the Project Name 345 * 346 * @param name 347 * @return 348 */ 349 protected String name2package(String name) 350 { 351 String packageName = getDefaultActivityName().toLowerCase(); 352 packageName = packageName.replaceAll("[^A-Za-z0-9_]+", "_"); //$NON-NLS-1$ //$NON-NLS-2$ 353 if (packageName.endsWith("_") && (packageName.length() > 1)) //$NON-NLS-1$ 354 { 355 packageName = packageName.substring(0, packageName.length() - 1); 356 } 357 return packageName; 358 } 359 360 /** 361 * Return the Minimum SDK Version 362 * 363 * @return 364 */ 365 public String getMinSdkVersion() 366 { 367 return minSdkVersion; 368 } 369 370 /** 371 * Returns <code>true</code> in case the SDK is a preview, 372 * <code>false</code> otherwise. 373 * 374 * @return Returns <code>true</code> in case the SDK is a preview, 375 * <code>false</code> otherwise. 376 */ 377 public boolean isSdkPreview() 378 { 379 return getSdkTarget().getVersion().isPreview(); 380 } 381 382 /** 383 * Return the project Name 384 * 385 * @return 386 */ 387 public String getName() 388 { 389 return name; 390 } 391 392 /** 393 * Return the package name. Or the Default package name, if using it. 394 * 395 * @return 396 */ 397 public String getPackageName() 398 { 399 String packageName; 400 if (isUsingDefaultPackage()) 401 { 402 packageName = getDefaultPackageName(); 403 } 404 else 405 { 406 packageName = this.packageName; 407 } 408 return packageName; 409 } 410 411 /** 412 * Return the SDK target used by this project. 413 * 414 * @return 415 */ 416 public IAndroidTarget getSdkTarget() 417 { 418 return sdkTarget; 419 } 420 421 /** 422 * Return the Source Folder to be created in the project. 423 * 424 * @return 425 */ 426 public List<String> getSourceFolders() 427 { 428 return sourceFolders; 429 } 430 431 /* 432 * (non-Javadoc) 433 * 434 * @see com.motorola.studio.android.model.IWizardModel#getStatus() 435 */ 436 public IStatus getStatus() 437 { 438 IStatus status = Status.OK_STATUS; 439 // Validating Project Name 440 if ((name == null) || (name.length() == 0)) 441 { 442 status = 443 new AndroidStatus(IStatus.ERROR, 444 AndroidNLS.ERR_AndroidProject_ProjectNameMustBeSpecified); 445 } 446 else 447 { 448 Pattern pattern = Pattern.compile("([A-Za-z0-9_\\.])+"); //$NON-NLS-1$ 449 Matcher matcher = pattern.matcher(name); 450 451 if (!matcher.matches()) 452 { 453 String errMsg = NLS.bind(AndroidNLS.ERR_AndroidProject_InvalidProjectName, name); 454 status = new AndroidStatus(IStatus.ERROR, errMsg); 455 } 456 else if (WORKSPACE.getRoot().getProject(name).exists()) 457 { 458 status = 459 new AndroidStatus(IStatus.ERROR, 460 AndroidNLS.ERR_AndroidProject_DuplicatedProjectNameInWorkspace); 461 } 462 else 463 { 464 status = WORKSPACE.validateName(name, IResource.PROJECT); 465 } 466 } 467 468 if (status.isOK() && (sourceType == SourceTypes.EXISTING)) 469 { 470 471 // Check first if the path is empty. If true, we show a info 472 // message to the user 473 if (getLocation().length() == 0) 474 { 475 status = 476 new AndroidStatus(IStatus.INFO, 477 AndroidNLS.ERR_AndroidProject_EmptySourceLocation); 478 } 479 else 480 { 481 // Check if the manifest exists 482 Path path = new Path(getLocation()); 483 String osPath = path.append(IAndroidConstants.FN_ANDROID_MANIFEST).toOSString(); 484 File manifest = new File(osPath); 485 if (!manifest.exists() || !manifest.isFile()) 486 { 487 String errMsg = 488 NLS.bind(AndroidNLS.ERR_AndroidProject_FileNotFoundError, 489 IAndroidConstants.FN_ANDROID_MANIFEST, path.lastSegment()); 490 status = new AndroidStatus(IStatus.ERROR, errMsg); 491 } 492 } 493 } 494 495 // Validating Project Location 496 if (status.isOK() && !isUsingDefaultLocation()) 497 { 498 IProject handle = WORKSPACE.getRoot().getProject(name); 499 status = WORKSPACE.validateProjectLocation(handle, new Path(location)); 500 if (status.isOK() && isNewProject() && (getLocation() != null)) 501 { 502 boolean projectLocationIsEmpty = 503 ProjectCreationSupport.validateNewProjectLocationIsEmpty(new Path( 504 getLocation())); 505 if (!projectLocationIsEmpty) 506 { 507 status = 508 new AndroidStatus(IStatus.ERROR, 509 AndroidNLS.UI_ProjectCreationSupport_NonEmptyFolder); 510 } 511 } 512 } 513 514 // Validating Project Location when adding Native Support on Windows 515 if (status.isOK() && isAddingNativeSupport() && Platform.getOS().equals(Platform.OS_WIN32)) 516 { 517 if ((isUsingDefaultLocation() && ResourcesPlugin.getWorkspace().getRoot().getLocation() 518 .toOSString().contains(" ")) //$NON-NLS-1$ 519 || (!isUsingDefaultLocation() && location.contains(" "))) //$NON-NLS-1$ 520 { 521 522 status = 523 new AndroidStatus(IStatus.ERROR, 524 AndroidNLS.ERR_AndroidProject_LocationContainsWhitespaces); 525 } 526 527 } 528 529 // Validating if the project could create a "file name too long" 530 // structure 531 if (status.isOK()) 532 { 533 String basePath = isUsingDefaultLocation() ? getDefaultLocation() : getLocation(); 534 String relativePackagePath = getPackageName().replace('.', File.separatorChar); 535 String binPath = 536 basePath + File.separatorChar + BIN_FOLDER + File.separatorChar 537 + relativePackagePath; 538 539 String rDrawableBinClass = binPath + File.separatorChar + R_DRAWABLE_CLASS; 540 541 String settingsFilePath = 542 basePath + File.separatorChar + SETTINGS_FOLDER + File.separatorChar 543 + SETTINGS_FILE; 544 545 String defaultClassBin = 546 binPath + File.separator + getDefaultActivityName() + CLASS_EXTENSION; 547 548 int maxFilenameLength = getMax(new int[] 549 { 550 rDrawableBinClass.length(), settingsFilePath.length(), defaultClassBin.length() 551 }); 552 553 if (maxFilenameLength > MAX_PATH_LENGTH) 554 { 555 status = 556 new AndroidStatus(IStatus.ERROR, 557 AndroidNLS.ERR_AndroidProject_ProjectNameTooLong); 558 } 559 } 560 561 // Validating SDK Target 562 if (status.isOK() && (sdkTarget == null)) 563 { 564 status = 565 new AndroidStatus(IStatus.ERROR, 566 AndroidNLS.ERR_AndroidProject_ASdkTargetMustBeSpecified); 567 } 568 569 // Validates the application name 570 if (status.isOK() 571 && ((sourceType == SourceTypes.NEW) || (sourceType == SourceTypes.WIDGET))) 572 { 573 if (appName.trim().length() == 0) 574 { 575 status = 576 new AndroidStatus(IStatus.WARNING, 577 AndroidNLS.WARN_AndroidProject_ApplicationNameIsEmpty); 578 } 579 if (appName.contains("&")) //$NON-NLS-1$ 580 { 581 status = 582 new AndroidStatus(IStatus.ERROR, NLS.bind( 583 AndroidNLS.ERR_AndroidProject_InvalidApplicationName, appName)); 584 } 585 586 } 587 588 // Validating PackageName 589 if (status.isOK() 590 && ((sourceType == SourceTypes.NEW) || (sourceType == SourceTypes.WIDGET)) 591 && !isUsingDefaultPackage()) 592 { 593 if (getPackageName().length() == 0) 594 { 595 status = 596 new AndroidStatus(IStatus.ERROR, 597 AndroidNLS.ERR_AndroidProject_EmptyPackageName); 598 } 599 else if (status.isOK()) 600 { 601 status = 602 JavaConventions.validatePackageName(getPackageName(), SDK_VERSION, 603 SDK_VERSION); 604 } 605 606 if (status.isOK() && (getPackageName().indexOf('.') == -1)) 607 { 608 // The Android Activity Manager does not accept packages names 609 // with only one 610 // identifier. Check the package name has at least one dot in 611 // them (the previous rule 612 // validated that if such a dot exist, it's not the first nor 613 // last characters of the 614 // string.) 615 status = 616 new AndroidStatus(IStatus.ERROR, 617 AndroidNLS.ERR_AndroidProject_InvalidPackageName); 618 } 619 620 if (status.isOK()) 621 { 622 Pattern pattern = Pattern.compile("[A-Za-z0-9_\\.]+"); //$NON-NLS-1$ 623 Matcher matcher = pattern.matcher(getPackageName()); 624 625 if (!matcher.matches()) 626 { 627 String errMsg = 628 NLS.bind(AndroidNLS.ERR_AndroidProject_InvalidCharsInPackageName, 629 getPackageName()); 630 631 status = new AndroidStatus(IStatus.ERROR, errMsg); 632 } 633 } 634 } 635 636 // validating activity name 637 if ((this.getSourceType() == SourceTypes.NEW) 638 || (this.getSourceType() == SourceTypes.WIDGET)) 639 { 640 if ((activityName == null) || (activityName.length() == 0)) 641 { 642 status = 643 new AndroidStatus(IStatus.ERROR, 644 AndroidNLS.ERR_AndroidProject_ActivityNameMustBeSpecified); 645 } 646 else 647 { 648 String onlyChars = "[A-Za-z_]"; //$NON-NLS-1$ 649 Pattern pattern = Pattern.compile("(" + onlyChars + ")(\\w)+"); //$NON-NLS-1$ //$NON-NLS-2$ 650 Matcher matcher = pattern.matcher(activityName); 651 652 if (!matcher.matches()) 653 { 654 String errMsg = 655 NLS.bind(AndroidNLS.ERR_AndroidProject_InvalidActivityName, 656 activityName); 657 status = new AndroidStatus(IStatus.ERROR, errMsg); 658 } 659 } 660 } 661 662 // Validating Min Sdk Version 663 if (status.isOK() 664 && ((sourceType == SourceTypes.NEW) || (sourceType == SourceTypes.WIDGET))) 665 { 666 // validate in case the sdk is preview 667 if (isSdkPreview()) 668 { 669 String sdkAPI = getSdkTarget().getVersion().getApiString(); 670 if (!sdkAPI.equals(getMinSdkVersion())) 671 { 672 status = 673 new AndroidStatus(IStatus.ERROR, NLS.bind( 674 AndroidNLS.AndroidProject_MsgSDKVersionIsPreview, sdkAPI)); 675 } 676 } 677 // since it is not a preview, validate it normally 678 else 679 { 680 int version = -1; 681 try 682 { 683 // If not empty, it must be a valid integer > 0 684 version = Integer.parseInt(getMinSdkVersion()); 685 } 686 catch (NumberFormatException nfe) 687 { 688 status = 689 new AndroidStatus(IStatus.ERROR, 690 AndroidNLS.ERR_AndroidProject_InvalidSdkVersion); 691 } 692 693 if (status.isOK() && (version < 1)) 694 { 695 status = 696 new AndroidStatus(IStatus.ERROR, 697 AndroidNLS.ERR_AndroidProject_InvalidSdkVersion); 698 } 699 700 if (status.isOK() && (getSdkTarget() != null)) 701 { 702 if (getSdkTarget().getVersion().getApiLevel() > version) 703 { 704 status = 705 new AndroidStatus(IStatus.WARNING, 706 AndroidNLS.ERR_AndroidProject_InvalidApiLevel); 707 } 708 else if (getSdkTarget().getVersion().getApiLevel() < version) 709 { 710 status = 711 new AndroidStatus(IStatus.ERROR, 712 AndroidNLS.EXC_AndroidProject_InvalidMinimumSdkVersion); 713 } 714 } 715 } 716 } 717 718 //validate if there are available samples 719 if (status.isOK() && (sourceType == SourceTypes.SAMPLE) && (sdkTarget != null) 720 && (SdkUtils.getSamples(sdkTarget).length == 0)) 721 { 722 status = 723 new AndroidStatus(IStatus.ERROR, 724 AndroidNLS.EXC_AndroidProject_NoSamplesAvailable); 725 } 726 727 // Validating Project Location when adding Obfuscation Support 728 if (status.isOK() && needToObfuscate()) 729 { 730 if ((isUsingDefaultLocation() && ResourcesPlugin.getWorkspace().getRoot().getLocation() 731 .toOSString().contains(" ")) //$NON-NLS-1$ 732 || (!isUsingDefaultLocation() && location.contains(" "))) //$NON-NLS-1$ 733 { 734 735 status = 736 new AndroidStatus(IStatus.WARNING, 737 AndroidNLS.WRN_Obfuscation_ProjectLocationContainWhitespaces); 738 } 739 } 740 741 return status; 742 } 743 744 /* 745 * (non-Javadoc) 746 * 747 * @see com.motorola.studio.android.model.IWizardModel#needMoreInformation() 748 */ 749 public boolean needMoreInformation() 750 { 751 boolean needMoreInformation = 752 (name == null) || (name.length() == 0) 753 || !WORKSPACE.validateName(name, IResource.PROJECT).isOK(); 754 755 if (!needMoreInformation) 756 { 757 boolean projectPathInformation = 758 (location == null) 759 || ((location.length() == 0) || !WORKSPACE.validateProjectLocation( 760 WORKSPACE.getRoot().getProject(name), new Path(location)) 761 .isOK()); 762 boolean newProjectInformation = !useDefaultLocation && projectPathInformation; 763 switch (sourceType) 764 { 765 case NEW: 766 needMoreInformation = newProjectInformation; 767 break; 768 case SAMPLE: 769 needMoreInformation = newProjectInformation || (sample == null); 770 break; 771 case EXISTING: 772 needMoreInformation = projectPathInformation; 773 break; 774 case WIDGET: 775 needMoreInformation = newProjectInformation; 776 } 777 } 778 779 if (!needMoreInformation) 780 { 781 if (((sourceType == SourceTypes.NEW) || (sourceType == SourceTypes.WIDGET)) 782 && !isUsingDefaultPackage()) 783 { 784 needMoreInformation = 785 (getPackageName().length() == 0) 786 || !JavaConventions.validatePackageName(getPackageName(), 787 SDK_VERSION, SDK_VERSION).isOK() 788 || (getPackageName().indexOf('.') == -1); 789 } 790 } 791 792 if (!needMoreInformation) 793 { 794 needMoreInformation = sdkTarget == null; 795 } 796 return needMoreInformation; 797 } 798 799 /* (non-Javadoc) 800 * @see com.motorola.studio.android.model.IWizardModel#save(org.eclipse.jface.wizard.IWizardContainer, org.eclipse.core.runtime.IProgressMonitor) 801 */ 802 public boolean save(IWizardContainer container, IProgressMonitor monitor) 803 { 804 try 805 { 806 return ProjectCreationSupport.createProject(this, container); 807 } 808 catch (AndroidException e) 809 { 810 IStatus status = 811 new Status(IStatus.ERROR, AndroidPlugin.PLUGIN_ID, e.getLocalizedMessage()); 812 813 EclipseUtils.showErrorDialog(AndroidNLS.GEN_Error, 814 AndroidNLS.EXC_AndroidProject_AnErrorHasOccurredWhenCreatingTheProject, status); 815 return false; 816 } 817 } 818 819 /** 820 * Change the SDK 821 * 822 * @param minSdkVersion 823 */ 824 public void setMinSdkVersion(String minSdkVersion) 825 { 826 this.minSdkVersion = minSdkVersion; 827 } 828 829 /** 830 * Change the project name 831 * 832 * @param name 833 */ 834 public void setName(String name) 835 { 836 this.name = name.trim(); 837 } 838 839 /** 840 * Change the package name. If using default package name will throw an 841 * {@link IllegalStateException} 842 * 843 * @param packageName 844 */ 845 public void setPackageName(String packageName) 846 { 847 if (isUsingDefaultPackage()) 848 { 849 throw new IllegalStateException(); 850 } 851 this.packageName = packageName.trim(); 852 } 853 854 /** 855 * Change the SDK Target 856 * 857 * @param sdkTarget 858 */ 859 public void setSdkTarget(IAndroidTarget sdkTarget) 860 { 861 this.sdkTarget = sdkTarget; 862 } 863 864 /** 865 * Change the Source Folder 866 * 867 * @param sourceFolder 868 */ 869 public void setSourceFolder(List<String> sourceFolders) 870 { 871 this.sourceFolders.clear(); 872 this.sourceFolders.addAll(sourceFolders); 873 } 874 875 /** 876 * Return the Default location for this project 877 * 878 * @return 879 */ 880 public String getDefaultLocation() 881 { 882 return ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString() + File.separator 883 + name; 884 } 885 886 /** 887 * Check if this project is a new project. 888 * 889 * @return 890 */ 891 public boolean isNewProject() 892 { 893 return getSourceType() != SourceTypes.EXISTING; 894 } 895 896 /** 897 * Set the name of the activity being created with the project 898 * This attribute is only valid for New Projects. 899 * Other kind of project will ignore this attribute. 900 */ 901 public void setActivityName(String activityName) 902 { 903 this.activityName = activityName; 904 } 905 906 /** 907 * Return this project default activity name 908 * @return an Activity name as string 909 */ 910 public String getActivityName() 911 { 912 return this.activityName; 913 } 914 915 /** 916 * Retrieves the maximum value from an int array 917 * 918 * @param values 919 * the int array 920 * 921 * @return the maximum value from the int array 922 */ 923 private int getMax(int[] values) 924 { 925 int max = values[0]; 926 927 for (int i = 1; i < values.length; i++) 928 { 929 max = Math.max(max, values[i]); 930 } 931 932 return max; 933 } 934 935 /** 936 * Set the application name to be used 937 * The app name will be used only when the project is new 938 * @param app_name 939 */ 940 public void setApplicationName(String app_name) 941 { 942 this.appName = app_name; 943 } 944 945 /** 946 * get the user defined application name 947 * @return 948 */ 949 public String getApplicationName() 950 { 951 return this.appName; 952 } 953 } 954