Home | History | Annotate | Download | only in api
      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
     79     public String getParentViewName(@NonNull String name) {
     80         name = getRawType(name);
     81 
     82         return PARENTS.get(name);
     83     }
     84 
     85     @Override
     86     @Nullable
     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
    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
    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 {
    154         PARENTS.put(COMPOUND_BUTTON, BUTTON);
    155         PARENTS.put(ABS_SPINNER, ADAPTER_VIEW);
    156         PARENTS.put(ABS_LIST_VIEW, ADAPTER_VIEW);
    157         PARENTS.put(ABS_SEEK_BAR, ADAPTER_VIEW);
    158         PARENTS.put(ADAPTER_VIEW, VIEW_GROUP);
    159         PARENTS.put(VIEW_GROUP, VIEW);
    160 
    161         PARENTS.put(TEXT_VIEW, VIEW);
    162         PARENTS.put(CHECKED_TEXT_VIEW, TEXT_VIEW);
    163         PARENTS.put(RADIO_BUTTON, COMPOUND_BUTTON);
    164         PARENTS.put(SPINNER, ABS_SPINNER);
    165         PARENTS.put(IMAGE_BUTTON, IMAGE_VIEW);
    166         PARENTS.put(IMAGE_VIEW, VIEW);
    167         PARENTS.put(EDIT_TEXT, TEXT_VIEW);
    168         PARENTS.put(PROGRESS_BAR, VIEW);
    169         PARENTS.put(TOGGLE_BUTTON, COMPOUND_BUTTON);
    170         PARENTS.put(VIEW_STUB, VIEW);
    171         PARENTS.put(BUTTON, TEXT_VIEW);
    172         PARENTS.put(SEEK_BAR, ABS_SEEK_BAR);
    173         PARENTS.put(CHECK_BOX, COMPOUND_BUTTON);
    174         PARENTS.put(SWITCH, COMPOUND_BUTTON);
    175         PARENTS.put(GALLERY, ABS_SPINNER);
    176         PARENTS.put(SURFACE_VIEW, VIEW);
    177         PARENTS.put(ABSOLUTE_LAYOUT, VIEW_GROUP);
    178         PARENTS.put(LINEAR_LAYOUT, VIEW_GROUP);
    179         PARENTS.put(RELATIVE_LAYOUT, VIEW_GROUP);
    180         PARENTS.put(LIST_VIEW, ABS_LIST_VIEW);
    181         PARENTS.put(VIEW_SWITCHER, VIEW_ANIMATOR);
    182         PARENTS.put(FRAME_LAYOUT, VIEW_GROUP);
    183         PARENTS.put(HORIZONTAL_SCROLL_VIEW, FRAME_LAYOUT);
    184         PARENTS.put(VIEW_ANIMATOR, FRAME_LAYOUT);
    185         PARENTS.put(TAB_HOST, FRAME_LAYOUT);
    186         PARENTS.put(TABLE_ROW, LINEAR_LAYOUT);
    187         PARENTS.put(RADIO_GROUP, LINEAR_LAYOUT);
    188         PARENTS.put(TAB_WIDGET, LINEAR_LAYOUT);
    189         PARENTS.put(EXPANDABLE_LIST_VIEW, LIST_VIEW);
    190         PARENTS.put(TABLE_LAYOUT, LINEAR_LAYOUT);
    191         PARENTS.put(SCROLL_VIEW, FRAME_LAYOUT);
    192         PARENTS.put(GRID_VIEW, ABS_LIST_VIEW);
    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 
    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