diff options
Diffstat (limited to 'eclipse')
53 files changed, 1103 insertions, 104 deletions
diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt index 7d6f931..f8d6550 100644 --- a/eclipse/dictionary.txt +++ b/eclipse/dictionary.txt @@ -233,6 +233,7 @@ recompilation rect redo refactor +refactored refactoring refactorings regex diff --git a/eclipse/features/com.android.ide.eclipse.adt.package/feature.xml b/eclipse/features/com.android.ide.eclipse.adt.package/feature.xml index 33b8803..fd6cbd1 100644 --- a/eclipse/features/com.android.ide.eclipse.adt.package/feature.xml +++ b/eclipse/features/com.android.ide.eclipse.adt.package/feature.xml @@ -44,6 +44,7 @@ <import plugin="org.eclipse.ui.forms"/> <import plugin="org.eclipse.ui.browser"/> <import plugin="org.eclipse.ui.views"/> + <import plugin="org.eclipse.ui.views.log"/> <import plugin="org.eclipse.wst.sse.core"/> <import plugin="org.eclipse.wst.sse.ui"/> <import plugin="org.eclipse.wst.xml.core"/> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FragmentRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FragmentRule.java index e809d00..f99cf0c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FragmentRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FragmentRule.java @@ -30,7 +30,7 @@ public class FragmentRule extends BaseViewRule { @Override public void onCreate(@NonNull INode node, @NonNull INode parent, @NonNull InsertType insertType) { - // When dropping a fragment tag, ask the user which layout to include. + // When dropping a fragment tag, ask the user which class to use. if (insertType == InsertType.CREATE) { // NOT InsertType.CREATE_PREVIEW String fqcn = mRulesEngine.displayFragmentSourceInput(); if (fqcn != null) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java index 1dafe53..9f2b4ae 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java @@ -19,7 +19,9 @@ package com.android.ide.common.layout; import static com.android.SdkConstants.ANDROID_URI; import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT; import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH; +import static com.android.SdkConstants.ATTR_ORIENTATION; import static com.android.SdkConstants.FQCN_LINEAR_LAYOUT; +import static com.android.SdkConstants.VALUE_VERTICAL; import com.android.annotations.NonNull; import com.android.annotations.Nullable; @@ -58,7 +60,8 @@ public class ScrollViewRule extends FrameLayoutRule { // Insert a default linear layout (which will in turn be registered as // a child of this node and the create child method above will set its // fill parent attributes, its id, etc. - node.appendChild(FQCN_LINEAR_LAYOUT); + INode linear = node.appendChild(FQCN_LINEAR_LAYOUT); + linear.setAttribute(ANDROID_URI, ATTR_ORIENTATION, VALUE_VERTICAL); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ViewTagRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ViewTagRule.java new file mode 100644 index 0000000..a89a3d8 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ViewTagRule.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ide.common.layout; + +import static com.android.SdkConstants.ATTR_CLASS; + +import com.android.annotations.NonNull; +import com.android.ide.common.api.INode; +import com.android.ide.common.api.IViewRule; +import com.android.ide.common.api.InsertType; +import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; + +/** + * An {@link IViewRule} for the special XML {@code <view>} tag. + */ +public class ViewTagRule extends BaseViewRule { + @Override + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { + // When dropping a view tag, ask the user which custom view class to use + if (insertType == InsertType.CREATE) { // NOT InsertType.CREATE_PREVIEW + String fqcn = mRulesEngine.displayCustomViewClassInput(); + if (fqcn != null) { + if (!ViewElementDescriptor.viewNeedsPackage(fqcn)) { + fqcn = fqcn.substring(fqcn.lastIndexOf('.') + 1); + } + node.editXml("Set Custom View Class", + new PropertySettingNodeHandler(null, ATTR_CLASS, + fqcn.length() > 0 ? fqcn : null)); + } else { + // Remove the view; the insertion was canceled + parent.removeChild(node); + } + } + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java index f83bd3c..edfc30c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java @@ -18,9 +18,9 @@ package com.android.ide.eclipse.adt; import static com.android.SdkConstants.DOT_AIDL; import static com.android.SdkConstants.DOT_DEP; +import static com.android.SdkConstants.DOT_FS; import static com.android.SdkConstants.DOT_JAVA; import static com.android.SdkConstants.DOT_RS; -import static com.android.SdkConstants.DOT_FS; import com.android.SdkConstants; import com.android.ide.eclipse.adt.internal.build.builders.PostCompilerBuilder; @@ -223,4 +223,5 @@ public class AdtConstants { public static final String DOC_HIDE = "@hide"; //$NON-NLS-1$ public static final String DEX_OPTIONS_FORCEJUMBO = "dex.force.jumbo"; //$NON-NLS-1$ + public static final String DEX_OPTIONS_DISABLE_MERGER = "dex.disable.merger"; //$NON-NLS-1$ } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java index c98e94f..223e5e5 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java @@ -753,11 +753,11 @@ public class AdtUtils { editor.wrapUndoEditXmlModel(description, new Runnable() { @Override public void run() { - String prefix = XmlUtils.lookupNamespacePrefix(element, TOOLS_URI, null); + String prefix = XmlUtils.lookupNamespacePrefix(element, TOOLS_URI, null, true); if (prefix == null) { // Add in new prefix... prefix = XmlUtils.lookupNamespacePrefix(element, - TOOLS_URI, TOOLS_PREFIX); + TOOLS_URI, TOOLS_PREFIX, true /*create*/); if (value != null) { // ...and ensure that the header is formatted such that // the XML namespace declaration is placed in the right @@ -880,11 +880,11 @@ public class AdtUtils { Document doc = domModel.getDocument(); if (doc != null && element.getOwnerDocument() == doc) { String prefix = XmlUtils.lookupNamespacePrefix(element, TOOLS_URI, - null); + null, true); if (prefix == null) { // Add in new prefix... prefix = XmlUtils.lookupNamespacePrefix(element, - TOOLS_URI, TOOLS_PREFIX); + TOOLS_URI, TOOLS_PREFIX, true); } String v = value; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java index 5ffe2b3..c94ef9a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java @@ -109,6 +109,7 @@ public class BuildHelper { private final AndroidPrintStream mOutStream; private final AndroidPrintStream mErrStream; private final boolean mForceJumbo; + private final boolean mDisableDexMerger; private final boolean mVerbose; private final boolean mDebugMode; @@ -140,7 +141,7 @@ public class BuildHelper { public BuildHelper(@NonNull IProject project, @NonNull AndroidPrintStream outStream, @NonNull AndroidPrintStream errStream, - boolean forceJumbo, boolean debugMode, + boolean forceJumbo, boolean disableDexMerger, boolean debugMode, boolean verbose, ResourceMarker resMarker) throws CoreException { mProject = project; mOutStream = outStream; @@ -148,6 +149,7 @@ public class BuildHelper { mDebugMode = debugMode; mVerbose = verbose; mForceJumbo = forceJumbo; + mDisableDexMerger = disableDexMerger; gatherPaths(resMarker); } @@ -712,13 +714,12 @@ public class BuildHelper { // replace the libs by their dexed versions (dexing them if needed.) List<String> finalInputPaths = new ArrayList<String>(inputPaths.size()); - if (inputPaths.size() == 1) { + if (mDisableDexMerger || inputPaths.size() == 1) { // only one input, no need to put a pre-dexed version, even if this path is // just a jar file (case for proguard'ed builds) finalInputPaths.addAll(inputPaths); } else { - for (String input : inputPaths) { File inputFile = new File(input); if (inputFile.isDirectory()) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java index 3dfcd1e..6e3dce3 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java @@ -372,6 +372,7 @@ public class PostCompilerBuilder extends BaseBuilder { BuildHelper helper = new BuildHelper(project, mOutStream, mErrStream, false /*jumbo mode doesn't matter here*/, + false /*dex merger doesn't matter here*/, true /*debugMode*/, AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE, mResourceMarker); @@ -477,10 +478,16 @@ public class PostCompilerBuilder extends BaseBuilder { if (mPackageResources || mConvertToDex || mBuildFinalPackage) { String forceJumboStr = projectState.getProperty( AdtConstants.DEX_OPTIONS_FORCEJUMBO); - Boolean b = Boolean.valueOf(forceJumboStr); + Boolean jumbo = Boolean.valueOf(forceJumboStr); + + String dexMergerStr = projectState.getProperty( + AdtConstants.DEX_OPTIONS_DISABLE_MERGER); + Boolean dexMerger = Boolean.valueOf(dexMergerStr); + BuildHelper helper = new BuildHelper(project, mOutStream, mErrStream, - b.booleanValue(), + jumbo.booleanValue(), + dexMerger.booleanValue(), true /*debugMode*/, AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE, mResourceMarker); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java index 25b16e4..ba23c95 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java @@ -56,6 +56,8 @@ import com.android.utils.ILogger; import com.android.utils.Pair; import com.android.xml.AndroidManifest; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; @@ -78,6 +80,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import javax.xml.parsers.ParserConfigurationException; @@ -1156,18 +1159,71 @@ public class PreCompilerBuilder extends BaseBuilder { File rFile = new File(outputFolder, SdkConstants.FN_RESOURCE_TEXT); // if the project has no resources, the file could not exist. if (rFile.isFile()) { - SymbolLoader symbolValues = new SymbolLoader(rFile); - symbolValues.load(); - - for (Pair<File, String> libData : libRFiles) { - File libRFile = libData.getFirst(); - if (libRFile.isFile()) { - SymbolLoader symbols = new SymbolLoader(libRFile); - symbols.load(); - - SymbolWriter writer = new SymbolWriter(osOutputPath, - libData.getSecond(), symbols, symbolValues); - writer.write(); + // Load the full symbols from the full R.txt file. + SymbolLoader fullSymbols = new SymbolLoader(rFile); + fullSymbols.load(); + + // simpler case of a single library + if (libRFiles.size() == 1) { + Pair<File, String> lib = libRFiles.get(0); + createRClass(fullSymbols, lib.getFirst(), lib.getSecond(), osOutputPath); + + } else { + Map<String, File> libPackages = Maps.newHashMapWithExpectedSize( + libRFiles.size()); + Set<String> duplicatePackages = Sets.newHashSet(); + + // preprocessing to figure out if there are dups in the package names of + // the libraries + for (Pair<File, String> lib : libRFiles) { + String libPackage = lib.getSecond(); + File existingPkg = libPackages.get(libPackage); + if (existingPkg != null) { + // record the dup package and keep going, in case there are all + // the same + duplicatePackages.add(libPackage); + continue; + } + + libPackages.put(libPackage, lib.getFirst()); + } + + // check if we have duplicate but all files are the same. + if (duplicatePackages.size() > 0) { + // possible conflict! + // detect case of all libraries == same package. + if (duplicatePackages.size() == 1 && libPackages.size() == 1 && + duplicatePackages.iterator().next().equals(libPackages.keySet().iterator().next())) { + // this is ok, all libraries have the same package. + // Make a copy of the full R class. + SymbolWriter writer = new SymbolWriter(osOutputPath, + duplicatePackages.iterator().next(), + fullSymbols, fullSymbols); + writer.write(); + } else { + StringBuilder sb = new StringBuilder(); + sb.append("The following packages have been found to be used by two or more libraries:"); + for (String pkg : duplicatePackages) { + sb.append("\n\t").append(pkg); + } + sb.append("\nNo libraries must share the same package, unless all libraries share the same packages."); + + String msg = sb.toString(); + markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); + + AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, + msg); + + throw new AbortBuildException(); + } + } else { + // no dups, all libraries have different packages. + // Conflicts with the main package have been removed already. + // Just process all the libraries. + for (Pair<File, String> lib : libRFiles) { + createRClass(fullSymbols, lib.getFirst(), lib.getSecond(), + osOutputPath); + } } } } @@ -1227,6 +1283,19 @@ public class PreCompilerBuilder extends BaseBuilder { } } + private void createRClass(SymbolLoader fullSymbols, File libRTxtFile, String libPackage, + String osOutputPath) throws IOException { + if (libRTxtFile.isFile()) { + SymbolLoader libSymbols = new SymbolLoader(libRTxtFile); + libSymbols.load(); + + SymbolWriter writer = new SymbolWriter(osOutputPath, libPackage, libSymbols, + fullSymbols); + writer.write(); + } + } + + /** * Creates a relative {@link IPath} from a java package. * @param javaPackageName the java package. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java index 09bd627..5aac51f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java @@ -20,6 +20,7 @@ import static com.android.SdkConstants.ANDROID_URI; import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX; import static com.android.SdkConstants.PREFIX_ANDROID; import static com.android.SdkConstants.PREFIX_RESOURCE_REF; +import static com.android.SdkConstants.PREFIX_THEME_REF; import static com.android.SdkConstants.UNIT_DP; import static com.android.SdkConstants.UNIT_IN; import static com.android.SdkConstants.UNIT_MM; @@ -46,6 +47,9 @@ import com.android.utils.Pair; import com.android.utils.XmlUtils; import org.eclipse.core.runtime.IStatus; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.ui.ISharedImages; +import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; @@ -226,8 +230,10 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { // or their values). if (info.isInValue) { - computeAttributeValues(proposals, offset, parent, info.name, currentNode, - wordPrefix, info.skipEndTag, info.replaceLength); + if (computeAttributeValues(proposals, offset, parent, info.name, currentNode, + wordPrefix, info.skipEndTag, info.replaceLength)) { + return; + } } // Look up attribute proposals based on descriptors @@ -463,14 +469,24 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { choices = UiResourceAttributeNode.computeResourceStringMatches( mEditor, attributeDescriptor, value); attrInfo.skipEndTag = false; + } else if (value.startsWith(PREFIX_THEME_REF) + && !attributeInfo.getFormats().contains(Format.REFERENCE)) { + choices = UiResourceAttributeNode.computeResourceStringMatches( + mEditor, attributeDescriptor, value); + attrInfo.skipEndTag = false; } return choices; } - protected void computeAttributeValues(List<ICompletionProposal> proposals, int offset, + /** + * Compute attribute values. Return true if the complete set of values was + * added, so addition descriptor information should not be added. + */ + protected boolean computeAttributeValues(List<ICompletionProposal> proposals, int offset, String parentTagName, String attributeName, Node node, String wordPrefix, boolean skipEndTag, int replaceLength) { + return false; } protected void computeTextValues(List<ICompletionProposal> proposals, int offset, @@ -504,8 +520,8 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { * * @return An ElementDescriptor[] or null. */ - private Object[] getElementChoicesForTextNode(Node parentNode) { - Object[] choices = null; + protected ElementDescriptor[] getElementChoicesForTextNode(Node parentNode) { + ElementDescriptor[] choices = null; String parent; if (parentNode.getNodeType() == Node.ELEMENT_NODE) { // We're editing a text node which parent is an element node. Limit @@ -556,6 +572,7 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { for (Object choice : choices) { String keyword = null; String nsPrefix = null; + String nsUri = null; Image icon = null; String tooltip = null; if (choice instanceof ElementDescriptor) { @@ -573,11 +590,11 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { // Get the namespace URI for the attribute. Note that some attributes // do not have a namespace and thus return null here. - String nsUri = ((AttributeDescriptor)choice).getNamespaceUri(); + nsUri = ((AttributeDescriptor)choice).getNamespaceUri(); if (nsUri != null) { nsPrefix = nsUriMap.get(nsUri); if (nsPrefix == null) { - nsPrefix = XmlUtils.lookupNamespacePrefix(currentNode, nsUri); + nsPrefix = XmlUtils.lookupNamespacePrefix(currentNode, nsUri, false); nsUriMap.put(nsUri, nsPrefix); } } @@ -598,6 +615,10 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { if (isAttribute) { icon = IconFactory.getInstance().getIcon(ATTRIBUTE_ICON_FILENAME); } + } else if (choice instanceof IType) { + IType type = (IType) choice; + keyword = type.getFullyQualifiedName(); + icon = JavaUI.getSharedImages().getImage(ISharedImages.IMG_OBJS_CUNIT); } else { continue; // discard unknown choice } @@ -667,7 +688,9 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor { icon, // Image image displayString, // displayString null, // IContextInformation contextInformation - tooltip // String additionalProposalInfo + tooltip, // String additionalProposalInfo + nsPrefix, + nsUri )); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/CompletionProposal.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/CompletionProposal.java index 74b7dd8..2d44677 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/CompletionProposal.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/CompletionProposal.java @@ -15,20 +15,34 @@ */ package com.android.ide.eclipse.adt.internal.editors; +import static com.android.SdkConstants.XMLNS; + import com.android.ide.common.api.IAttributeInfo; +import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; +import com.android.utils.XmlUtils; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.ISourceRange; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.Position; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -54,18 +68,21 @@ class CompletionProposal implements ICompletionProposal { private final AndroidContentAssist mAssist; private final Object mChoice; private final int mCursorPosition; - private final int mReplacementOffset; + private int mReplacementOffset; private final int mReplacementLength; private final String mReplacementString; private final Image mImage; private final String mDisplayString; private final IContextInformation mContextInformation; + private final String mNsPrefix; + private final String mNsUri; private String mAdditionalProposalInfo; CompletionProposal(AndroidContentAssist assist, Object choice, String replacementString, int replacementOffset, int replacementLength, int cursorPosition, Image image, String displayString, - IContextInformation contextInformation, String additionalProposalInfo) { + IContextInformation contextInformation, String additionalProposalInfo, + String nsPrefix, String nsUri) { assert replacementString != null; assert replacementOffset >= 0; assert replacementLength >= 0; @@ -81,6 +98,8 @@ class CompletionProposal implements ICompletionProposal { mDisplayString = displayString; mContextInformation = contextInformation; mAdditionalProposalInfo = additionalProposalInfo; + mNsPrefix = nsPrefix; + mNsUri = nsUri; } @Override @@ -142,6 +161,24 @@ class CompletionProposal implements ICompletionProposal { } } + } else if (mChoice instanceof IType) { + IType type = (IType) mChoice; + try { + ISourceRange javadocRange = type.getJavadocRange(); + if (javadocRange != null && javadocRange.getLength() > 0) { + ISourceRange sourceRange = type.getSourceRange(); + if (sourceRange != null) { + String source = type.getSource(); + int start = javadocRange.getOffset() - sourceRange.getOffset(); + int length = javadocRange.getLength(); + String doc = source.substring(start, start + length); + return doc; + } + } + return type.getAttachedJavadoc(new NullProgressMonitor()); + } catch (JavaModelException e) { + AdtPlugin.log(e, null); + } } } @@ -151,6 +188,39 @@ class CompletionProposal implements ICompletionProposal { @Override public void apply(IDocument document) { try { + Position position = new Position(mReplacementOffset); + document.addPosition(position); + + // Ensure that the namespace is defined in the document + String prefix = mNsPrefix; + if (mNsUri != null && prefix != null) { + Document dom = DomUtilities.getDocument(mAssist.getEditor()); + if (dom != null) { + Element root = dom.getDocumentElement(); + if (root != null) { + // Is the namespace already defined? + boolean found = false; + NamedNodeMap attributes = root.getAttributes(); + for (int i = 0, n = attributes.getLength(); i < n; i++) { + Attr attribute = (Attr) attributes.item(i); + String name = attribute.getName(); + if (name.startsWith(XMLNS) && mNsUri.equals(attribute.getValue())) { + found = true; + break; + } + } + if (!found) { + if (prefix.endsWith(":")) { //$NON-NLS-1$ + prefix = prefix.substring(0, prefix.length() - 1); + } + XmlUtils.lookupNamespacePrefix(root, mNsUri, prefix, true); + } + } + } + } + + mReplacementOffset = position.getOffset(); + document.removePosition(position); document.replace(mReplacementOffset, mReplacementLength, mReplacementString); } catch (BadLocationException x) { // ignore diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/OutlineLabelProvider.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/OutlineLabelProvider.java index 1d27e33..bb5d1ba 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/OutlineLabelProvider.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/OutlineLabelProvider.java @@ -24,6 +24,8 @@ import static com.android.SdkConstants.ATTR_SRC; import static com.android.SdkConstants.ATTR_TEXT; import static com.android.SdkConstants.DRAWABLE_PREFIX; import static com.android.SdkConstants.LAYOUT_RESOURCE_PREFIX; +import static com.android.SdkConstants.VIEW; +import static com.android.SdkConstants.VIEW_TAG; import org.eclipse.swt.graphics.Image; import org.eclipse.wst.xml.ui.internal.contentoutline.JFaceNodeLabelProvider; @@ -43,6 +45,11 @@ class OutlineLabelProvider extends JFaceNodeLabelProvider { if (element instanceof Element) { Element e = (Element) element; String tagName = e.getTagName(); + if (VIEW_TAG.equals(tagName)) { + // Can't have both view.png and View.png; issues on case sensitive vs + // case insensitive file systems + tagName = VIEW; + } IconFactory factory = IconFactory.getInstance(); Image img = factory.getIcon(tagName, null); if (img != null) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java index 777cf1d..8a4cf23 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java @@ -70,7 +70,7 @@ public final class AnimationContentAssist extends AndroidContentAssist { } @Override - protected void computeAttributeValues(List<ICompletionProposal> proposals, int offset, + protected boolean computeAttributeValues(List<ICompletionProposal> proposals, int offset, String parentTagName, String attributeName, Node node, String wordPrefix, boolean skipEndTag, int replaceLength) { @@ -95,8 +95,8 @@ public final class AnimationContentAssist extends AndroidContentAssist { } - super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node, - wordPrefix, skipEndTag, replaceLength); + return super.computeAttributeValues(proposals, offset, parentTagName, attributeName, + node, wordPrefix, skipEndTag, replaceLength); } else if (parentTagName.equals(OBJECT_ANIMATOR) && attributeName.endsWith(PROPERTY_NAME)) { @@ -156,12 +156,13 @@ public final class AnimationContentAssist extends AndroidContentAssist { addMatchingProposals(proposals, pairs.toArray(), offset, node, wordPrefix, (char) 0 /* needTag */, true /* isAttribute */, false /* isNew */, skipEndTag /* skipEndTag */, replaceLength); - return; } } + + return false; } else { - super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node, - wordPrefix, skipEndTag, replaceLength); + return super.computeAttributeValues(proposals, offset, parentTagName, attributeName, + node, wordPrefix, skipEndTag, replaceLength); } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutContentAssist.java index 7efa34a..99549ab 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutContentAssist.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutContentAssist.java @@ -16,13 +16,48 @@ package com.android.ide.eclipse.adt.internal.editors.layout; +import static com.android.SdkConstants.ANDROID_PKG_PREFIX; +import static com.android.SdkConstants.ATTR_CLASS; +import static com.android.SdkConstants.ATTR_CONTEXT; +import static com.android.SdkConstants.ATTR_NAME; +import static com.android.SdkConstants.CLASS_ACTIVITY; +import static com.android.SdkConstants.CLASS_FRAGMENT; +import static com.android.SdkConstants.CLASS_V4_FRAGMENT; +import static com.android.SdkConstants.CLASS_VIEW; +import static com.android.SdkConstants.VIEW_FRAGMENT; +import static com.android.SdkConstants.VIEW_TAG; + +import com.android.annotations.Nullable; import com.android.annotations.VisibleForTesting; +import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.AndroidContentAssist; import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.CustomViewDescriptorService; +import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CustomViewFinder; +import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; +import com.google.common.collect.Lists; +import com.google.common.collect.ObjectArrays; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.ITypeHierarchy; +import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.w3c.dom.Node; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + /** * Content Assist Processor for /res/layout XML files */ @@ -55,6 +90,145 @@ public final class LayoutContentAssist extends AndroidContentAssist { } } + if (choices == null && parent.length() >= 1 && Character.isLowerCase(parent.charAt(0))) { + // Custom view prefix? + List<ElementDescriptor> descriptors = getCustomViews(); + if (descriptors != null && !descriptors.isEmpty()) { + List<ElementDescriptor> matches = Lists.newArrayList(); + for (ElementDescriptor descriptor : descriptors) { + if (descriptor.getXmlLocalName().startsWith(parent)) { + matches.add(descriptor); + } + } + if (!matches.isEmpty()) { + return matches.toArray(new ElementDescriptor[matches.size()]); + } + } + } + return choices; } + + @Override + protected ElementDescriptor[] getElementChoicesForTextNode(Node parentNode) { + ElementDescriptor[] choices = super.getElementChoicesForTextNode(parentNode); + + // Add in custom views, if any + List<ElementDescriptor> descriptors = getCustomViews(); + if (descriptors != null && !descriptors.isEmpty()) { + ElementDescriptor[] array = descriptors.toArray( + new ElementDescriptor[descriptors.size()]); + choices = ObjectArrays.concat(choices, array, ElementDescriptor.class); + choices = sort(choices); + } + + return choices; + } + + @Nullable + private List<ElementDescriptor> getCustomViews() { + // Add in custom views, if any + IProject project = mEditor.getProject(); + CustomViewFinder finder = CustomViewFinder.get(project); + Collection<String> views = finder.getAllViews(); + if (views == null) { + finder.refresh(); + views = finder.getAllViews(); + } + if (views != null && !views.isEmpty()) { + List<ElementDescriptor> descriptors = Lists.newArrayListWithExpectedSize(views.size()); + CustomViewDescriptorService customViews = CustomViewDescriptorService.getInstance(); + for (String fqcn : views) { + ViewElementDescriptor descriptor = customViews.getDescriptor(project, fqcn); + if (descriptor != null) { + descriptors.add(descriptor); + } + } + + return descriptors; + } + + return null; + } + + @Override + protected boolean computeAttributeValues(List<ICompletionProposal> proposals, int offset, + String parentTagName, String attributeName, Node node, String wordPrefix, + boolean skipEndTag, int replaceLength) { + super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node, + wordPrefix, skipEndTag, replaceLength); + + boolean projectOnly = false; + List<String> superClasses = null; + if (VIEW_FRAGMENT.equals(parentTagName) && (attributeName.endsWith(ATTR_NAME) + || attributeName.equals(ATTR_CLASS))) { + // Insert fragment class matches + superClasses = Arrays.asList(CLASS_V4_FRAGMENT, CLASS_FRAGMENT); + } else if (VIEW_TAG.equals(parentTagName) && attributeName.endsWith(ATTR_CLASS)) { + // Insert custom view matches + superClasses = Collections.singletonList(CLASS_VIEW); + projectOnly = true; + } else if (attributeName.endsWith(ATTR_CONTEXT)) { + // Insert activity matches + superClasses = Collections.singletonList(CLASS_ACTIVITY); + } + + if (superClasses != null) { + IProject project = mEditor.getProject(); + if (project == null) { + return false; + } + try { + IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); + IType type = javaProject.findType(superClasses.get(0)); + Set<IType> elements = new HashSet<IType>(); + if (type != null) { + ITypeHierarchy hierarchy = type.newTypeHierarchy(new NullProgressMonitor()); + IType[] allSubtypes = hierarchy.getAllSubtypes(type); + for (IType subType : allSubtypes) { + if (!projectOnly || subType.getResource() != null) { + elements.add(subType); + } + } + } + assert superClasses.size() <= 2; // If more, need to do additional work below + if (superClasses.size() == 2) { + type = javaProject.findType(superClasses.get(1)); + if (type != null) { + ITypeHierarchy hierarchy = type.newTypeHierarchy( + new NullProgressMonitor()); + IType[] allSubtypes = hierarchy.getAllSubtypes(type); + for (IType subType : allSubtypes) { + if (!projectOnly || subType.getResource() != null) { + elements.add(subType); + } + } + } + } + + List<IType> sorted = new ArrayList<IType>(elements); + Collections.sort(sorted, new Comparator<IType>() { + @Override + public int compare(IType type1, IType type2) { + String fqcn1 = type1.getFullyQualifiedName(); + String fqcn2 = type2.getFullyQualifiedName(); + int category1 = fqcn1.startsWith(ANDROID_PKG_PREFIX) ? 1 : -1; + int category2 = fqcn2.startsWith(ANDROID_PKG_PREFIX) ? 1 : -1; + if (category1 != category2) { + return category1 - category2; + } + return fqcn1.compareTo(fqcn2); + } + }); + addMatchingProposals(proposals, sorted.toArray(), offset, node, wordPrefix, + (char) 0, false /* isAttribute */, false /* isNew */, + false /* skipEndTag */, replaceLength); + return true; + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + } + + return false; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java index 6aace4c..b261a5f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java @@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout; import static com.android.SdkConstants.ANDROID_PKG_PREFIX; import static com.android.SdkConstants.CALENDAR_VIEW; +import static com.android.SdkConstants.CLASS_VIEW; import static com.android.SdkConstants.EXPANDABLE_LIST_VIEW; import static com.android.SdkConstants.FQCN_GRID_VIEW; import static com.android.SdkConstants.FQCN_SPINNER; @@ -142,6 +143,11 @@ public final class ProjectCallback extends LegacyCallback { throws ClassNotFoundException, Exception { mUsed = true; + if (className == null) { + // Just make a plain <View> if you specify <view> without a class= attribute. + className = CLASS_VIEW; + } + // look for a cached version Class<?> clazz = mLoadedClasses.get(className); if (clazz != null) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java index 35ef935..7b2fe84 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java @@ -21,11 +21,13 @@ import static com.android.SdkConstants.ATTR_CLASS; import static com.android.SdkConstants.ATTR_LAYOUT; import static com.android.SdkConstants.ATTR_NAME; import static com.android.SdkConstants.ATTR_TAG; +import static com.android.SdkConstants.CLASS_VIEW; import static com.android.SdkConstants.FQCN_GESTURE_OVERLAY_VIEW; import static com.android.SdkConstants.REQUEST_FOCUS; import static com.android.SdkConstants.VIEW_FRAGMENT; import static com.android.SdkConstants.VIEW_INCLUDE; import static com.android.SdkConstants.VIEW_MERGE; +import static com.android.SdkConstants.VIEW_TAG; import com.android.SdkConstants; import com.android.ide.common.api.IAttributeInfo.Format; @@ -168,6 +170,14 @@ public final class LayoutDescriptors implements IDescriptorProvider { newDescriptors.addAll(newLayouts); newDescriptors.addAll(newViews); + ViewElementDescriptor viewTag = createViewTag(frameLayoutAttrs); + newViews.add(viewTag); + newDescriptors.add(viewTag); + + ViewElementDescriptor requestFocus = createRequestFocus(); + newViews.add(requestFocus); + newDescriptors.add(requestFocus); + // Link all layouts to everything else here.. recursively for (ViewElementDescriptor layoutDesc : newLayouts) { layoutDesc.setChildren(newDescriptors); @@ -184,10 +194,6 @@ public final class LayoutDescriptors implements IDescriptorProvider { fixSuperClasses(infoDescMap); - ViewElementDescriptor requestFocus = createRequestFocus(); - newViews.add(requestFocus); - newDescriptors.add(requestFocus); - // The <merge> tag can only be a root tag, so it is added at the end. // It gets everything else as children but it is not made a child itself. ViewElementDescriptor mergeTag = createMerge(frameLayoutAttrs); @@ -305,7 +311,7 @@ public final class LayoutDescriptors implements IDescriptorProvider { } /** - * Creates a new <include> descriptor and adds it to the list of view descriptors. + * Creates a new {@code <include>} descriptor and adds it to the list of view descriptors. * * @param knownViews A list of view descriptors being populated. Also used to find the * View descriptor and extract its layout attributes. @@ -456,6 +462,37 @@ public final class LayoutDescriptors implements IDescriptorProvider { } /** + * Creates and returns a new {@code <view>} descriptor. + * @param viewLayoutAttribs The layout attributes to use for the new descriptor + * @param styleMap The style map provided by the SDK + */ + private ViewElementDescriptor createViewTag(AttributeDescriptor[] viewLayoutAttribs) { + String xmlName = VIEW_TAG; + + TextAttributeDescriptor classAttribute = new ClassAttributeDescriptor( + CLASS_VIEW, + ATTR_CLASS, null /* namespace */, + new AttributeInfo(ATTR_CLASS, Format.STRING_SET), + true /*mandatory*/) + .setTooltip("Supply the name of the view class to instantiate"); + + // Create the include descriptor + ViewElementDescriptor desc = new ViewElementDescriptor(xmlName, + xmlName, // ui_name + xmlName, // "class name"; the GLE only treats this as an element tag + "A view tag whose class attribute names the class to be instantiated", // tooltip + null, // sdk_url + new AttributeDescriptor[] { // attributes + classAttribute + }, + viewLayoutAttribs, // layout attributes + null, // children + false /* mandatory */); + + return desc; + } + + /** * Creates and returns a new {@code <requestFocus>} descriptor. */ private ViewElementDescriptor createRequestFocus() { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/ViewElementDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/ViewElementDescriptor.java index 466720a..7999524 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/ViewElementDescriptor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/ViewElementDescriptor.java @@ -19,6 +19,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout.descriptors; import static com.android.SdkConstants.ANDROID_VIEW_PKG; import static com.android.SdkConstants.ANDROID_WEBKIT_PKG; import static com.android.SdkConstants.ANDROID_WIDGET_PREFIX; +import static com.android.SdkConstants.VIEW; +import static com.android.SdkConstants.VIEW_TAG; import com.android.ide.common.resources.platform.AttributeInfo; import com.android.ide.eclipse.adt.AdtPlugin; @@ -188,6 +190,10 @@ public class ViewElementDescriptor extends ElementDescriptor { // "android.gesture.GestureOverlayView" in their XML, we need to look up // only by basename name = name.substring(name.lastIndexOf('.') + 1); + } else if (VIEW_TAG.equals(name)) { + // Can't have both view.png and View.png; issues on case sensitive vs + // case insensitive file systems + name = VIEW; } Image icon = factory.getIcon(name); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java index 472b158..388907a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java @@ -21,6 +21,7 @@ import static com.android.SdkConstants.ATTR_ID; import static com.android.SdkConstants.AUTO_URI; import static com.android.SdkConstants.CLASS_FRAGMENT; import static com.android.SdkConstants.CLASS_V4_FRAGMENT; +import static com.android.SdkConstants.CLASS_VIEW; import static com.android.SdkConstants.NEW_ID_PREFIX; import static com.android.SdkConstants.URI_PREFIX; @@ -512,7 +513,8 @@ class ClientRulesEngine implements IClientRulesEngine { int modifiers = typeInfoRequestor.getModifiers(); if (!Flags.isPublic(modifiers) || Flags.isInterface(modifiers) - || Flags.isEnum(modifiers)) { + || Flags.isEnum(modifiers) + || Flags.isAbstract(modifiers)) { return false; } return true; @@ -544,6 +546,98 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override + public String displayCustomViewClassInput() { + try { + IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); + IProject project = mRulesEngine.getProject(); + final IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); + if (javaProject != null) { + // Look up sub-types of each (new fragment class and compatibility fragment + // class, if any) and merge the two arrays - then create a scope from these + // elements. + IType[] viewTypes = new IType[0]; + IType fragmentType = javaProject.findType(CLASS_VIEW); + if (fragmentType != null) { + ITypeHierarchy hierarchy = + fragmentType.newTypeHierarchy(new NullProgressMonitor()); + viewTypes = hierarchy.getAllSubtypes(fragmentType); + } + scope = SearchEngine.createJavaSearchScope(viewTypes, IJavaSearchScope.SOURCES); + } + + Shell parent = AdtPlugin.getShell(); + final AtomicReference<String> returnValue = + new AtomicReference<String>(); + final AtomicReference<SelectionDialog> dialogHolder = + new AtomicReference<SelectionDialog>(); + final SelectionDialog dialog = JavaUI.createTypeDialog( + parent, + new ProgressMonitorDialog(parent), + scope, + IJavaElementSearchConstants.CONSIDER_CLASSES, false, + // Use ? as a default filter to fill dialog with matches + "?", //$NON-NLS-1$ + new TypeSelectionExtension() { + @Override + public Control createContentArea(Composite parentComposite) { + Composite composite = new Composite(parentComposite, SWT.NONE); + composite.setLayout(new GridLayout(1, false)); + Button button = new Button(composite, SWT.PUSH); + button.setText("Create New..."); + button.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + String fqcn = createNewCustomViewClass(javaProject); + if (fqcn != null) { + returnValue.set(fqcn); + dialogHolder.get().close(); + } + } + }); + return composite; + } + + @Override + public ITypeInfoFilterExtension getFilterExtension() { + return new ITypeInfoFilterExtension() { + @Override + public boolean select(ITypeInfoRequestor typeInfoRequestor) { + int modifiers = typeInfoRequestor.getModifiers(); + if (!Flags.isPublic(modifiers) + || Flags.isInterface(modifiers) + || Flags.isEnum(modifiers) + || Flags.isAbstract(modifiers)) { + return false; + } + return true; + } + }; + } + }); + dialogHolder.set(dialog); + + dialog.setTitle("Choose Custom View Class"); + dialog.setMessage("Select a Custom View class (? = any character, * = any string):"); + if (dialog.open() == IDialogConstants.CANCEL_ID) { + return null; + } + if (returnValue.get() != null) { + return returnValue.get(); + } + + Object[] types = dialog.getResult(); + if (types != null && types.length > 0) { + return ((IType) types[0]).getFullyQualifiedName(); + } + } catch (JavaModelException e) { + AdtPlugin.log(e, null); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + return null; + } + + @Override public void redraw() { mRulesEngine.getEditor().getCanvasControl().redraw(); } @@ -583,13 +677,17 @@ class ClientRulesEngine implements IClientRulesEngine { return (int) (pixels / mRulesEngine.getEditor().getCanvasControl().getScale()); } - String createNewFragmentClass(IJavaProject javaProject) { + private String createNewFragmentClass(IJavaProject javaProject) { NewClassWizardPage page = new NewClassWizardPage(); IProject project = mRulesEngine.getProject(); - IAndroidTarget target = Sdk.getCurrent().getTarget(project); + Sdk sdk = Sdk.getCurrent(); + if (sdk == null) { + return null; + } + IAndroidTarget target = sdk.getTarget(project); String superClass; - if (target.getVersion().getApiLevel() < 11) { + if (target == null || target.getVersion().getApiLevel() < 11) { superClass = CLASS_V4_FRAGMENT; } else { superClass = CLASS_FRAGMENT; @@ -615,6 +713,32 @@ class ClientRulesEngine implements IClientRulesEngine { } } + private String createNewCustomViewClass(IJavaProject javaProject) { + NewClassWizardPage page = new NewClassWizardPage(); + + IProject project = mRulesEngine.getProject(); + String superClass = CLASS_VIEW; + page.setSuperClass(superClass, true /* canBeModified */); + IPackageFragmentRoot root = ManifestInfo.getSourcePackageRoot(javaProject); + if (root != null) { + page.setPackageFragmentRoot(root, true /* canBeModified */); + } + ManifestInfo manifestInfo = ManifestInfo.get(project); + IPackageFragment pkg = manifestInfo.getPackageFragment(); + if (pkg != null) { + page.setPackageFragment(pkg, true /* canBeModified */); + } + OpenNewClassWizardAction action = new OpenNewClassWizardAction(); + action.setConfiguredWizardPage(page); + action.run(); + IType createdType = page.getCreatedType(); + if (createdType != null) { + return createdType.getFullyQualifiedName(); + } else { + return null; + } + } + @Override public @NonNull String getUniqueId(@NonNull String fqcn) { UiDocumentNode root = mRulesEngine.getEditor().getModel(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java index f7eac4434..8f99237 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java @@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gre; import static com.android.SdkConstants.ANDROID_WIDGET_PREFIX; import static com.android.SdkConstants.VIEW_MERGE; +import static com.android.SdkConstants.VIEW_TAG; import com.android.annotations.NonNull; import com.android.annotations.Nullable; @@ -792,6 +793,12 @@ public class RulesEngine { String baseName = realFqcn.substring(dotIndex+1); // Capitalize rule class name to match naming conventions, if necessary (<merge>) if (Character.isLowerCase(baseName.charAt(0))) { + if (baseName.equals(VIEW_TAG)) { + // Hack: ViewRule is generic for the "View" class, so we can't use it + // for the special XML "view" tag (lowercase); instead, the rule is + // named "ViewTagRule" instead. + baseName = "ViewTag"; //$NON-NLS-1$ + } baseName = Character.toUpperCase(baseName.charAt(0)) + baseName.substring(1); } ruleClassName = packageName + "." + //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/extra-view-metadata.xml b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/extra-view-metadata.xml index 796843f..6a67b1d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/extra-view-metadata.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/extra-view-metadata.xml @@ -397,6 +397,10 @@ topAttrs="layout,inflatedId,visibility" render="skip" /> <view + class="view" + topAttrs="class" + render="skip" /> + <view class="android.gesture.GestureOverlayView" topAttrs="gestureStrokeType,uncertainGestureColor,eventsInterceptionEnabled,gestureColor,orientation" render="skip" /> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/uimodel/UiViewElementNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/uimodel/UiViewElementNode.java index 7050be4..d9d2722 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/uimodel/UiViewElementNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/uimodel/UiViewElementNode.java @@ -153,11 +153,17 @@ public class UiViewElementNode extends UiElementNode { if (className != null && className.length() > 0) { int index = className.lastIndexOf('.'); if (index != -1) { - className = className.substring(index + 1); + className = "customView"; //$NON-NLS-1$ } img = icons.getIcon(className); } } + + if (img == null) { + // Can't have both view.png and View.png; issues on case sensitive vs + // case insensitive file systems + img = icons.getIcon("View"); //$NON-NLS-1$ + } } if (img == null) { img = desc.getGenericIcon(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestContentAssist.java index 8f78a0f..1492adb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestContentAssist.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestContentAssist.java @@ -48,7 +48,7 @@ public final class ManifestContentAssist extends AndroidContentAssist { } @Override - protected void computeAttributeValues(List<ICompletionProposal> proposals, int offset, + protected boolean computeAttributeValues(List<ICompletionProposal> proposals, int offset, String parentTagName, String attributeName, Node node, String wordPrefix, boolean skipEndTag, int replaceLength) { if (attributeName.endsWith(ATTRIBUTE_MIN_SDK_VERSION) @@ -60,7 +60,11 @@ public final class ManifestContentAssist extends AndroidContentAssist { List<Pair<String, String>> choices = new ArrayList<Pair<String, String>>(); int max = AdtUtils.getHighestKnownApiLevel(); // Look for any more recent installed versions the user may have - IAndroidTarget[] targets = Sdk.getCurrent().getTargets(); + Sdk sdk = Sdk.getCurrent(); + if (sdk == null) { + return false; + } + IAndroidTarget[] targets = sdk.getTargets(); for (IAndroidTarget target : targets) { AndroidVersion version = target.getVersion(); int apiLevel = version.getApiLevel(); @@ -81,9 +85,10 @@ public final class ManifestContentAssist extends AndroidContentAssist { addMatchingProposals(proposals, choices.toArray(), offset, node, wordPrefix, needTag, true /* isAttribute */, false /* isNew */, skipEndTag /* skipEndTag */, replaceLength); + return true; } else { - super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node, - wordPrefix, skipEndTag, replaceLength); + return super.computeAttributeValues(proposals, offset, parentTagName, attributeName, + node, wordPrefix, skipEndTag, replaceLength); } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/model/UiClassAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/model/UiClassAttributeNode.java index a1a4b58..4c829d9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/model/UiClassAttributeNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/model/UiClassAttributeNode.java @@ -82,6 +82,10 @@ import org.eclipse.ui.forms.widgets.TableWrapData; import org.w3c.dom.Element; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * Represents an XML attribute for a class, that can be modified using a simple text field or @@ -686,7 +690,46 @@ public class UiClassAttributeNode extends UiTextAttributeNode { @Override public String[] getPossibleValues(String prefix) { - // TODO: compute a list of existing classes for content assist completion + // Compute a list of existing classes for content assist completion + IProject project = getProject(); + if (project == null || mReferenceClass == null) { + return null; + } + + try { + IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); + IType type = javaProject.findType(mReferenceClass); + // Use sets because query sometimes repeats the same class + Set<String> libraryTypes = new HashSet<String>(80); + Set<String> localTypes = new HashSet<String>(30); + if (type != null) { + ITypeHierarchy hierarchy = type.newTypeHierarchy(new NullProgressMonitor()); + IType[] allSubtypes = hierarchy.getAllSubtypes(type); + for (IType subType : allSubtypes) { + int flags = subType.getFlags(); + if (Flags.isPublic(flags) && !Flags.isAbstract(flags)) { + String fqcn = subType.getFullyQualifiedName(); + if (subType.getResource() != null) { + localTypes.add(fqcn); + } else { + libraryTypes.add(fqcn); + } + } + } + } + + List<String> local = new ArrayList<String>(localTypes); + List<String> library = new ArrayList<String>(libraryTypes); + Collections.sort(local); + Collections.sort(library); + List<String> combined = new ArrayList<String>(local.size() + library.size()); + combined.addAll(local); + combined.addAll(library); + return combined.toArray(new String[combined.size()]); + } catch (Exception e) { + AdtPlugin.log(e, null); + } + return null; } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/values/ValuesContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/values/ValuesContentAssist.java index bd6c079..d0ee92c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/values/ValuesContentAssist.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/values/ValuesContentAssist.java @@ -70,7 +70,7 @@ public class ValuesContentAssist extends AndroidContentAssist { } @Override - protected void computeAttributeValues(List<ICompletionProposal> proposals, int offset, + protected boolean computeAttributeValues(List<ICompletionProposal> proposals, int offset, String parentTagName, String attributeName, Node node, String wordPrefix, boolean skipEndTag, int replaceLength) { super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node, @@ -129,10 +129,12 @@ public class ValuesContentAssist extends AndroidContentAssist { addMatchingProposals(proposals, sorted.toArray(), offset, node, wordPrefix, needTag, true /* isAttribute */, false /* isNew */, skipEndTag /* skipEndTag */, replaceLength); - return; + return true; } } } + + return false; } @Override diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java index d048f43..d215f2f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java @@ -127,11 +127,15 @@ public final class ExportHelper { // get the jumbo mode option String forceJumboStr = projectState.getProperty(AdtConstants.DEX_OPTIONS_FORCEJUMBO); - Boolean b = Boolean.valueOf(forceJumboStr); + Boolean jumbo = Boolean.valueOf(forceJumboStr); + + String dexMergerStr = projectState.getProperty(AdtConstants.DEX_OPTIONS_DISABLE_MERGER); + Boolean dexMerger = Boolean.valueOf(dexMergerStr); BuildHelper helper = new BuildHelper(project, fakeStream, fakeStream, - b.booleanValue(), + jumbo.booleanValue(), + dexMerger.booleanValue(), debugMode, false /*verbose*/, null /*resourceMarker*/); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipant.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipant.java index 67f7d44..a5b29e3 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipant.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipant.java @@ -32,6 +32,7 @@ import com.android.annotations.NonNull; import com.android.ide.common.xml.ManifestData; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; import com.android.resources.ResourceFolderType; import com.android.utils.SdkUtils; @@ -51,10 +52,14 @@ import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.corext.refactoring.changes.RenamePackageChange; import org.eclipse.jdt.internal.corext.refactoring.rename.RenameCompilationUnitProcessor; import org.eclipse.jdt.internal.corext.refactoring.rename.RenameTypeProcessor; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Region; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.CompositeChange; +import org.eclipse.ltk.core.refactoring.FileStatusContext; import org.eclipse.ltk.core.refactoring.NullChange; import org.eclipse.ltk.core.refactoring.RefactoringStatus; +import org.eclipse.ltk.core.refactoring.RefactoringStatusContext; import org.eclipse.ltk.core.refactoring.TextFileChange; import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor; @@ -65,9 +70,11 @@ import org.eclipse.text.edits.TextEdit; import org.eclipse.wst.sse.core.StructuredModelManager; import org.eclipse.wst.sse.core.internal.provisional.IModelManager; import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; +import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; import org.w3c.dom.Attr; +import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -107,6 +114,44 @@ public class AndroidPackageRenameParticipant extends RenameParticipant { @Override public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) throws OperationCanceledException { + if (mAppPackage.equals(mOldPackage) && !mRefactoringAppPackage) { + IRegion region = null; + Document document = DomUtilities.getDocument(mManifestFile); + if (document != null && document.getDocumentElement() != null) { + Attr attribute = document.getDocumentElement().getAttributeNode(ATTR_PACKAGE); + if (attribute instanceof IndexedRegion) { + IndexedRegion ir = (IndexedRegion) attribute; + int start = ir.getStartOffset(); + region = new Region(start, ir.getEndOffset() - start); + } + } + if (region == null) { + region = new Region(0, 0); + } + // There's no line wrapping in the error dialog, so split up the message into + // individually digestible pieces of information + RefactoringStatusContext ctx = new FileStatusContext(mManifestFile, region); + RefactoringStatus status = RefactoringStatus.createInfoStatus( + "You are refactoring the same package as your application's " + + "package (specified in the manifest).\n", ctx); + status.addInfo( + "Note that this refactoring does NOT also update your " + + "application package.", ctx); + status.addInfo("The application package defines your application's identity.", ctx); + status.addInfo( + "If you change it, then it is considered to be a different application.", ctx); + status.addInfo("(Users of the previous version cannot update to the new version.)", + ctx); + status.addInfo( + "The application package, and the package containing the code, can differ.", + ctx); + status.addInfo( + "To really change application package, " + + "choose \"Android Tools\" > \"Rename Application Package.\" " + + "from the project context menu.", ctx); + return status; + } + return new RefactoringStatus(); } @@ -393,7 +438,10 @@ public class AndroidPackageRenameParticipant extends RenameParticipant { if (tag.equals(VIEW_TAG)) { classNode = element.getAttributeNode(ATTR_CLASS); } else if (tag.equals(VIEW_FRAGMENT)) { - classNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME); + classNode = element.getAttributeNode(ATTR_CLASS); + if (classNode == null) { + classNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME); + } } else if (element.hasAttributeNS(TOOLS_URI, ATTR_CONTEXT)) { classNode = element.getAttributeNodeNS(TOOLS_URI, ATTR_CONTEXT); if (classNode != null && classNode.getValue().startsWith(".")) { //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeMoveParticipant.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeMoveParticipant.java index 26ae8d0..7181f98 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeMoveParticipant.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeMoveParticipant.java @@ -277,7 +277,10 @@ public class AndroidTypeMoveParticipant extends MoveParticipant { } } } else if (tag.equals(VIEW_FRAGMENT)) { - Attr classNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME); + Attr classNode = element.getAttributeNode(ATTR_CLASS); + if (classNode == null) { + classNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME); + } if (classNode != null && classNode.getValue().equals(mOldFqcn)) { int start = RefactoringUtil.getAttributeValueRangeStart(classNode, document); if (start != -1) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeRenameParticipant.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeRenameParticipant.java index f454c68..383fd13 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeRenameParticipant.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeRenameParticipant.java @@ -291,7 +291,10 @@ public class AndroidTypeRenameParticipant extends RenameParticipant { } } } else if (tag.equals(VIEW_FRAGMENT)) { - Attr classNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME); + Attr classNode = element.getAttributeNode(ATTR_CLASS); + if (classNode == null) { + classNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME); + } if (classNode != null && classNode.getValue().equals(mOldFqcn)) { int start = RefactoringUtil.getAttributeValueRangeStart(classNode, document); if (start != -1) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringUtil.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringUtil.java index 41551a4..04ebcfa 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringUtil.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringUtil.java @@ -24,7 +24,9 @@ import static com.android.xml.AndroidManifest.ATTRIBUTE_PARENT_ACTIVITY_NAME; import static com.android.xml.AndroidManifest.ATTRIBUTE_TARGET_ACTIVITY; import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.xml.AndroidManifest; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; @@ -174,24 +176,47 @@ public class RefactoringUtil { * Returns whether the given manifest attribute should be considered to describe * a class name. These will be eligible for refactoring when classes are renamed * or moved. - * <p> - * TODO: Move to {@link RefactoringUtil} * * @param attribute the manifest attribute * @return true if this attribute can describe a class */ public static boolean isManifestClassAttribute(@NonNull Attr attribute) { - String name = attribute.getLocalName(); + return isManifestClassAttribute( + attribute.getOwnerElement().getTagName(), + attribute.getNamespaceURI(), + attribute.getLocalName()); + } + + /** + * Returns whether the given manifest attribute should be considered to describe + * a class name. These will be eligible for refactoring when classes are renamed + * or moved. + * + * @param tag the tag, if known + * @param uri the attribute namespace, if any + * @param name the attribute local name, if any + * @return true if this attribute can describe a class + */ + public static boolean isManifestClassAttribute( + @Nullable String tag, + @Nullable String uri, + @Nullable String name) { if (name == null) { return false; } - if (name.equals(ATTR_NAME) + if ((name.equals(ATTR_NAME) + && (AndroidManifest.NODE_ACTIVITY.equals(tag) + || AndroidManifest.NODE_APPLICATION.equals(tag) + || AndroidManifest.NODE_INSTRUMENTATION.equals(tag) + || AndroidManifest.NODE_PROVIDER.equals(tag) + || AndroidManifest.NODE_SERVICE.equals(tag) + || AndroidManifest.NODE_RECEIVER.equals(tag))) || name.equals(ATTRIBUTE_TARGET_ACTIVITY) || name.equals(ATTRIBUTE_MANAGE_SPACE_ACTIVITY) || name.equals(ATTRIBUTE_BACKUP_AGENT) || name.equals(ATTRIBUTE_PARENT_ACTIVITY_NAME)) { - return ANDROID_URI.equals(attribute.getNamespaceURI()); + return ANDROID_URI.equals(uri); } return false; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoring.java index ec40a6e..95ae529 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoring.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoring.java @@ -436,10 +436,13 @@ class ApplicationPackageNameRefactoring extends Refactoring { } else if (SdkConstants.EXT_XML.equals(file.getFileExtension())) { if (SdkConstants.FN_ANDROID_MANIFEST_XML.equals(file.getName())) { - - TextFileChange manifest_change = editAndroidManifest(file); - mChanges.add(manifest_change); - + // Ensure that this is the root manifest, not some other copy + // (such as the one in bin/) + IPath path = file.getFullPath(); + if (path.segmentCount() == 2) { + TextFileChange manifest_change = editAndroidManifest(file); + mChanges.add(manifest_change); + } } else { // Currently we only support Android resource XML files, diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java index ace88a1..28fb8c0 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java @@ -304,6 +304,7 @@ class NewXmlFileCreationPage extends WizardPage { if (SCROLL_VIEW.equals(root) || HORIZONTAL_SCROLL_VIEW.equals(root)) { return " <LinearLayout " //$NON-NLS-1$ + getDefaultAttrs(project, root).replace('\n', ' ') + + " android:orientation=\"vertical\"" //$NON-NLS-1$ + "></LinearLayout>\n"; //$NON-NLS-1$ } return null; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java index 2f9d939..fdb26b1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java @@ -61,6 +61,7 @@ public class NewProjectWizard extends TemplateWizard { private static final String ACTIVITY_TITLE = "activityTitle"; //$NON-NLS-1$ private static final String IS_LAUNCHER = "isLauncher"; //$NON-NLS-1$ static final String IS_NEW_PROJECT = "isNewProject"; //$NON-NLS-1$ + static final String IS_LIBRARY_PROJECT = "isLibraryProject"; //$NON-NLS-1$ static final String ATTR_COPY_ICONS = "copyIcons"; //$NON-NLS-1$ static final String ATTR_TARGET_API = "targetApi"; //$NON-NLS-1$ static final String ATTR_MIN_API = "minApi"; //$NON-NLS-1$ @@ -385,6 +386,7 @@ public class NewProjectWizard extends TemplateWizard { addProjectInfo(parameters); parameters.put(IS_NEW_PROJECT, true); + parameters.put(IS_LIBRARY_PROJECT, mValues.isLibrary); // Ensure that activities created as part of a new project are marked as // launcher activities parameters.put(IS_LAUNCHER, true); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java index 1d1eb1d..805399b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java @@ -22,6 +22,7 @@ import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectW import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_API_LEVEL; import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_PACKAGE_NAME; import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_TARGET_API; +import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.IS_LIBRARY_PROJECT; import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.IS_NEW_PROJECT; import static com.android.ide.eclipse.adt.internal.wizards.templates.NewTemplateWizard.BLANK_ACTIVITY; @@ -30,6 +31,7 @@ import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.internal.assetstudio.ConfigureAssetSetPage; import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState; import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; +import com.android.ide.eclipse.adt.internal.sdk.ProjectState; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.sdklib.IAndroidTarget; @@ -155,6 +157,9 @@ public class NewTemplateWizardState { parameters.put(ATTR_TARGET_API, manifest.getTargetSdkVersion()); parameters.put(ATTR_BUILD_API, getBuildApi()); parameters.put(ATTR_COPY_ICONS, mIconState == null); + ProjectState projectState = Sdk.getProjectState(project); + parameters.put(IS_LIBRARY_PROJECT, + projectState != null ? projectState.isLibrary() : false); List<Change> changes = getTemplateHandler().render(project, parameters); diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java index 55a6b0b..700e68b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java @@ -501,6 +501,28 @@ public class AndroidContentAssistTest extends AdtProjectTest { checkLayoutCompletion("navigation1.xml", "?android:a^ttr/alertDialogStyle"); } + public void testComplation77() throws Exception { + // Test <fragment class="^" completion + checkLayoutCompletion("fragmentlayout.xml", "android:name=\"^com"); + } + + public void testComplation78() throws Exception { + // Test <fragment android:name="^" completion + checkLayoutCompletion("fragmentlayout.xml", "class=\"^com"); + } + + public void testComplation79() throws Exception { + // Test tools context completion + checkLayoutCompletion("completion11.xml", "tools:context=\"^.MainActivity\""); + } + + public void testComplation80() throws Exception { + // Test manifest class completion + checkManifestCompletion("manifest.xml", "<activity android:name=\"^."); + } + + // TODO: Test <view completion! + // ---- Test *applying* code completion ---- // The following tests check -applying- a specific code completion @@ -796,6 +818,12 @@ public class AndroidContentAssistTest extends AdtProjectTest { "?android:attr/Textapp^", "?android:attr/textAppearanceLargeInverse"); } + public void testApplyCompletion47() throws Exception { + // Test applying <fragment android:name="^" completion + checkApplyLayoutCompletion("fragmentlayout.xml", "class=\"^com", + "android.app.ListFragment"); + } + // --- Code Completion test infrastructure ---- private void checkLayoutCompletion(String name, String caretLocation) throws Exception { @@ -944,11 +972,16 @@ public class AndroidContentAssistTest extends AdtProjectTest { sb.append("Code completion in " + basename + " for " + caretLocation + ":\n"); for (ICompletionProposal proposal : proposals) { // TODO: assertNotNull(proposal.getImage()); + int length = sb.length(); sb.append(proposal.getDisplayString().trim()); String help = proposal.getAdditionalProposalInfo(); if (help != null && help.trim().length() > 0) { sb.append(" : "); sb.append(help.replace('\n', ' ').trim()); + if (sb.length() > length + 300) { + sb.setLength(length + 300 - "...".length()); + sb.append("..."); + } } sb.append('\n'); } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutMetadataTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutMetadataTest.java index fa9e18f..c71064e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutMetadataTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutMetadataTest.java @@ -53,11 +53,11 @@ public class LayoutMetadataTest extends AdtProjectTest { assertNull(LayoutMetadata.getProperty(node, "foo")); Element element = (Element) node; - String prefix = XmlUtils.lookupNamespacePrefix(element, TOOLS_URI, null); + String prefix = XmlUtils.lookupNamespacePrefix(element, TOOLS_URI, null, false); if (prefix == null) { // Add in new prefix... prefix = XmlUtils.lookupNamespacePrefix(element, - TOOLS_URI, TOOLS_PREFIX); + TOOLS_URI, TOOLS_PREFIX, true); } element.setAttribute(prefix + ':' + "foo", "bar"); } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion11.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion11.txt index 8d25f95..20dad3a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion11.txt +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion11.txt @@ -63,3 +63,5 @@ Code completion in completion1.xml for ^<TextView: <android.gesture.GestureOverlayView ></android.gesture.GestureOverlayView> : GestureOverlayView specific attributes. <fragment /> : A Fragment is a piece of an application's user interface or behavior that can be placed in an Activity <include /> : Lets you statically include XML layouts inside other XML layouts. +<requestFocus /> : Requests focus for the parent element or one of its descendants +<view /> : A view tag whose class attribute names the class to be instantiated diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion12.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion12.txt index a5fe067..8da18db 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion12.txt +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion12.txt @@ -63,3 +63,5 @@ Code completion in completion1.xml for btn_default">^</FrameLayout>: <android.gesture.GestureOverlayView ></android.gesture.GestureOverlayView> : GestureOverlayView specific attributes. <fragment /> : A Fragment is a piece of an application's user interface or behavior that can be placed in an Activity <include /> : Lets you statically include XML layouts inside other XML layouts. +<requestFocus /> : Requests focus for the parent element or one of its descendants +<view /> : A view tag whose class attribute names the class to be instantiated diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion39.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion39.txt index ec756c7..2ac2d31 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion39.txt +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion39.txt @@ -29,7 +29,7 @@ android:minWidth : Makes the TextView be at least this many pixels wide. [dimen android:gravity : Specifies how to align the text by the view's x- and/or y-axis when the text is smaller than the view. [flag] android:scrollHorizontally : Whether the text is allowed to be wider than the view (and therefore can be scrolled horizontally). [boolean] android:password : Whether the characters of the field are displayed as password dots instead of themselves. * Deprecated: Use inputType instead. [boolean] -android:singleLine : Constrains the text to a single horizontally scrolling line instead of letting it wrap onto multiple lines, and advances focus instead of inserting a newline when you press the enter key. * Deprecated: This attribute is deprecated. Use "maxLines" instead to change the layout of a static text, and use the "textMultiLine" flag in the inputType attribute instead for editable text views (if both singleLine and inputType are supplied, the inputType flags will override the value of singleLine). [boolean] +android:singleLine : Constrains the text to a single horizontally scrolling line instead of letting it wrap onto multiple lines, and advances focus instead of inserting a newline when you press the enter key. * Deprecated: This attribute is deprecated. Use "maxLines" instead to change the layo... android:enabled : Specifies whether the widget is enabled. [boolean] android:selectAllOnFocus : If the text is selectable, select it all when the view takes focus. [boolean] android:includeFontPadding : Leave enough room for ascenders and descenders instead of using the font ascent and descent strictly. [boolean] diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion11-expected-complation79.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion11-expected-complation79.txt new file mode 100644 index 0000000..3748c77 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion11-expected-complation79.txt @@ -0,0 +1,10 @@ +Code completion in completion11.xml for tools:context="^.MainActivity": +android.accounts.AccountAuthenticatorActivity : <p>See <code><a href="/reference/android/app/SearchManager.html">android.app.SearchManager</a></code> for more details.</td> </tr> <tr class=" api apilevel-1" > <td class="jd-typecol">int</td> <td class="jd-linkcol"... +android.app.ActivityGroup : <p> <p class="caution"> <strong>This class was deprecated in API level 13</strong>.<br/> Use the new <code><a href="/reference/android/app/Fragment.html">Fragment</a></code> and <code><a href="/reference/android/app/FragmentManager.html">FragmentManager</... +android.app.AliasActivity : <p>See <code><a href="/reference/android/app/SearchManager.html">android.app.SearchManager</a></code> for more details.</td> </tr> <tr class=" api apilevel-1" > <td class="jd-typecol">int</td> <td class="jd-linkcol"><a href="/reference... +android.app.ExpandableListActivity : <p> ExpandableListActivity hosts a <code><a href="/reference/android/widget/ExpandableListView.html">ExpandableListView</a></code> object that can be bound to different data sources that provide a two-levels of data (the top-level is group, and below each ... +android.app.LauncherActivity : <div id="jd-header"> public abstract class <h1 itemprop="name">LauncherActivity</h1> extends <a href="/reference/android/app/ListActivity.html">ListActivity</a><br/> ... +android.app.ListActivity : <p> ListActivity hosts a <code><a href="/reference/android/widget/ListView.html">ListView</a></code> object that can be bound to different data sources, typically either an array or a Cursor holding query results. Binding, screen layout, and row layout are discussed ... +android.app.NativeActivity : <p>A typical manifest would look like: <pre><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.native_activity" android:versionCode="1" android:versionName="1.0"> <!-- This is the platform ... +android.app.TabActivity : <p> <p class="caution"> <strong>This class was deprecated in API level 13</strong>.<br/> New applications should use Fragments instead of this class; to continue to run on older devices, you can use the v4 support library which provides a version of the F... +android.preference.PreferenceActivity : <p>This activity shows one or more headers of preferences, each of which is associated with a <code><a href="/reference/android/preference/PreferenceFragment.html">PreferenceFragment</a></code> to display the preferences of that header. The actual layout... diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion5-expected-completion40.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion5-expected-completion40.txt index 01d86ac..a4cf0fa 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion5-expected-completion40.txt +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion5-expected-completion40.txt @@ -29,7 +29,7 @@ android:minWidth : Makes the TextView be at least this many pixels wide. [dimen android:gravity : Specifies how to align the text by the view's x- and/or y-axis when the text is smaller than the view. [flag] android:scrollHorizontally : Whether the text is allowed to be wider than the view (and therefore can be scrolled horizontally). [boolean] android:password : Whether the characters of the field are displayed as password dots instead of themselves. * Deprecated: Use inputType instead. [boolean] -android:singleLine : Constrains the text to a single horizontally scrolling line instead of letting it wrap onto multiple lines, and advances focus instead of inserting a newline when you press the enter key. * Deprecated: This attribute is deprecated. Use "maxLines" instead to change the layout of a static text, and use the "textMultiLine" flag in the inputType attribute instead for editable text views (if both singleLine and inputType are supplied, the inputType flags will override the value of singleLine). [boolean] +android:singleLine : Constrains the text to a single horizontally scrolling line instead of letting it wrap onto multiple lines, and advances focus instead of inserting a newline when you press the enter key. * Deprecated: This attribute is deprecated. Use "maxLines" instead to change the layo... android:enabled : Specifies whether the widget is enabled. [boolean] android:selectAllOnFocus : If the text is selectable, select it all when the view takes focus. [boolean] android:includeFontPadding : Leave enough room for ascenders and descenders instead of using the font ascent and descent strictly. [boolean] diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion9-expected-completion64.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion9-expected-completion64.txt index be2096b..2085e96 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion9-expected-completion64.txt +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion9-expected-completion64.txt @@ -65,3 +65,4 @@ Code completion in completion9.xml for ^<Button: <include /> : Lets you statically include XML layouts inside other XML layouts. <merge ></merge> : A root tag useful for XML layouts inflated using a ViewStub. <requestFocus /> : Requests focus for the parent element or one of its descendants +<view /> : A view tag whose class attribute names the class to be instantiated diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completionvalues1-expected-completion32.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completionvalues1-expected-completion32.txt index 825c7b5..57684d7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completionvalues1-expected-completion32.txt +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completionvalues1-expected-completion32.txt @@ -34,7 +34,7 @@ android:childIndicator : Indicator shown beside the child View. [reference] android:childIndicatorLeft : The left bound for a child's indicator. [dimension] android:childIndicatorRight : The right bound for a child's indicator. [dimension] android:choiceMode : Defines the choice behavior for the view. [enum] -class : Supply the name of the fragment class to instantiate +class : Supply the name of the view class to instantiate android:clickColor : Color of the outline of click feedback. [color] android:clickable : Defines whether this view reacts to click events. [boolean] android:clipChildren : Defines whether a child is limited to draw inside of its bounds or not. [boolean] @@ -244,7 +244,7 @@ android:showDividers : Setting for which dividers to show. [flag] android:showWeekNumber : Whether do show week numbers. [boolean] android:shownWeekCount : The number of weeks to be shown. [integer] android:shrinkColumns : The zero-based index of the columns to shrink. [string] -android:singleLine : Constrains the text to a single horizontally scrolling line instead of letting it wrap onto multiple lines, and advances focus instead of inserting a newline when you press the enter key. * Deprecated: This attribute is deprecated. Use "maxLines" instead to change the layout of a static text, and use the "textMultiLine" flag in the inputType attribute instead for editable text views (if both singleLine and inputType are supplied, the inputType flags will override the value of singleLine). [boolean] +android:singleLine : Constrains the text to a single horizontally scrolling line instead of letting it wrap onto multiple lines, and advances focus instead of inserting a newline when you press the enter key. * Deprecated: This attribute is deprecated. Use "maxLines" instead to change the layo... android:smoothScrollbar : When set to true, the list will use a more refined calculation method based on the pixels height of the items visible on screen. [boolean] android:soundEffectsEnabled : Boolean that controls whether a view should have sound effects enabled for events such as clicking and touching. [boolean] android:spacing : [dimension] diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/fragmentlayout-expected-applyCompletion47.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/fragmentlayout-expected-applyCompletion47.diff new file mode 100644 index 0000000..3ed60f1 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/fragmentlayout-expected-applyCompletion47.diff @@ -0,0 +1,4 @@ +Code completion in fragmentlayout.xml for class="^com selecting android.app.ListFragment: +@@ -16 +16 +- <fragment class="^com.android.eclipse.tests.TestFragment" ++ <fragment class="android.app.ListFragment^" diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/fragmentlayout-expected-complation77.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/fragmentlayout-expected-complation77.txt new file mode 100644 index 0000000..6e8687f --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/fragmentlayout-expected-complation77.txt @@ -0,0 +1,5 @@ +Code completion in fragmentlayout.xml for android:name="^com: +android.app.DialogFragment : <p>Implementations should override this class and implement <code><a href="/reference/android/app/Fragment.html#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)">onCreateView(LayoutInflater, ViewGroup, Bundle)</a></code> to supply ... +android.app.ListFragment : <p> ListFragment hosts a <code><a href="/reference/android/widget/ListView.html">ListView</a></code> object that can be bound to different data sources, typically either an array or a Cursor holding query results. Binding, screen layout, and row layout are discussed ... +android.preference.PreferenceFragment : <p> Furthermore, the preferences shown will follow the visual style of system preferences. It is easy to create a hierarchy of preferences (that can be shown on multiple screens) via XML. For these reasons, it is recommended to use this fragment (as a s... +android.webkit.WebViewFragment : <p> The WebView is automically paused or resumed when the Fragment is paused or resumed. </p> </div><!-- jd-descr --> <div class="jd-descr"> <h2>Summary</h2> <!-- =========== ENUM CONSTANT SUMMARY =========== --> <table id="... diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/fragmentlayout-expected-complation78.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/fragmentlayout-expected-complation78.txt new file mode 100644 index 0000000..e02637c --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/fragmentlayout-expected-complation78.txt @@ -0,0 +1,5 @@ +Code completion in fragmentlayout.xml for class="^com: +android.app.DialogFragment : <p>Implementations should override this class and implement <code><a href="/reference/android/app/Fragment.html#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)">onCreateView(LayoutInflater, ViewGroup, Bundle)</a></code> to supply ... +android.app.ListFragment : <p> ListFragment hosts a <code><a href="/reference/android/widget/ListView.html">ListView</a></code> object that can be bound to different data sources, typically either an array or a Cursor holding query results. Binding, screen layout, and row layout are discussed ... +android.preference.PreferenceFragment : <p> Furthermore, the preferences shown will follow the visual style of system preferences. It is easy to create a hierarchy of preferences (that can be shown on multiple screens) via XML. For these reasons, it is recommended to use this fragment (as a s... +android.webkit.WebViewFragment : <p> The WebView is automically paused or resumed when the Fragment is paused or resumed. </p> </div><!-- jd-descr --> <div class="jd-descr"> <h2>Summary</h2> <!-- =========== ENUM CONSTANT SUMMARY =========== --> <table id="... diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-complation80.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-complation80.txt new file mode 100644 index 0000000..cb1d0ce --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-complation80.txt @@ -0,0 +1,8 @@ +Code completion in manifest.xml for <activity android:name="^.: +android.accounts.AccountAuthenticatorActivity +android.app.ActivityGroup +android.app.AliasActivity +android.app.ExpandableListActivity +android.app.ListActivity +android.app.NativeActivity +android.app.TabActivity diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion69.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion69.txt index 1cd2f93..cf7e0f4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion69.txt +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion69.txt @@ -16,13 +16,3 @@ Code completion in manifest.xml for <uses-sdk android:minSdkVersion="^11" />: 3 : API 3: Android 1.5 (Cupcake) 2 : API 2: Android 1.1 1 : API 1: Android 1.0 -@string/ -@android: -@+id/ -@anim/ -@animator/ -@color/ -@drawable/ -@id/ -@layout/ -@style/ diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipantTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipantTest.java index a074146..bff6a0b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipantTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipantTest.java @@ -61,7 +61,8 @@ public class AndroidPackageRenameParticipantTest extends RefactoringTestBase { " + android:name=\"my.pkg.name.MainActivity\"\n" + " @@ -25 +25\n" + " - android:name=\".MainActivity2\"\n" + - " + android:name=\"my.pkg.name.MainActivity2\""); + " + android:name=\"my.pkg.name.MainActivity2\"", + true); } public void testRefactor1_noreferences() throws Exception { @@ -73,7 +74,8 @@ public class AndroidPackageRenameParticipantTest extends RefactoringTestBase { "CHANGES:\n" + "-------\n" + - "* Rename package 'com.example.refactoringtest' to 'my.pkg.name'"); + "* Rename package 'com.example.refactoringtest' to 'my.pkg.name'", + false); } public void testRefactor2() throws Exception { @@ -118,7 +120,8 @@ public class AndroidPackageRenameParticipantTest extends RefactoringTestBase { " + android:name=\"my.pkg.name.MainActivity\"\n" + " @@ -25 +25\n" + " - android:name=\".MainActivity2\"\n" + - " + android:name=\"my.pkg.name.MainActivity2\""); + " + android:name=\"my.pkg.name.MainActivity2\"", + true); } public void testRefactor2_renamesub() throws Exception { @@ -175,7 +178,8 @@ public class AndroidPackageRenameParticipantTest extends RefactoringTestBase { "* customviews.xml - /testRefactor2_renamesub/res/layout-land/customviews.xml\n" + " @@ -15 +15\n" + " - <com.example.refactoringtest.subpackage.CustomView2\n" + - " + <my.pkg.name.subpackage.CustomView2"); + " + <my.pkg.name.subpackage.CustomView2", + true); } public void testRefactor2_renamesub_norefs() throws Exception { @@ -188,7 +192,8 @@ public class AndroidPackageRenameParticipantTest extends RefactoringTestBase { "CHANGES:\n" + "-------\n" + - "* Rename package 'com.example.refactoringtest' and subpackages to 'my.pkg.name'"); + "* Rename package 'com.example.refactoringtest' and subpackages to 'my.pkg.name'", + false); } @@ -199,9 +204,13 @@ public class AndroidPackageRenameParticipantTest extends RefactoringTestBase { boolean renameSubpackages, boolean updateReferences, @NonNull String newName, - @NonNull String expected) throws Exception { + @NonNull String expected, + boolean expectedAppPackageRenameWarning) throws Exception { IProject project = createProject(testData); - renamePackage(project, renameSubpackages, updateReferences, newName, expected); + String expectedWarnings = expectedAppPackageRenameWarning ? + EXPECTED_WARNINGS_TEMPLATE.replace("PROJECTNAME", project.getName()) : null; + renamePackage(project, renameSubpackages, updateReferences, newName, expected, + expectedWarnings); } protected void renamePackage( @@ -209,7 +218,8 @@ public class AndroidPackageRenameParticipantTest extends RefactoringTestBase { boolean renameSubpackages, boolean updateReferences, @NonNull String newName, - @NonNull String expected) throws Exception { + @NonNull String expected, + @NonNull String expectedWarnings) throws Exception { ManifestInfo info = ManifestInfo.get(project); String currentPackage = info.getPackage(); assertNotNull(currentPackage); @@ -222,7 +232,7 @@ public class AndroidPackageRenameParticipantTest extends RefactoringTestBase { assertNotNull(processor); RenameRefactoring refactoring = new RenameRefactoring(processor); - checkRefactoring(refactoring, expected); + checkRefactoring(refactoring, expected, expectedWarnings); } private static IPackageFragment getPackageFragment(IProject project, String pkg) @@ -240,4 +250,44 @@ public class AndroidPackageRenameParticipantTest extends RefactoringTestBase { } return pkgFragment; } + + private static String EXPECTED_WARNINGS_TEMPLATE = + "<INFO\n" + + "\t\n" + + "INFO: You are refactoring the same package as your application's package (specified in the manifest).\n" + + "\n" + + "Context: L/PROJECTNAME/AndroidManifest.xml\n" + + "code: none\n" + + "Data: null\n" + + "\t\n" + + "INFO: Note that this refactoring does NOT also update your application package.\n" + + "Context: L/PROJECTNAME/AndroidManifest.xml\n" + + "code: none\n" + + "Data: null\n" + + "\t\n" + + "INFO: The application package defines your application's identity.\n" + + "Context: L/PROJECTNAME/AndroidManifest.xml\n" + + "code: none\n" + + "Data: null\n" + + "\t\n" + + "INFO: If you change it, then it is considered to be a different application.\n" + + "Context: L/PROJECTNAME/AndroidManifest.xml\n" + + "code: none\n" + + "Data: null\n" + + "\t\n" + + "INFO: (Users of the previous version cannot update to the new version.)\n" + + "Context: L/PROJECTNAME/AndroidManifest.xml\n" + + "code: none\n" + + "Data: null\n" + + "\t\n" + + "INFO: The application package, and the package containing the code, can differ.\n" + + "Context: L/PROJECTNAME/AndroidManifest.xml\n" + + "code: none\n" + + "Data: null\n" + + "\t\n" + + "INFO: To really change application package, choose \"Android Tools\" > \"Rename Application Package.\" from the project context menu.\n" + + "Context: L/PROJECTNAME/AndroidManifest.xml\n" + + "code: none\n" + + "Data: null\n" + + ">"; } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringTestBase.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringTestBase.java index 44fb522..8b7b817 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringTestBase.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringTestBase.java @@ -51,12 +51,19 @@ import java.util.List; @SuppressWarnings({"javadoc","restriction"}) public abstract class RefactoringTestBase extends AdtProjectTest { - protected void checkRefactoring(Refactoring refactoring, String expected) - throws Exception { + protected void checkRefactoring(Refactoring refactoring, String expected) throws Exception { + checkRefactoring(refactoring, expected, null); + } + + protected void checkRefactoring(Refactoring refactoring, String expected, + @Nullable String expectedWarnings) throws Exception { RefactoringStatus status = refactoring.checkAllConditions(new NullProgressMonitor()); assertNotNull(status); + if (expectedWarnings == null) { + expectedWarnings = "<OK\n>"; + } + assertEquals(status.toString().trim(), expectedWarnings.trim()); if (!status.isOK()) { - assertEquals(status.toString(), expected); return; } assertTrue(status.toString(), status.isOK()); @@ -634,5 +641,10 @@ public abstract class RefactoringTestBase extends AdtProjectTest { "res/values/styles.xml", // file 3 SAMPLE_STYLES, + + // Just a gen file, should not be refactored + "bin/AndroidManifest.xml", + SAMPLE_MANIFEST, + }; } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipantTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipantTest.java index 3a6859c..d3459b8 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipantTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipantTest.java @@ -230,7 +230,8 @@ public class RenameResourceParticipantTest extends RefactoringTestBase { "\n" + "* Rename 'testRefactor7/res/layout-land/activity_main.xml' to 'newlayout.xml'\n" + "\n" + - "* Rename 'testRefactor7/res/layout/activity_main.xml' to 'newlayout.xml'"); + "* Rename 'testRefactor7/res/layout/activity_main.xml' to 'newlayout.xml'", + null); } public void testRefactor8() throws Exception { @@ -270,7 +271,8 @@ public class RenameResourceParticipantTest extends RefactoringTestBase { "* R.java - /testRefactor8/gen/com/example/refactoringtest/R.java\n" + " @@ -23 +23\n" + " - public static final int activity_main=0x7f030000;\n" + - " + public static final int newlauncher=0x7f030000;"); + " + public static final int newlauncher=0x7f030000;", + null); } public void testInvalidName() throws Exception { @@ -280,6 +282,7 @@ public class RenameResourceParticipantTest extends RefactoringTestBase { true /*updateReferences*/, "Newlauncher", + "", "<ERROR\n" + "\t\n" + "ERROR: File-based resource names must start with a lowercase letter.\n" + @@ -338,8 +341,18 @@ public class RenameResourceParticipantTest extends RefactoringTestBase { boolean updateReferences, @NonNull String newName, @NonNull String expected) throws Exception { + renameResource(testData, resource, updateReferences, newName, expected, null); + } + + protected void renameResource( + @NonNull Object[] testData, + @NonNull Object resource, + boolean updateReferences, + @NonNull String newName, + @NonNull String expected, + @NonNull String expectedWarnings) throws Exception { IProject project = createProject(testData); - renameResource(project, resource, updateReferences, newName, expected); + renameResource(project, resource, updateReferences, newName, expected, expectedWarnings); } protected void renameResource( @@ -347,7 +360,8 @@ public class RenameResourceParticipantTest extends RefactoringTestBase { @NonNull Object resource, boolean updateReferences, @NonNull String newName, - @NonNull String expected) throws Exception { + @NonNull String expected, + @NonNull String expectedWarnings) throws Exception { RenameProcessor processor = null; if (resource instanceof String) { String url = (String) resource; @@ -382,6 +396,6 @@ public class RenameResourceParticipantTest extends RefactoringTestBase { assertNotNull(processor); RenameRefactoring refactoring = new RenameRefactoring(processor); - checkRefactoring(refactoring, expected); + checkRefactoring(refactoring, expected, expectedWarnings); } }
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoringTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoringTest.java new file mode 100644 index 0000000..742aa31 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoringTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ide.eclipse.adt.internal.refactorings.renamepackage; + +import com.android.annotations.NonNull; +import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; +import com.android.ide.eclipse.adt.internal.refactorings.core.RefactoringTestBase; + +import org.eclipse.core.resources.IProject; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.Name; + +@SuppressWarnings("javadoc") +public class ApplicationPackageNameRefactoringTest extends RefactoringTestBase { + public void testRefactor1() throws Exception { + renamePackage( + TEST_PROJECT, + "my.pkg.name", + + "CHANGES:\n" + + "-------\n" + + "* Refactoring Application package name\n" + + "\n" + + " * MainActivity2.java - /testRefactor1/src/com/example/refactoringtest/MainActivity2.java\n" + + " @@ -7 +7\n" + + " + import my.pkg.name.R;\n" + + "\n" + + "\n" + + " * MainActivity.java - /testRefactor1/src/com/example/refactoringtest/MainActivity.java\n" + + " @@ -7 +7\n" + + " + import my.pkg.name.R;\n" + + "\n" + + "\n" + + " * Make Manifest edits - /testRefactor1/AndroidManifest.xml\n" + + " @@ -3 +3\n" + + " - package=\"com.example.refactoringtest\"\n" + + " + package=\"my.pkg.name\"\n" + + " @@ -25 +25\n" + + " - android:name=\".MainActivity2\"\n" + + " + android:name=\"com.example.refactoringtest.MainActivity2\""); + } + + public void testRefactor2() throws Exception { + // Tests custom view handling + renamePackage( + TEST_PROJECT2, + "my.pkg.name", + + "CHANGES:\n" + + "-------\n" + + "* Refactoring Application package name\n" + + "\n" + + " * MyFragment.java - /testRefactor2/src/com/example/refactoringtest/MyFragment.java\n" + + " @@ -3 +3\n" + + " + import my.pkg.name.R;\n" + + "\n" + + "\n" + + " * MainActivity.java - /testRefactor2/src/com/example/refactoringtest/MainActivity.java\n" + + " @@ -7 +7\n" + + " + import my.pkg.name.R;\n" + + "\n" + + "\n" + + " * CustomView1.java - /testRefactor2/src/com/example/refactoringtest/CustomView1.java\n" + + " @@ -5 +5\n" + + " + import my.pkg.name.R;\n" + + "\n" + + "\n" + + " * Make Manifest edits - /testRefactor2/AndroidManifest.xml\n" + + " @@ -3 +3\n" + + " - package=\"com.example.refactoringtest\"\n" + + " + package=\"my.pkg.name\"\n" + + " @@ -25 +25\n" + + " - android:name=\".MainActivity2\"\n" + + " + android:name=\"com.example.refactoringtest.MainActivity2\""); + } + + // ---- Test infrastructure ---- + + protected void renamePackage( + @NonNull Object[] testData, + @NonNull String newName, + @NonNull String expected) throws Exception { + IProject project = createProject(testData); + renamePackage(project, newName, expected); + } + + protected void renamePackage( + @NonNull IProject project, + @NonNull String newName, + @NonNull String expected) throws Exception { + ManifestInfo info = ManifestInfo.get(project); + String currentPackage = info.getPackage(); + assertNotNull(currentPackage); + + final AST astValidator = AST.newAST(AST.JLS3); + Name oldPackageName = astValidator.newName(currentPackage); + Name newPackageName = astValidator.newName(newName); + ApplicationPackageNameRefactoring refactoring = + new ApplicationPackageNameRefactoring(project, oldPackageName, newPackageName); + checkRefactoring(refactoring, expected); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java index d0d2cd2..4b4bb81 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java @@ -359,6 +359,13 @@ public class LayoutTestBase extends TestCase { fail("Not supported in tests yet"); return false; } + + @Override + @Nullable + public String displayCustomViewClassInput() { + fail("Not supported in tests yet"); + return null; + } } public void testDummy() { |