aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/SupportLibraryHelper.java
blob: e1819b28358fb2e5dbb3f61984b997cda1334409 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
 * 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.project;

import static com.android.SdkConstants.FQCN_GRID_LAYOUT;
import static com.android.SdkConstants.FQCN_GRID_LAYOUT_V7;
import static com.android.SdkConstants.FQCN_SPACE;
import static com.android.SdkConstants.FQCN_SPACE_V7;

import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.eclipse.adt.AdtUtils;
import com.android.ide.eclipse.adt.internal.actions.AddSupportJarAction;
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.ProjectState.LibraryState;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;

import org.eclipse.core.resources.IProject;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;

/**
 * Helper class for the Android Support Library. The support library provides
 * (for example) a backport of GridLayout, which must be used as a library
 * project rather than a jar library since it has resources. This class provides
 * support for finding the library project, or downloading and installing it on
 * demand if it does not, as well as translating tags such as
 * {@code <GridLayout>} into {@code <com.android.support.v7.GridLayout>} if it
 * does not.
 */
public class SupportLibraryHelper {
    /**
     * Returns the correct tag to use for the given view tag. This is normally
     * the same as the tag itself. However, for some views which are not available
     * on all platforms, this will:
     * <ul>
     *  <li> Check if the view is available in the compatibility library,
     *       and if so, if the support library is not installed, will offer to
     *       install it via the SDK manager.
     *  <li> (The tool may also offer to adjust the minimum SDK of the project
     *       up to a level such that the given tag is supported directly, and then
     *       this method will return the original tag.)
     *  <li> Check whether the compatibility library is included in the project, and
     *       if not, offer to copy it into the workspace and add a library dependency.
     *  <li> Return the alternative tag. For example, for "GridLayout", it will
     *       (if the minimum SDK is less than 14) return "com.android.support.v7.GridLayout"
     *       instead.
     * </ul>
     *
     * @param project the project to add the dependency into
     * @param tag the tag to look up, such as "GridLayout"
     * @return the tag to use in the layout, normally the same as the input tag but possibly
     *      an equivalent compatibility library tag instead.
     */
    @NonNull
    public static String getTagFor(@NonNull IProject project, @NonNull String tag) {
        boolean isGridLayout = tag.equals(FQCN_GRID_LAYOUT);
        boolean isSpace = tag.equals(FQCN_SPACE);
        if (isGridLayout || isSpace) {
            int minSdk = ManifestInfo.get(project).getMinSdkVersion();
            if (minSdk < 14) {
                // See if the support library is installed in the SDK area
                // See if there is a local project in the workspace providing the
                // project
                IProject supportProject = getSupportProjectV7();
                if (supportProject != null) {
                    // Make sure I have a dependency on it
                    ProjectState state = Sdk.getProjectState(project);
                    if (state != null) {
                        for (LibraryState library : state.getLibraries()) {
                            if (supportProject.equals(library.getProjectState().getProject())) {
                                // Found it: you have the compatibility library and have linked
                                // to it: use the alternative tag
                                return isGridLayout ? FQCN_GRID_LAYOUT_V7 : FQCN_SPACE_V7;
                            }
                        }
                    }
                }

                // Ask user to install it
                String message = String.format(
                        "%1$s requires API level 14 or higher, or a compatibility "
                                + "library for older versions.\n\n"
                                + " Do you want to install the compatibility library?", tag);
                MessageDialog dialog =
                        new MessageDialog(
                                Display.getCurrent().getActiveShell(),
                                "Warning",
                                null,
                                message,
                                MessageDialog.QUESTION,
                                new String[] {
                                        "Install", "Cancel"
                                },
                                1 /* default button: Cancel */);
                int answer = dialog.open();
                if (answer == 0) {
                    if (supportProject != null) {
                        // Just add library dependency
                        if (!AddSupportJarAction.addLibraryDependency(
                                supportProject,
                                project,
                                true /* waitForFinish */)) {
                            return tag;
                        }
                    } else {
                        // Install library AND add dependency
                        if (!AddSupportJarAction.installGridLayoutLibrary(
                                project,
                                true /* waitForFinish */)) {
                            return tag;
                        }
                    }

                    return isGridLayout ? FQCN_GRID_LAYOUT_V7 : FQCN_SPACE_V7;
                }
            }
        }

        return tag;
    }

    /** Cache for {@link #getSupportProjectV7()} */
    private static IProject sCachedProject;

    /**
     * Finds and returns the support project in the workspace, if any.
     *
     * @return the android support library project, or null if not found
     */
    @Nullable
    public static IProject getSupportProjectV7() {
        if (sCachedProject != null) {
            if (sCachedProject.isAccessible()) {
                return sCachedProject;
            } else {
                sCachedProject = null;
            }
        }

        sCachedProject = findSupportProjectV7();
        return sCachedProject;
    }

    @Nullable
    private static IProject findSupportProjectV7() {
        for (IJavaProject javaProject : AdtUtils.getOpenAndroidProjects()) {
            IProject project = javaProject.getProject();
            ProjectState state = Sdk.getProjectState(project);
            if (state != null && state.isLibrary()) {
                ManifestInfo manifestInfo = ManifestInfo.get(project);
                if (manifestInfo.getPackage().equals("android.support.v7.gridlayout")) { //$NON-NLS-1$
                    return project;
                }
            }
        }

        return null;
    }
}