• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tools.lint.client.api;
18 
19 import static com.android.tools.lint.detector.api.LintConstants.ABSOLUTE_LAYOUT;
20 import static com.android.tools.lint.detector.api.LintConstants.ABS_LIST_VIEW;
21 import static com.android.tools.lint.detector.api.LintConstants.ABS_SEEK_BAR;
22 import static com.android.tools.lint.detector.api.LintConstants.ABS_SPINNER;
23 import static com.android.tools.lint.detector.api.LintConstants.ADAPTER_VIEW;
24 import static com.android.tools.lint.detector.api.LintConstants.BUTTON;
25 import static com.android.tools.lint.detector.api.LintConstants.CHECKED_TEXT_VIEW;
26 import static com.android.tools.lint.detector.api.LintConstants.CHECK_BOX;
27 import static com.android.tools.lint.detector.api.LintConstants.COMPOUND_BUTTON;
28 import static com.android.tools.lint.detector.api.LintConstants.EDIT_TEXT;
29 import static com.android.tools.lint.detector.api.LintConstants.EXPANDABLE_LIST_VIEW;
30 import static com.android.tools.lint.detector.api.LintConstants.FRAME_LAYOUT;
31 import static com.android.tools.lint.detector.api.LintConstants.GALLERY;
32 import static com.android.tools.lint.detector.api.LintConstants.GRID_VIEW;
33 import static com.android.tools.lint.detector.api.LintConstants.HORIZONTAL_SCROLL_VIEW;
34 import static com.android.tools.lint.detector.api.LintConstants.IMAGE_BUTTON;
35 import static com.android.tools.lint.detector.api.LintConstants.IMAGE_VIEW;
36 import static com.android.tools.lint.detector.api.LintConstants.LINEAR_LAYOUT;
37 import static com.android.tools.lint.detector.api.LintConstants.LIST_VIEW;
38 import static com.android.tools.lint.detector.api.LintConstants.PROGRESS_BAR;
39 import static com.android.tools.lint.detector.api.LintConstants.RADIO_BUTTON;
40 import static com.android.tools.lint.detector.api.LintConstants.RADIO_GROUP;
41 import static com.android.tools.lint.detector.api.LintConstants.RELATIVE_LAYOUT;
42 import static com.android.tools.lint.detector.api.LintConstants.SCROLL_VIEW;
43 import static com.android.tools.lint.detector.api.LintConstants.SEEK_BAR;
44 import static com.android.tools.lint.detector.api.LintConstants.SPINNER;
45 import static com.android.tools.lint.detector.api.LintConstants.SURFACE_VIEW;
46 import static com.android.tools.lint.detector.api.LintConstants.SWITCH;
47 import static com.android.tools.lint.detector.api.LintConstants.TABLE_LAYOUT;
48 import static com.android.tools.lint.detector.api.LintConstants.TABLE_ROW;
49 import static com.android.tools.lint.detector.api.LintConstants.TAB_HOST;
50 import static com.android.tools.lint.detector.api.LintConstants.TAB_WIDGET;
51 import static com.android.tools.lint.detector.api.LintConstants.TEXT_VIEW;
52 import static com.android.tools.lint.detector.api.LintConstants.TOGGLE_BUTTON;
53 import static com.android.tools.lint.detector.api.LintConstants.VIEW;
54 import static com.android.tools.lint.detector.api.LintConstants.VIEW_ANIMATOR;
55 import static com.android.tools.lint.detector.api.LintConstants.VIEW_GROUP;
56 import static com.android.tools.lint.detector.api.LintConstants.VIEW_PKG_PREFIX;
57 import static com.android.tools.lint.detector.api.LintConstants.VIEW_STUB;
58 import static com.android.tools.lint.detector.api.LintConstants.VIEW_SWITCHER;
59 import static com.android.tools.lint.detector.api.LintConstants.WEB_VIEW;
60 import static com.android.tools.lint.detector.api.LintConstants.WIDGET_PKG_PREFIX;
61 
62 import com.android.annotations.NonNull;
63 import com.android.annotations.Nullable;
64 import com.google.common.annotations.Beta;
65 
66 import java.util.HashMap;
67 import java.util.Map;
68 
69 /**
70  * Default simple implementation of an {@link SdkInfo}
71  * <p>
72  * <b>NOTE: This is not a public or final API; if you rely on this be prepared
73  * to adjust your code for the next tools release.</b>
74  */
75 @Beta
76 class DefaultSdkInfo extends SdkInfo {
77     @Override
78     @Nullable
getParentViewName(@onNull String name)79     public String getParentViewName(@NonNull String name) {
80         name = getRawType(name);
81 
82         return PARENTS.get(name);
83     }
84 
85     @Override
86     @Nullable
getParentViewClass(@onNull String fqcn)87     public String getParentViewClass(@NonNull String fqcn) {
88         int index = fqcn.lastIndexOf('.');
89         if (index != -1) {
90             fqcn = fqcn.substring(index + 1);
91         }
92 
93         String parent = PARENTS.get(fqcn);
94         if (parent == null) {
95             return null;
96         }
97         // The map only stores class names internally; correct for full package paths
98         if (parent.equals(VIEW) || parent.equals(VIEW_GROUP) || parent.equals(SURFACE_VIEW)) {
99             return VIEW_PKG_PREFIX + parent;
100         } else {
101             return WIDGET_PKG_PREFIX + parent;
102         }
103     }
104 
105     @Override
isSubViewOf(@onNull String parent, @NonNull String child)106     public boolean isSubViewOf(@NonNull String parent, @NonNull String child) {
107         parent = getRawType(parent);
108         child = getRawType(child);
109 
110         // Do analysis just on non-fqcn paths
111         if (parent.indexOf('.') != -1) {
112             parent = parent.substring(parent.lastIndexOf('.') + 1);
113         }
114         if (child.indexOf('.') != -1) {
115             child = child.substring(child.lastIndexOf('.') + 1);
116         }
117 
118         if (parent.equals(VIEW)) {
119             return true;
120         }
121 
122         while (!child.equals(VIEW)) {
123             if (parent.equals(child)) {
124                 return true;
125             }
126             child = PARENTS.get(child);
127             if (child == null) {
128                 // Unknown view - err on the side of caution
129                 return true;
130             }
131         }
132 
133         return false;
134     }
135 
136     // Strip off type parameters, e.g. AdapterView<?> => AdapterView
getRawType(String type)137     private static String getRawType(String type) {
138         if (type != null) {
139             int index = type.indexOf('<');
140             if (index != -1) {
141                 type = type.substring(0, index);
142             }
143         }
144 
145         return type;
146     }
147 
148     private static final int CLASS_COUNT = 59;
149 
150     @NonNull
151     private static final Map<String, String> PARENTS = new HashMap<String, String>(CLASS_COUNT);
152 
153     static {
PARENTS.put(COMPOUND_BUTTON, BUTTON)154         PARENTS.put(COMPOUND_BUTTON, BUTTON);
PARENTS.put(ABS_SPINNER, ADAPTER_VIEW)155         PARENTS.put(ABS_SPINNER, ADAPTER_VIEW);
PARENTS.put(ABS_LIST_VIEW, ADAPTER_VIEW)156         PARENTS.put(ABS_LIST_VIEW, ADAPTER_VIEW);
PARENTS.put(ABS_SEEK_BAR, ADAPTER_VIEW)157         PARENTS.put(ABS_SEEK_BAR, ADAPTER_VIEW);
PARENTS.put(ADAPTER_VIEW, VIEW_GROUP)158         PARENTS.put(ADAPTER_VIEW, VIEW_GROUP);
PARENTS.put(VIEW_GROUP, VIEW)159         PARENTS.put(VIEW_GROUP, VIEW);
160 
PARENTS.put(TEXT_VIEW, VIEW)161         PARENTS.put(TEXT_VIEW, VIEW);
PARENTS.put(CHECKED_TEXT_VIEW, TEXT_VIEW)162         PARENTS.put(CHECKED_TEXT_VIEW, TEXT_VIEW);
PARENTS.put(RADIO_BUTTON, COMPOUND_BUTTON)163         PARENTS.put(RADIO_BUTTON, COMPOUND_BUTTON);
PARENTS.put(SPINNER, ABS_SPINNER)164         PARENTS.put(SPINNER, ABS_SPINNER);
PARENTS.put(IMAGE_BUTTON, IMAGE_VIEW)165         PARENTS.put(IMAGE_BUTTON, IMAGE_VIEW);
PARENTS.put(IMAGE_VIEW, VIEW)166         PARENTS.put(IMAGE_VIEW, VIEW);
PARENTS.put(EDIT_TEXT, TEXT_VIEW)167         PARENTS.put(EDIT_TEXT, TEXT_VIEW);
PARENTS.put(PROGRESS_BAR, VIEW)168         PARENTS.put(PROGRESS_BAR, VIEW);
PARENTS.put(TOGGLE_BUTTON, COMPOUND_BUTTON)169         PARENTS.put(TOGGLE_BUTTON, COMPOUND_BUTTON);
PARENTS.put(VIEW_STUB, VIEW)170         PARENTS.put(VIEW_STUB, VIEW);
PARENTS.put(BUTTON, TEXT_VIEW)171         PARENTS.put(BUTTON, TEXT_VIEW);
PARENTS.put(SEEK_BAR, ABS_SEEK_BAR)172         PARENTS.put(SEEK_BAR, ABS_SEEK_BAR);
PARENTS.put(CHECK_BOX, COMPOUND_BUTTON)173         PARENTS.put(CHECK_BOX, COMPOUND_BUTTON);
PARENTS.put(SWITCH, COMPOUND_BUTTON)174         PARENTS.put(SWITCH, COMPOUND_BUTTON);
PARENTS.put(GALLERY, ABS_SPINNER)175         PARENTS.put(GALLERY, ABS_SPINNER);
PARENTS.put(SURFACE_VIEW, VIEW)176         PARENTS.put(SURFACE_VIEW, VIEW);
PARENTS.put(ABSOLUTE_LAYOUT, VIEW_GROUP)177         PARENTS.put(ABSOLUTE_LAYOUT, VIEW_GROUP);
PARENTS.put(LINEAR_LAYOUT, VIEW_GROUP)178         PARENTS.put(LINEAR_LAYOUT, VIEW_GROUP);
PARENTS.put(RELATIVE_LAYOUT, VIEW_GROUP)179         PARENTS.put(RELATIVE_LAYOUT, VIEW_GROUP);
PARENTS.put(LIST_VIEW, ABS_LIST_VIEW)180         PARENTS.put(LIST_VIEW, ABS_LIST_VIEW);
PARENTS.put(VIEW_SWITCHER, VIEW_ANIMATOR)181         PARENTS.put(VIEW_SWITCHER, VIEW_ANIMATOR);
PARENTS.put(FRAME_LAYOUT, VIEW_GROUP)182         PARENTS.put(FRAME_LAYOUT, VIEW_GROUP);
PARENTS.put(HORIZONTAL_SCROLL_VIEW, FRAME_LAYOUT)183         PARENTS.put(HORIZONTAL_SCROLL_VIEW, FRAME_LAYOUT);
PARENTS.put(VIEW_ANIMATOR, FRAME_LAYOUT)184         PARENTS.put(VIEW_ANIMATOR, FRAME_LAYOUT);
PARENTS.put(TAB_HOST, FRAME_LAYOUT)185         PARENTS.put(TAB_HOST, FRAME_LAYOUT);
PARENTS.put(TABLE_ROW, LINEAR_LAYOUT)186         PARENTS.put(TABLE_ROW, LINEAR_LAYOUT);
PARENTS.put(RADIO_GROUP, LINEAR_LAYOUT)187         PARENTS.put(RADIO_GROUP, LINEAR_LAYOUT);
PARENTS.put(TAB_WIDGET, LINEAR_LAYOUT)188         PARENTS.put(TAB_WIDGET, LINEAR_LAYOUT);
PARENTS.put(EXPANDABLE_LIST_VIEW, LIST_VIEW)189         PARENTS.put(EXPANDABLE_LIST_VIEW, LIST_VIEW);
PARENTS.put(TABLE_LAYOUT, LINEAR_LAYOUT)190         PARENTS.put(TABLE_LAYOUT, LINEAR_LAYOUT);
PARENTS.put(SCROLL_VIEW, FRAME_LAYOUT)191         PARENTS.put(SCROLL_VIEW, FRAME_LAYOUT);
PARENTS.put(GRID_VIEW, ABS_LIST_VIEW)192         PARENTS.put(GRID_VIEW, ABS_LIST_VIEW);
PARENTS.put(WEB_VIEW, ABSOLUTE_LAYOUT)193         PARENTS.put(WEB_VIEW, ABSOLUTE_LAYOUT);
194 
195         PARENTS.put("CheckedTextView", TEXT_VIEW);        //$NON-NLS-1$
196         PARENTS.put("MediaController", FRAME_LAYOUT);     //$NON-NLS-1$
197         PARENTS.put("SlidingDrawer", VIEW_GROUP);         //$NON-NLS-1$
198         PARENTS.put("DialerFilter", RELATIVE_LAYOUT);     //$NON-NLS-1$
199         PARENTS.put("DigitalClock", TEXT_VIEW);           //$NON-NLS-1$
200         PARENTS.put("Chronometer", TEXT_VIEW);            //$NON-NLS-1$
201         PARENTS.put("ImageSwitcher", VIEW_SWITCHER);      //$NON-NLS-1$
202         PARENTS.put("TextSwitcher", VIEW_SWITCHER);       //$NON-NLS-1$
203         PARENTS.put("AnalogClock", VIEW);                 //$NON-NLS-1$
204         PARENTS.put("TwoLineListItem", RELATIVE_LAYOUT);  //$NON-NLS-1$
205         PARENTS.put("ZoomControls", LINEAR_LAYOUT);       //$NON-NLS-1$
206         PARENTS.put("DatePicker", FRAME_LAYOUT);          //$NON-NLS-1$
207         PARENTS.put("TimePicker", FRAME_LAYOUT);          //$NON-NLS-1$
208         PARENTS.put("VideoView", SURFACE_VIEW);           //$NON-NLS-1$
209         PARENTS.put("ZoomButton", IMAGE_BUTTON);          //$NON-NLS-1$
210         PARENTS.put("AutoCompleteTextView", EDIT_TEXT);   //$NON-NLS-1$
211         PARENTS.put("RatingBar", ABS_SEEK_BAR);           //$NON-NLS-1$
212         PARENTS.put("ViewFlipper", VIEW_ANIMATOR);        //$NON-NLS-1$
213         PARENTS.put("NumberPicker", LINEAR_LAYOUT);       //$NON-NLS-1$
214         PARENTS.put("MultiAutoCompleteTextView",          //$NON-NLS-1$
215                 "AutoCompleteTextView");                  //$NON-NLS-1$
216 
PARENTS.size()217         assert PARENTS.size() <= CLASS_COUNT : PARENTS.size();
218 
219         /*
220         // Check that all widgets lead to the root view
221         if (LintUtils.assertionsEnabled()) {
222             for (String key : PARENTS.keySet()) {
223                 String parent = PARENTS.get(key);
224                 if (!parent.equals(VIEW)) {
225                     String grandParent = PARENTS.get(parent);
226                     assert grandParent != null : parent;
227                 }
228             }
229         }
230         */
231     }
232 }
233