aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2011-05-18 12:14:43 -0700
committerAndroid Code Review <code-review@android.com>2011-05-18 12:14:43 -0700
commitbf6b323f21012b8eb5e8d2e9ba424f71791db045 (patch)
tree9b18c5f6e3c73a024b874d5c90ed01a87b1d61d3 /eclipse
parentf257edb5a919e1449fa6c65a0841793315c45927 (diff)
parentcd05e93b1194c89fe9eca1ee4b999d2991334f4b (diff)
downloadsdk-bf6b323f21012b8eb5e8d2e9ba424f71791db045.zip
sdk-bf6b323f21012b8eb5e8d2e9ba424f71791db045.tar.gz
sdk-bf6b323f21012b8eb5e8d2e9ba424f71791db045.tar.bz2
Merge "Basic fragment support" into tools-adt_r11
Diffstat (limited to 'eclipse')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/icons/fragment.pngbin0 -> 473 bytes
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FragmentRule.java44
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java27
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java116
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java123
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/extra-view-metadata.xml5
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/xml/Hyperlinks.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java5
12 files changed, 325 insertions, 18 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/fragment.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/fragment.png
new file mode 100644
index 0000000..35b62b6
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/fragment.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java
index 6aa4776..e31323b 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java
@@ -147,6 +147,14 @@ public interface IClientRulesEngine {
String displayIncludeSourceInput();
/**
+ * Displays an input dialog tailored for inputing the source of a {@code <fragment>}
+ * layout tag.
+ *
+ * @return the fully qualified class name of the fragment activity
+ */
+ String displayFragmentSourceInput();
+
+ /**
* Select the given nodes
*
* @param nodes the nodes to be selected, never null
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
new file mode 100644
index 0000000..3e10efd
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FragmentRule.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 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.ide.common.layout.LayoutConstants.ANDROID_URI;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_NAME;
+
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.IViewRule;
+import com.android.ide.common.api.InsertType;
+
+/**
+ * An {@link IViewRule} for the special XML {@code <fragment>} tag.
+ */
+public class FragmentRule extends BaseViewRule {
+ @Override
+ public void onCreate(INode node, INode parent, InsertType insertType) {
+ // When dropping a fragment tag, ask the user which layout to include.
+ if (insertType == InsertType.CREATE) { // NOT InsertType.CREATE_PREVIEW
+ String fqcn = mRulesEngine.displayFragmentSourceInput();
+ if (fqcn != null) {
+ node.editXml("Add Fragment",
+ new PropertySettingNodeHandler(ANDROID_URI, ATTR_NAME,
+ 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/common/layout/LayoutConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java
index 319a2b4d..825c84e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java
@@ -32,12 +32,10 @@ public class LayoutConstants {
/** The element name in a <code>&lt;view class="..."&gt;</code> element. */
public static final String VIEW = "view"; //$NON-NLS-1$
- /** The element name in a <code>&lt;fragment android:name="..."&gt;</code> element. */
- public static final String FRAGMENT = "fragment"; //$NON-NLS-1$
-
/** The attribute name in a {@code <view class="...">} element. */
public static final String ATTR_CLASS = "class"; //$NON-NLS-1$
public static final String ATTR_ON_CLICK = "onClick"; //$NON-NLS-1$
+ public static final String ATTR_TAG = "tag"; //$NON-NLS-1$
// Some common layout element names
public static final String RELATIVE_LAYOUT = "RelativeLayout"; //$NON-NLS-1$
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 7383659..064094e 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
@@ -20,6 +20,7 @@ import static com.android.ide.common.layout.LayoutConstants.ANDROID_PKG_PREFIX;
import static com.android.ide.common.layout.LayoutConstants.CALENDAR_VIEW;
import static com.android.ide.common.layout.LayoutConstants.EXPANDABLE_LIST_VIEW;
import static com.android.ide.common.layout.LayoutConstants.LIST_VIEW;
+import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.VIEW_FRAGMENT;
import com.android.ide.common.rendering.LayoutLibrary;
import com.android.ide.common.rendering.api.AdapterBinding;
@@ -45,6 +46,7 @@ import com.android.util.Pair;
import org.eclipse.core.resources.IProject;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Set;
@@ -141,7 +143,9 @@ public final class ProjectCallback extends LegacyCallback {
} catch (Exception e) {
// Add the missing class to the list so that the renderer can print them later.
// no need to log this.
- mMissingClasses.add(className);
+ if (!className.equals(VIEW_FRAGMENT)) {
+ mMissingClasses.add(className);
+ }
}
try {
@@ -175,6 +179,27 @@ public final class ProjectCallback extends LegacyCallback {
Method m = view.getClass().getMethod("setText",
new Class<?>[] { CharSequence.class });
m.invoke(view, getShortClassName(className));
+
+ // Call MockView.setGravity(Gravity.CENTER) to get the text centered in
+ // MockViews.
+ // TODO: Do this in layoutlib's MockView class instead.
+ try {
+ // Look up android.view.Gravity#CENTER - or can we just hard-code
+ // the value (17) here?
+ Class<?> gravity =
+ Class.forName("android.view.Gravity", //$NON-NLS-1$
+ true, view.getClass().getClassLoader());
+ Field centerField = gravity.getField("CENTER"); //$NON-NLS-1$
+ int center = centerField.getInt(null);
+ m = view.getClass().getMethod("setGravity",
+ new Class<?>[] { Integer.TYPE });
+ // Center
+ //int center = (0x0001 << 4) | (0x0001 << 0);
+ m.invoke(view, Integer.valueOf(center));
+ } catch (Exception e) {
+ // Not important to center views
+ }
+
return view;
} catch (Exception e) {
// We failed to create and return a mock view.
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 172802e..f7019a5 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
@@ -16,8 +16,14 @@
package com.android.ide.eclipse.adt.internal.editors.layout.descriptors;
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_CLASS;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_NAME;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_TAG;
+
import com.android.ide.common.api.IAttributeInfo.Format;
import com.android.ide.common.resources.platform.AttributeInfo;
+import com.android.ide.common.resources.platform.DeclareStyleableInfo;
import com.android.ide.common.resources.platform.ViewClassInfo;
import com.android.ide.common.resources.platform.ViewClassInfo.LayoutParamsInfo;
import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
@@ -26,6 +32,8 @@ import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescript
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.SeparatorAttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.ClassAttributeDescriptor;
+import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants;
import java.util.ArrayList;
@@ -56,6 +64,13 @@ public final class LayoutDescriptors implements IDescriptorProvider {
public static final String VIEW_MERGE = "merge"; //$NON-NLS-1$
/**
+ * The XML name of the special {@code <fragment>} layout tag.
+ * A synthetic element with that name is created as part of the view descriptors list
+ * returned by {@link #getViewDescriptors()}.
+ */
+ public static final String VIEW_FRAGMENT = "fragment"; //$NON-NLS-1$
+
+ /**
* The XML name of the special {@code <view>} layout tag. This is used to add generic
* views with a class attribute to specify the view.
* <p>
@@ -144,8 +159,11 @@ public final class LayoutDescriptors implements IDescriptorProvider {
*
* @param views The list of views in the framework.
* @param layouts The list of layouts in the framework.
+ * @param styleMap A map from style names to style information provided by the SDK
+ * @param target The android target being initialized
*/
- public synchronized void updateDescriptors(ViewClassInfo[] views, ViewClassInfo[] layouts) {
+ public synchronized void updateDescriptors(ViewClassInfo[] views, ViewClassInfo[] layouts,
+ Map<String, DeclareStyleableInfo> styleMap, IAndroidTarget target) {
// This map links every ViewClassInfo to the ElementDescriptor we created.
// It is filled by convertView() and used later to fix the super-class hierarchy.
@@ -172,6 +190,15 @@ public final class LayoutDescriptors implements IDescriptorProvider {
}
}
+ // Find View and inherit all its layout attributes
+ AttributeDescriptor[] viewLayoutAttribs = findViewLayoutAttributes(
+ SdkConstants.CLASS_FRAMELAYOUT, newLayouts);
+
+ if (target.getVersion().getApiLevel() >= 4) {
+ ViewElementDescriptor fragmentTag = createFragment(viewLayoutAttribs, styleMap);
+ newViews.add(fragmentTag);
+ }
+
List<ElementDescriptor> newDescriptors = new ArrayList<ElementDescriptor>();
newDescriptors.addAll(newLayouts);
newDescriptors.addAll(newViews);
@@ -185,7 +212,7 @@ public final class LayoutDescriptors implements IDescriptorProvider {
// 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(newLayouts);
+ ViewElementDescriptor mergeTag = createMerge(viewLayoutAttribs);
mergeTag.setChildren(newDescriptors); // mergeTag makes a copy of the list
newDescriptors.add(mergeTag);
newLayouts.add(mergeTag);
@@ -352,16 +379,11 @@ public final class LayoutDescriptors implements IDescriptorProvider {
/**
* Creates and returns a new {@code <merge>} descriptor.
- * @param knownLayouts A list of all known layout view descriptors, used to find the
- * FrameLayout descriptor and extract its layout attributes.
+ * @param viewLayoutAttribs The layout attributes to use for the new descriptor
*/
- private ViewElementDescriptor createMerge(List<ViewElementDescriptor> knownLayouts) {
+ private ViewElementDescriptor createMerge(AttributeDescriptor[] viewLayoutAttribs) {
String xml_name = VIEW_MERGE;
- // Find View and inherit all its layout attributes
- AttributeDescriptor[] viewLayoutAttribs = findViewLayoutAttributes(
- SdkConstants.CLASS_FRAMELAYOUT, knownLayouts);
-
// Create the include descriptor
ViewElementDescriptor desc = new ViewElementDescriptor(xml_name, // xml_name
xml_name, // ui_name
@@ -377,6 +399,82 @@ public final class LayoutDescriptors implements IDescriptorProvider {
}
/**
+ * Creates and returns a new {@code <fragment>} descriptor.
+ * @param viewLayoutAttribs The layout attributes to use for the new descriptor
+ * @param styleMap The style map provided by the SDK
+ */
+ private ViewElementDescriptor createFragment(AttributeDescriptor[] viewLayoutAttribs,
+ Map<String, DeclareStyleableInfo> styleMap) {
+ String xml_name = VIEW_FRAGMENT;
+ final ViewElementDescriptor descriptor;
+
+ // First try to create the descriptor from metadata in attrs.xml:
+ DeclareStyleableInfo style = styleMap.get("Fragment"); //$NON-NLS-1$
+ String fragmentTooltip =
+ "A Fragment is a piece of an application's user interface or behavior that "
+ + "can be placed in an Activity";
+ String sdkUrl = "http://developer.android.com/guide/topics/fundamentals/fragments.html";
+ ClassAttributeDescriptor classAttribute = new ClassAttributeDescriptor(
+ // Should accept both CLASS_V4_FRAGMENT and CLASS_FRAGMENT
+ null /*superClassName*/,
+ ATTR_CLASS, ATTR_CLASS, null /* namespace */,
+ "Supply the name of the fragment class to instantiate",
+ new AttributeInfo(ATTR_CLASS, new Format[] { Format.STRING}),
+ true /*mandatory*/);
+
+ if (style != null) {
+ descriptor = new ViewElementDescriptor(
+ VIEW_FRAGMENT, VIEW_FRAGMENT, VIEW_FRAGMENT,
+ fragmentTooltip, // tooltip
+ sdkUrl, //,
+ null /* attributes */,
+ viewLayoutAttribs, // layout attributes
+ null /*childrenElements*/,
+ false /*mandatory*/);
+ ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>();
+ // The class attribute is not included in the attrs.xml
+ descs.add(classAttribute);
+ DescriptorsUtils.appendAttributes(descs,
+ null, // elementName
+ SdkConstants.NS_RESOURCES,
+ style.getAttributes(),
+ null, // requiredAttributes
+ null); // overrides
+ //descriptor.setTooltip(style.getJavaDoc());
+ descriptor.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()]));
+ } else {
+ // The above will only work on API 11 and up. However, fragments are *also* available
+ // on older platforms, via the fragment support library, so add in a manual
+ // entry if necessary.
+ descriptor = new ViewElementDescriptor(xml_name, // xml_name
+ xml_name, // ui_name
+ xml_name, // "class name"; the GLE only treats this as an element tag
+ fragmentTooltip,
+ sdkUrl,
+ new AttributeDescriptor[] {
+ new ClassAttributeDescriptor(
+ null /*superClassName*/,
+ ATTR_NAME, ATTR_NAME, ANDROID_URI,
+ "Supply the name of the fragment class to instantiate",
+ new AttributeInfo(ATTR_NAME, new Format[] { Format.STRING}),
+ true /*mandatory*/),
+ classAttribute,
+ new ClassAttributeDescriptor(
+ null /*superClassName*/,
+ ATTR_TAG, ATTR_TAG, ANDROID_URI,
+ "Supply a tag for the top-level view containing a String",
+ new AttributeInfo(ATTR_TAG, new Format[] { Format.STRING}),
+ true /*mandatory*/),
+ }, // attributes
+ viewLayoutAttribs, // layout attributes
+ null, // children
+ false /* mandatory */);
+ }
+
+ return descriptor;
+ }
+
+ /**
* Finds the descriptor and retrieves all its layout attributes.
*/
private AttributeDescriptor[] findViewLayoutAttributes(
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 6838432..2d0dc66 100755
--- 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,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gre;
import static com.android.ide.common.layout.LayoutConstants.ANDROID_WIDGET_PREFIX;
import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.VIEW_MERGE;
+import static com.android.sdklib.SdkConstants.CLASS_FRAGMENT;
+import static com.android.sdklib.SdkConstants.CLASS_V4_FRAGMENT;
import com.android.ide.common.api.DropFeedback;
import com.android.ide.common.api.IClientRulesEngine;
@@ -41,6 +43,7 @@ import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SelectionManager;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SimpleElement;
import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
+import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
import com.android.ide.eclipse.adt.internal.resources.CyclicDependencyValidator;
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
@@ -54,12 +57,32 @@ import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.internal.project.ProjectProperties;
import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.ITypeHierarchy;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchEngine;
+import org.eclipse.jdt.ui.IJavaElementSearchConstants;
+import org.eclipse.jdt.ui.JavaUI;
+import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension;
+import org.eclipse.jdt.ui.dialogs.ITypeInfoRequestor;
+import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.dialogs.SelectionDialog;
import java.io.File;
import java.net.MalformedURLException;
@@ -764,7 +787,6 @@ public class RulesEngine {
* with a few methods they can use to use functionality from this {@link RulesEngine}.
*/
private class ClientRulesEngineImpl implements IClientRulesEngine {
-
private final String mFqcn;
public ClientRulesEngineImpl(String fqcn) {
@@ -960,5 +982,104 @@ public class RulesEngine {
}
});
}
+
+ public String displayFragmentSourceInput() {
+ try {
+ // Compute a search scope: We need to merge all the subclasses
+ // android.app.Fragment and android.support.v4.app.Fragment
+ IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
+ IJavaProject javaProject = BaseProjectHelper.getJavaProject(mProject);
+ if (javaProject != null) {
+ IType oldFragmentType = javaProject.findType(CLASS_V4_FRAGMENT);
+
+ // First check to make sure fragments are available, and if not,
+ // warn the user.
+ IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
+ if (target.getVersion().getApiLevel() < 11 && oldFragmentType == null) {
+ // Compatibility library must be present
+ Status status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, 0,
+ "Fragments require API level 11 or higher, or a compatibility "
+ + "library for older versions.\n\n"
+ + "Please install the \"Android Compatibility Package\" from "
+ + "the SDK manager and add its .jar file "
+ + "(extras/android/compatibility/v4/android-support-v4.jar) "
+ + "to the project's "
+ + " Java Build Path.", null);
+ ErrorDialog.openError(Display.getCurrent().getActiveShell(),
+ "Fragment Warning", null, status);
+
+ // TODO: Offer to automatically perform configuration for the user;
+ // either upgrade project to require API 11, or first install the
+ // compatibility library via the SDK manager and then adding
+ // ${SDK_HOME}/extras/android/compatibility/v4/android-support-v4.jar
+ // to the project jar dependencies.
+ return 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[] fragmentTypes = new IType[0];
+ IType[] oldFragmentTypes = new IType[0];
+ if (oldFragmentType != null) {
+ ITypeHierarchy hierarchy =
+ oldFragmentType.newTypeHierarchy(new NullProgressMonitor());
+ oldFragmentTypes = hierarchy.getAllSubtypes(oldFragmentType);
+ }
+ IType fragmentType = javaProject.findType(CLASS_FRAGMENT);
+ if (fragmentType != null) {
+ ITypeHierarchy hierarchy =
+ fragmentType.newTypeHierarchy(new NullProgressMonitor());
+ fragmentTypes = hierarchy.getAllSubtypes(fragmentType);
+ }
+ IType[] subTypes = new IType[fragmentTypes.length + oldFragmentTypes.length];
+ System.arraycopy(fragmentTypes, 0, subTypes, 0, fragmentTypes.length);
+ System.arraycopy(oldFragmentTypes, 0, subTypes, fragmentTypes.length,
+ oldFragmentTypes.length);
+ scope = SearchEngine.createJavaSearchScope(subTypes, IJavaSearchScope.SOURCES);
+ }
+
+ Shell parent = AdtPlugin.getDisplay().getActiveShell();
+ 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 ITypeInfoFilterExtension getFilterExtension() {
+ return new ITypeInfoFilterExtension() {
+ public boolean select(ITypeInfoRequestor typeInfoRequestor) {
+ int modifiers = typeInfoRequestor.getModifiers();
+ if (!Flags.isPublic(modifiers)
+ || Flags.isInterface(modifiers)
+ || Flags.isEnum(modifiers)) {
+ return false;
+ }
+ return true;
+ }
+ };
+ }
+ });
+
+ dialog.setTitle("Choose Fragment Class");
+ dialog.setMessage("Select a Fragment class (? = any character, * = any string):");
+ if (dialog.open() == IDialogConstants.CANCEL_ID) {
+ return null;
+ }
+
+ 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;
+ }
}
}
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 0870f69..7f11574 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
@@ -168,6 +168,11 @@
name="Include Other Layout"
render="skip" />
<view
+ class="fragment"
+ name="Fragment"
+ fill="opposite"
+ render="skip" />
+ <view
class="android.widget.TableLayout"
fill="opposite"
render="skip" />
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java
index e2b6ccf..47f22a1 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java
@@ -247,6 +247,8 @@ public class UiElementNode implements IPropertySource {
attr = _Element_getAttributeNS(elem,
SdkConstants.NS_RESOURCES,
AndroidManifestDescriptors.ANDROID_LABEL_ATTR);
+ } else if (mXmlNode.getNodeName().equals(LayoutDescriptors.VIEW_FRAGMENT)) {
+ attr = attr.substring(attr.lastIndexOf('.') + 1);
}
if (attr == null || attr.length() == 0) {
attr = _Element_getAttributeNS(elem,
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/xml/Hyperlinks.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/xml/Hyperlinks.java
index c30b78a..069d475 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/xml/Hyperlinks.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/xml/Hyperlinks.java
@@ -20,7 +20,6 @@ import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
import static com.android.ide.common.layout.LayoutConstants.ATTR_CLASS;
import static com.android.ide.common.layout.LayoutConstants.ATTR_NAME;
import static com.android.ide.common.layout.LayoutConstants.ATTR_ON_CLICK;
-import static com.android.ide.common.layout.LayoutConstants.FRAGMENT;
import static com.android.ide.common.layout.LayoutConstants.NEW_ID_PREFIX;
import static com.android.ide.common.layout.LayoutConstants.VIEW;
import static com.android.ide.common.resources.ResourceResolver.PREFIX_ANDROID_RESOURCE_REF;
@@ -29,6 +28,7 @@ import static com.android.ide.eclipse.adt.AdtConstants.ANDROID_PKG;
import static com.android.ide.eclipse.adt.AdtConstants.EXT_XML;
import static com.android.ide.eclipse.adt.AdtConstants.FN_RESOURCE_BASE;
import static com.android.ide.eclipse.adt.AdtConstants.FN_RESOURCE_CLASS;
+import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.VIEW_FRAGMENT;
import static com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors.NAME_ATTR;
import static com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors.ROOT_ELEMENT;
import static com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors.STYLE_ELEMENT;
@@ -340,8 +340,8 @@ public class Hyperlinks {
}
String tag = context.getElement().getTagName();
String attributeName = attribute.getLocalName();
- return ATTR_CLASS.equals(attributeName) && (VIEW.equals(tag) || FRAGMENT.equals(tag))
- || ATTR_NAME.equals(attributeName) && FRAGMENT.equals(tag);
+ return ATTR_CLASS.equals(attributeName) && (VIEW.equals(tag) || VIEW_FRAGMENT.equals(tag))
+ || ATTR_NAME.equals(attributeName) && VIEW_FRAGMENT.equals(tag);
}
/** Returns true if this represents an onClick attribute specifying a method handler */
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java
index 19b2e3d..1bdfd4e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java
@@ -199,7 +199,8 @@ public final class AndroidTargetParser {
}
LayoutDescriptors layoutDescriptors = new LayoutDescriptors();
- layoutDescriptors.updateDescriptors(layoutViewsInfo, layoutGroupsInfo);
+ layoutDescriptors.updateDescriptors(layoutViewsInfo, layoutGroupsInfo,
+ attrsXmlParser.getDeclareStyleableList(), mAndroidTarget);
progress.worked(1);
if (progress.isCanceled()) {
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 18d985e..a3d0f1b 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
@@ -253,6 +253,11 @@ public class LayoutTestBase extends TestCase {
public void select(Collection<INode> nodes) {
fail("Not supported in tests yet");
}
+
+ public String displayFragmentSourceInput() {
+ fail("Not supported in tests yet");
+ return null;
+ }
}
public void testDummy() {